Skip to content

eth: add debug_storageRangeAt#14350

Merged
karalabe merged 5 commits into
ethereum:masterfrom
fjl:trie-iterator-skip-2
Apr 25, 2017
Merged

eth: add debug_storageRangeAt#14350
karalabe merged 5 commits into
ethereum:masterfrom
fjl:trie-iterator-skip-2

Conversation

@fjl
Copy link
Copy Markdown
Contributor

@fjl fjl commented Apr 19, 2017

The new RPC method allows downloading storage in chunks.

debug_storageRangeAt takes parameters blockHash, txIndex, account, startKey, limit. The startKey applies to the hashed key (instead of the preimage as originally suggested in #3407) . The returned storage values contain the preimage if available. The returned object also contains the nextKey field, which will be non-null if there are more keys after the range that was returned.

Example:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_storageRangeAt",
  "params": [
    "0xced82545131cdb6253f183a62dc3eaf81259be5cc744767798bcfb95664dc32c", // blockHash
    4,                                                                    // txIndex
    "0xB4A5BB81C6962Fa87Af6886ABE59b3cc56ec44b8",                         // account
    "0x",                                                                 // startKey
    2                                                                     // limit
  ]
}
// Response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "storage": {
      "0x1ab0c6948a275349ae45a06aad66a8bd65ac18074615d53676c09b67809099e0": {
        "key": "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace",
        "value": "0x00000000000000000000009413739a6ef2d14b5433465dbeffafbc2f2d610551"
      },
      "0x1d3954ea05fac9c4f44f290d32ed11be13922e2c8162b3594bb3bb0405546e8e": {
        "key": "0x2a359015afbfbe3b36db751c88f03aed63209927e8cf9ca7f0b69158e29e28f5",
        "value": "0x0000000000000000000000000000000000000000000000000000000000000004"
      }
    },
    "nextKey": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"
  }
}

// Continuing the download using nextKey as startKey:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_storageRangeAt",
  "params": [
    "0xced82545131cdb6253f183a62dc3eaf81259be5cc744767798bcfb95664dc32c",
    4,
    "0xB4A5BB81C6962Fa87Af6886ABE59b3cc56ec44b8",
    "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563",
    100
  ]
}
// The response has nextKey == null because there aren't any more values:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "storage": {
      "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": {
        "key": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "value": "0x0000000000000000000000945e237bf1540eea146f5e830593d1d54c279616a9"
      },
      ... // 16 more entries elided
    },
    "nextKey": null
  }
}

We agreed on a preliminary spec in #3407. This supersedes that PR.
The earlier commits leading up to the new API add support for seeking in the trie iterator.

The key was constructed from nibbles, which isn't possible for all
nodes. Remove the only use of Key in LightTrie by always retrying with
the original key that was looked up.
@fjl fjl requested a review from Arachnid April 19, 2017 10:13
@fjl fjl force-pushed the trie-iterator-skip-2 branch 2 times, most recently from 5fb8474 to e1678ce Compare April 19, 2017 13:23
Comment thread trie/encoding.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you define typedefs for hex and compact encoding?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, because both types of key can be stored in shortNode.Key.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could always use casts there. Typedefs would be helpful to avoid confusion elsewhere - though the function naming accomplishes some of that at least.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't want to change it in this PR. We can do it in another PR.

Comment thread trie/iterator.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

preorder. :)

Comment thread trie/iterator.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What was the motivation behind making this internal?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The motivation was to have a single constructor for each iterator. Please see the commit message.

Comment thread trie/iterator.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why isn't this part of the loop initializer any longer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Accident

Comment thread trie/iterator_test.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you add tests for seeking to the empty string, and for seeking to a key past the end?

Copy link
Copy Markdown
Contributor Author

@fjl fjl Apr 19, 2017

Choose a reason for hiding this comment

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

No need to test empty string, all other tests use NodeIterator(nil) ;). I've added one that seeks past the end.

@fjl fjl force-pushed the trie-iterator-skip-2 branch from 69e1404 to 2f13ce1 Compare April 19, 2017 22:02
Comment thread eth/api_test.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume these are the hashes of the keys in the array below? Could you add a note to that effect for anyone coming across this later?

@fjl fjl force-pushed the trie-iterator-skip-2 branch from 43de846 to b22dfc8 Compare April 20, 2017 10:23
@karalabe karalabe added this to the 1.6.1 milestone Apr 20, 2017
Copy link
Copy Markdown
Member

@karalabe karalabe left a comment

Choose a reason for hiding this comment

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

Minor issues mostly. Please check and consider whether to fix or not.

One potentially bigger issue I saw was in the state object deep copy. Please check hat part out in detail and explain why it works if it works.

Comment thread trie/iterator.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

❤️ I hate these labels so much :P

Comment thread trie/iterator.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why return the previous "item" if peeking at the next one fails?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It has to return something. The idea was that the iterator wouldn't advance if there was an error fetching the next item.

Comment thread trie/encoding.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

onE byte

Comment thread trie/encoding.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah sweet, I've never seen this part of the code in 2 years :))

Comment thread trie/encoding_test.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you add a test for encoding/decoding empty keys? The previous code had explicit checks whereas the new code does this implicitly by relying on the calculation returning an empty slice. There's even a slight API change, where the old code returned nil in hexToKeybytes whereas the new returns []byte{}. I'd be happy to see an explicit test that verifies this weird case too.

Comment thread trie/encoding_test.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you add a test for encoding/decoding empty keys?

Comment thread core/state/state_object.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't stateObject.trie a trie.SecureTrie? Because that one is a much fancier construct that won't "deep copy" so easily https://github.com/ethereum/go-ethereum/blob/master/trie/secure_trie.go#L44

Copy link
Copy Markdown
Contributor Author

@fjl fjl Apr 24, 2017

Choose a reason for hiding this comment

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

Shallow copy support for SecureTrie was added in 710435b51, by yours truly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't trust that guy.... he looks shady af ;)

Comment thread core/state/statedb.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doesn't look like an iterator to me :P

Comment thread eth/api.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can this ever happen? If the tx is already in our chain, I think it's safe to say this won't ever fail. (Mentioning because you deleted a similar check at tx.AsMessage).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The around AsMessage is for deriving the sender. I don't want to remove this one because many more things can go wrong (including DB errors, etc.).

fjl added 4 commits April 25, 2017 02:14
'encode' and 'decode' are meaningless because the code deals with three
encodings. Document the encodings and give a name to each one.
Make it so each iterator has exactly one public constructor:

- NodeIterators can be created through a method.
- Iterators can be created through NewIterator on any NodeIterator.
The 'step' method is split into two parts, 'peek' and 'push'. peek
returns the next state but doesn't make it current.

The end of iteration was previously tracked by setting 'trie' to nil.
End of iteration is now tracked using the 'iteratorEnd' error, which is
slightly cleaner and requires less code.
@fjl fjl force-pushed the trie-iterator-skip-2 branch from b22dfc8 to 207bd7d Compare April 25, 2017 00:14
Copy link
Copy Markdown
Member

@karalabe karalabe left a comment

Choose a reason for hiding this comment

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

LGTM

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