-
Notifications
You must be signed in to change notification settings - Fork 20.4k
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
core/state: access trie through Database interface, track errors #14589
Conversation
trie/iterator.go
Outdated
// Callers must not retain references to the return value after calling Next | ||
Path() []byte | ||
|
||
// Leaf returns true iff the current node is a leaf node. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: "iff"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see https://en.wiktionary.org/wiki/iff. I think it's not needed here, but the word was already there and I didn't want to change the original comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh... got it, thanks
core/blockchain.go
Outdated
@@ -531,7 +526,7 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash) bool { | |||
return false | |||
} | |||
// Ensure the associated state is also present | |||
_, err := state.New(block.Root(), bc.chainDb) | |||
_, err := state.New(block.Root(), bc.stateCache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The state.New
does a lot of allocation and things (https://github.com/ethereum/go-ethereum/blob/master/core/state/statedb.go#L89) . Seems a bit wasteful to instantiate one and just throw it away. Couldn't we just verify the state without actually allocating the entire instance in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we could use stateCache.OpenTrie to check.
} | ||
state, err := state.New(parent.Root(), bc.stateCache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For inserting N blocks, you'll be instantiating a new state
N times. Is that really needed? In most situations (after the first block), the state
will already be where you want it to be - no action needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old version used Reset on stateCache, which was a StateDB. In the new code, stateCache is state.Database and state.New is about as expensive as Reset was.
ee25500
to
8a31557
Compare
Note: the first few commits are part of #14615 and can be removed when that's merged. |
8e76ab5
to
1d90246
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in general, see inline comments.
return &odrDatabase{ctx, StateTrieID(head), odr} | ||
} | ||
|
||
type odrDatabase struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are implementing the entire odr database backend for the state here (not just the trie), maybe we should rename this file to something like odr_database.go.
func (m cachedTrie) CommitTo(dbw trie.DatabaseWriter) (common.Hash, error) { | ||
root, err := m.SecureTrie.CommitTo(dbw) | ||
if err == nil { | ||
m.db.pushTrie(m.SecureTrie) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm mistaken but it seems like now we are caching storage tries too, which makes the entire pastTries cache useless since there are usually a lot of storage tries processed per block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenStorageTrie doesn't return cachedTrie, it returns *trie.SecureTrie.
if codeHash == sha3_nil { | ||
return nil, nil | ||
} | ||
if code, err := db.backend.Database().Get(codeHash[:]); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since StateDB is using a cachingDB which also checks the database, isn't this check redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StateDB doesn't use cachingDB is the Database returned by state.NewDatabase. It's not used here.
return len(code), err | ||
} | ||
|
||
type odrTrie struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something I should have done already but please either add a comment stating that odrTrie is a SecureTrie (key caching is included) or rename it to odrSecureTrie. Maybe the comment is enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will move hashing to StateDB in a follow-up PR.
core/state/database.go
Outdated
@@ -0,0 +1,152 @@ | |||
// Copyright 2014 The go-ethereum Authors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/2014/21017/
core/state/database.go
Outdated
CommitTo(trie.DatabaseWriter) (common.Hash, error) | ||
Hash() common.Hash | ||
NodeIterator(startKey []byte) trie.NodeIterator | ||
GetKey([]byte) []byte // TODO(fjl): remove this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When SecureTrie is removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a note to that effect? Otherwise there's no way to know when this todo is relevant for.
const ( | ||
// Number of past tries to keep. This value is chosen such that | ||
// reasonable chain reorg depths will hit an existing trie. | ||
maxPastTries = 12 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, pastries.
core/state/database.go
Outdated
type Database interface { | ||
// Accessing tries | ||
OpenTrie(root common.Hash) (Trie, error) | ||
OpenStorageTrie(addrHash, root common.Hash) (Trie, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we just use OpenTrie
here? And what is addrHash
used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO it's useful to distinguish between storage tries and the main accounts trie. For example, the cachingDB caches the accounts trie on commit, but doesn't cache storage at all. addrHash is used by the light client, you can see how in les/trie.go.
Also improve error reporting in ODR tests because it was impossible to see what's wrong when the only output is "odr mismatch".
func (t *odrTrie) TryUpdate(key, value []byte) error { | ||
key = crypto.Keccak256(key) | ||
return t.do(key, func() error { | ||
return t.trie.TryDelete(key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have written my question in here. I'm not sure whether anybody would be notified to see it. So I comment again in this PR. @fjl
Hi there, I'm confused here a little bit. Why
TryUpdate
does not callt.trie.TryUpdate(key, value)
and callst.trie.TryDelete
instead? This is not apparent from my point of view. The update operation simply deletes the corresponding entry, though it could retrieve later by odr. However, it adds further network overhead.
Motivation for this change:
work with the light client.
It opens the door to more code deletions later:
Get
,Update
, ... in a later PR because they'reno longer used by core/state.
SecureTrie
because core/state is now aware of key hashing.ForEachStorage
because we now have aStorageTrie
method.