-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Create RPC method GetSlice(path hex, depth int, root hash, storage bool)
#9857
Comments
This is an example of the current output we have from our go-ethereum fork https://gist.github.com/hermanjunge/e430de12d7124208ad6052182ec6866f |
Adding @Tbaut as he is working on the light client effort as well. |
Also pinging @holgerd77. |
Hi @dryajov - we talked about this at devcon, did we?
How does this work if the state changes every 15 seconds?
How does this perform if a slice contains crypto-kitties? Did you implement something like this in Geth yet? If yes, could you link your work here? Also, did you consider writing an EIP for this? |
Hi @5chdn, Implementation in geth:ethereum/go-ethereum@master...MetaMask:wip/slicer Output examplehttps://gist.github.com/hermanjunge/e430de12d7124208ad6052182ec6866f How does this work if the state changes every 15 seconds?Example of a slice id:
which is How does this perform if a slice contains crypto-kitties?We apply the same logic for storage tries: We compute the slice where the keys of interest of that database reside, and then the client keeps track of that path. Afri, currently I am bashing my head against the keyboard to implement this in rust 😸 , now, we can always make a quick call to clarify anything. Let me know! |
@5chdn yes, I showed you a quick demo of how this works. This works for both state and storage tries and slices are just a few KBs, we can also control the slice size by adjusting it's depth. For the state trie, we have a deterministic address space of 65000 slices. This technique uses the smallest unique prefix approach to generate the slices, in our case we use 4 chars as our prefix. Same goes for contract storage, with the complication that contracts don't have this nice uniform address space and are in general sparse, our intuition is that this affects large contracts less than it does small ones. So for contracts, such as cryptokities, we can calculate what's the storage key that is being looked up on demand, and request the network to start tracking that (the on demand pubsub topics are documented here - musteka-la/kitsunet-docs#1). The downside of this is that it will be relatively slow on first request. One way of mitigating this is providing a way for contract authors to create maps for their contract storage, also, for standard contracts (ERC20, etc..) we can generate the maps ourselfs. Also, it's worth noting that, once a slice is tracked by the network, subsequent access to it should be significantly faster. |
Adding @vpulim as he is working on ethereumjs-client with an emphasis on light client functionality, also already some exchange on this with @dryajov on our Gitter channel. |
Thanks @holgerd77. I’ve been following this thread and once we implement state downloading in ethereumjs-client, we can support the GetSlice RPC method. |
Hi @hermanjunge, really dig this work and am currently working on exposing the I'm curious what the motivation for returning the nodes as |
What is this
This is an enhancement issue to focus efforts and gather feedback
Motivation
In Mustekala, we are working on a p2p network of light clients: Its key feature is that nodes consume and seed subsets of the state called slices.
Specifications
Slice definition
A slice consists on a merkle trie starting from an arbitrary head, which is a trie node found following the
path
from the given state orstorage
root
and delivering all its children up to a specifieddepth
.Example: The following slice
Is a slice from a state trie which root is
0xddc8b0
, which starts at the node found in the path [0
,a
,b
,3
], delivering all its children until a depth of 4.Why these "slices"? What are you talking about?
Enable browsers and low resource devices to consume and become seeders of light chunks of data. The average state slice size with 600 trie-nodes is 128 kB.
You can find all the information you need from an account (balance, nonce, evm code reference and storage root) inside a slice. The same applies to a smart contract and storage slices, as the value of a key will be mapped to the same slice id over blocks (same key, same path from the storage root).
Enables the emergence of clusters of nodes consuming and seeding particular slices, increasing the readiness for the
N+1
node. In other words, the more required is an area of the state (and hence the slices attached to that area), the more available it becomes.Likewise, as clients in the network will be seeders (can't stress that enough), the burden over full clients to serve data will dramatically decrease.
Generally speaking, for any given slice, there is a low rate of nodes that change over each block. This approach presents opportunities in the range of memory management for the seeders of said slices.
RPC Method
Input
GetSlice(path hex, depth int, root hash, storage bool)
path
: String representing the traversal in nibbles, from the givenroot
to the head of the slice.depth
: Maximum number of steps to walk down from the head.root
: The hash of the root of the state orstorage
trie from where we are taking the slice.storage
: Boolean. If set false, additional values from the state will be returned.As an anecdote fact, at of 2018.11.02, if we choose paths of 4 nibbles, and depth of 10, we can cover the whole state trie with 65,536 slices of 128 kB. The choose of path/depth for storage slices is a little bit more complicated, as it is related to the elections the smart contract developers took for the keys in their DB schema.
Output
slice-id
: string specifying<path>-<depth>-<root>
trie-nodes
:stem
: ["hash
:value
"]: Nodes from the root to the head. Enables the client to verify the slicehead
: ["hash
:value
"]: Head node of the sliceslice
: ["hash
:value
"]: Children from the head, up to the specifieddepth
metadata
:time-ms
:00-trie-loading
: In milliseconds01-fetch-stem-keys
: In milliseconds02-fetch-slice-keys
: In milliseconds03-fetch-leaves-info
: In millisecondsnodes-number
:00-stem-and-head-nodes
: count01-max-depth
: depth of the deepest children found02-total-trie-nodes
: count03-leaves
: count04-smart-contracs
: countAdditional output for state slices
While a smart contract account contains a field defined for the EVM code, this is but a content-addressed reference to its actual bytes. Then. each leaf in a slice must be parsed, the ones containing an EVM code field different from empty, must retrieve it using this reference from the database and return it inside the response.
Also, for convenience, we are returning the storage root of each smart contract, to avoid clients to traverse the slice for this value.
leaves
: A JSON object, which keys are the full path to the leaf, Each leave contains:storage-root
: Hashevm-code
: String representation in hexadecimalChallenges
Cache: Either an enhancement of the current caching system for trie nodes or a special cache for slices must be build to avoid calls to the database as much as possible. As mentioned above, while the contents of a slice vary little over blocks, a clever cache eviction process must be in place, for those trie-nodes no longer needed.
Deltas: We may want in the future to have a separate RPC method to return the differences (deltas) between two slices.
EIP: This method should be worked as part of the RPC Protocol.
Conclusion
We are confident that this approach will contribute to the goal of a truly decentralized blockchain as well as facilitating the participation of browsers and low resource devices as seeders of data, reducing the load of full clients.
In a fully deployed model, during each computed block, full nodes would be serving a number of slices to kitsunet clients, to be relayed over the network, creating effective scalability over the reading operations of the ethereum database, providing data availability at face value.
The text was updated successfully, but these errors were encountered: