Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trie: more node iterator improvements #14615

Merged
merged 6 commits into from
Jun 20, 2017
Merged

Conversation

fjl
Copy link
Contributor

@fjl fjl commented Jun 13, 2017

Split out of #14589 to get review earlier.

The changes:

  • NodeIterator interface gains LeafKey method which returns the key of the current (leaf) node.
  • nodeIterator now handles missing nodes gracefully. Callers can recover from MissingNodeError
    by inserting the node into the database before calling Next again.
  • nodeIterator no longer returns hash nodes and always adds the terminator symbol to Path.
    This makes Path unique.
  • MissingNodeError contains hex-encoded Path of the missing node. This is useful for the light client.

Set deadlocks immediately and isn't part of the Database interface.
@fjl fjl requested a review from Arachnid June 13, 2017 11:20
@fjl fjl force-pushed the trie-iterator-errtrack branch 2 times, most recently from e06b8f5 to 262d96e Compare June 14, 2017 11:47
fjl added 2 commits June 14, 2017 14:04
This is useful for testing because the underlying NodeIterator doesn't
need to be kept in a separate variable just to get the error.
@fjl fjl force-pushed the trie-iterator-errtrack branch 3 times, most recently from 699ed58 to e8f756d Compare June 14, 2017 12:23
trie/encoding.go Outdated
func hexToKeybytes(hex []byte) []byte {
if hasTerm(hex) {
hex = hex[:len(hex)-1]
}
if len(hex)&1 != 0 {
panic("can't convert hex key of odd length")
// Odd length. This can happen if someone iterates a Trie
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's explained in the commit message:

This also removes the the panic for odd length because it is too subtle
to be useful. In a follow-up commit, using LeafKey in a core/state test
revealed that it iterates tries rooted in an intermediate node. This can
produce odd-length leaf keys and it's hard to debug. Removing the panic
removes risk of a rare production crash later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't a 'rare production crash' the correct behaviour if we're iterating partial tries?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. Not sure. Consider that the only use of hexToKeybytes is in LeafKey. With this change, LeafKey will return nil for leaves when iterating a subtrie rooted at odd level. Should it panic instead?

The odd-length panic is very new (added in f958d7d) and compared to one month ago, I no longer feel that it's strictly necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand what the compelling reason to return nil here is, though. Is there any situation in which this would be expected?

return it
}

// Hash returns the hash of the current node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why delete these comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're not visible in GoDoc and other implementations of NodeIterator don't have comments either.

trie/iterator.go Outdated
state, parentIndex, path, err := it.peek(descend)
if err != nil {
it.err = err
if it.err = err; it.err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense to have the first statement here part of the if clause.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I guess this is a style question that we can 🚲 🏠 over.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's bikeshedding. Would you agree this is bad style?

if it.err = err; err != nil {

they're functionally equivalent, but the latter demonstrates more clearly that the first part of the if statement is only being used for its side-effect.

Copy link
Contributor Author

@fjl fjl Jun 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optional first part of a condition is always used for side effect because it is a statement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it's generally used to generate something; not just an assignment.

@fjl fjl changed the title trie: misc iterator improvements trie: more node iterator improvements Jun 15, 2017
fjl added 3 commits June 16, 2017 10:11
LeafKey is useful for callers that can't interpret Path.
Instead of failing iteration irrecoverably, make it so Next retries the
pending seek or peek every time.

Smaller changes in this commit make this easier to test:

* The iterator previously returned from Next on encountering a hash
  node. This caused it to visit the same path twice.
* Path returned nibbles with terminator symbol for valueNode attached
  to fullNode, but removed it for valueNode attached to shortNode. Now
  the terminator is always present. This makes Path unique to each node
  and simplifies Leaf.
The light client trie iterator needs to know the path of the node that's
missing so it can retrieve a proof for it. NodeIterator.Path is not
sufficient because it is updated when the node is resolved and actually
visited by the iterator.

Also remove unused fields. They were added a long time ago before we
knew which fields would be needed for the light client.
@fjl fjl force-pushed the trie-iterator-errtrack branch from fd46e3b to 3a2fcee Compare June 16, 2017 08:13
@fjl
Copy link
Contributor Author

fjl commented Jun 16, 2017

squashed

@fjl fjl merged commit 693d9cc into ethereum:master Jun 20, 2017
@karalabe karalabe added this to the 1.6.6 milestone Jun 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants