3

Reading geth code and various posts here, I think I have now a good understanding of how the data is stored in Ethereum (please correct me if I am wrong at some point).

At the lowest level we have a key-value database

At the next level we have a generic datastructure called trie

And at the Ethereum Blockchain level we have something like (only relevant parts named):

block -> state trie -> account* -> storage trie

[Q1]: For state trie the paths represent the account addresses. What are the paths in the storage trie? Storage indices?

[Q2]: If we have a simple contract of the form:

contract C {
    uint256 public x = 100;
}

When we instantiate two instances of this contract. Will they have the same storage root hash? If yes, will they share exactly the same key/value pair in the database (at the lowest level), respectively the same trie node in the storage trie?

0

2 Answers 2

1

For state trie the paths represent the account addresses. What are the paths in the storage trie? Storage indices?

That's correct, except that the addresses and indexes are hashed before they are stored in the trie. This is done for DoS protection: Why are keys hashed in Merkle Patricia Trie?

When we instantiate two instances of this contract. Will they have the same storage root hash?

Yes.

will they share exactly the same key/value pair in the database (at the lowest level), respectively the same trie node in the storage trie?

Yes, because the trie root is the same for both contracts they share the key/values in the underlying database. It seems counter-intuitive or insecure at first, that 2 contracts "share the same storage", however, because the trie structure is immutable, whenever a new entry is added to the trie, a modified instace is created with it's own root. The old unmodified trie still exists in the underlying database and other contracts can still point to it.

You can try creating 2 contracts with the same storage, then reading their storage roots and content using this nodejs code https://ethereum.stackexchange.com/a/40280/18932

3
  • 2
    Thanks for the excellent answer! I was asking this, because I think it would be cool to be able to instantiate a new contract with the content of an old contract. If I understand everything correctly, at evm level this would be only the matter of setting the same storage root for the new contract, instead of starting with a blank storage. That would be pretty cool stuff from the perspective of the upgradeability of contracts. I know we can use delegatecall for the upgradeability, but the most direct way IMHO is to fast-copy the storage.
    – ivicaa
    Commented Mar 2, 2018 at 14:27
  • I think technically it's possible. The tricky part will be making sure that the new contract variables point to the same slots as old contract variables, e.g. if you had 2 fields in old contract then add 1 more in between those 2 in the new contract, the slot will shift for 3rd field. Maybe it can be solved in Solidity somehow by introducing annotations. Commented Mar 2, 2018 at 14:50
  • 1
    Yes, sure.. the same problem like with delegatecall.
    – ivicaa
    Commented Mar 2, 2018 at 14:52
0

Contracts actually have a storage root hash and a code root hash (which isn't so much a root hash as just a regular hash since code is one blob). If two contracts have the exact same code, and thus the exact same code hash, then the blob that equates to that hash should only be stored once in the db by the node, but I can't speak to whether or not they actually do that.

It's the same with the state root hash of a contract, but since that can change from block to block, it may be a little more complicated in the db. I assume it isn't duplicated since the db is largely a key-value store, but I can't be sure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.