From d927ccfa62c5ee46fe7262687c3730b2069fe8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 14 Mar 2019 13:25:51 +0200 Subject: [PATCH] core, trie: get rid of remainder of cache gen boilerplate --- core/state/database.go | 104 +++++++++++++++++------------------------ trie/secure_trie.go | 6 --- trie/sync_test.go | 10 ++-- trie/trie.go | 4 -- 4 files changed, 48 insertions(+), 76 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 1d77cc91d0..8798b73806 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -18,7 +18,6 @@ package state import ( "fmt" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" @@ -27,10 +26,6 @@ import ( ) const ( - // Number of past tries to keep. This value is chosen such that - // reasonable chain reorg depths will hit an existing trie. - maxPastTries = 12 - // Number of codehash->size associations to keep. codeSizeCacheSize = 100000 ) @@ -56,28 +51,61 @@ type Database interface { TrieDB() *trie.Database } -// Trie is a Ethereum Merkle Trie. +// Trie is a Ethereum Merkle Patricia trie. type Trie interface { + // GetKey returns the sha3 preimage of a hashed key that was previously used + // to store a value. + // + // TODO(fjl): remove this when SecureTrie is removed + GetKey([]byte) []byte + + // TryGet returns the value for key stored in the trie. The value bytes must + // not be modified by the caller. If a node was not found in the database, a + // trie.MissingNodeError is returned. TryGet(key []byte) ([]byte, error) + + // TryUpdate associates key with value in the trie. If value has length zero, any + // existing value is deleted from the trie. The value bytes must not be modified + // by the caller while they are stored in the trie. If a node was not found in the + // database, a trie.MissingNodeError is returned. TryUpdate(key, value []byte) error + + // TryDelete removes any existing value for key from the trie. If a node was not + // found in the database, a trie.MissingNodeError is returned. TryDelete(key []byte) error - Commit(onleaf trie.LeafCallback) (common.Hash, error) + + // Hash returns the root hash of the trie. It does not write to the database and + // can be used even if the trie doesn't have one. Hash() common.Hash + + // Commit writes all nodes to the trie's memory database, tracking the internal + // and external (for account tries) references. + Commit(onleaf trie.LeafCallback) (common.Hash, error) + + // NodeIterator returns an iterator that returns nodes of the trie. Iteration + // starts at the key after the given start key. NodeIterator(startKey []byte) trie.NodeIterator - GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed + + // Prove constructs a Merkle proof for key. The result contains all encoded nodes + // on the path to the value at key. The value itself is also included in the last + // node and can be retrieved by verifying the proof. + // + // If the trie does not contain a value for key, the returned proof contains all + // nodes of the longest existing prefix of the key (at least the root), ending + // with the node that proves the absence of the key. Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error } // NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use and retains a few recent expanded trie nodes in memory. To keep -// more historical state in memory, use the NewDatabaseWithCache constructor. +// concurrent use, but does not retain any recent trie nodes in memory. To keep some +// historical state in memory, use the NewDatabaseWithCache constructor. func NewDatabase(db ethdb.Database) Database { return NewDatabaseWithCache(db, 0) } -// NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use and retains both a few recent expanded trie nodes in memory, as -// well as a lot of collapsed RLP trie nodes in a large memory cache. +// NewDatabaseWithCache creates a backing store for state. The returned database +// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a +// large memory cache. func NewDatabaseWithCache(db ethdb.Database, cache int) Database { csc, _ := lru.New(codeSizeCacheSize) return &cachingDB{ @@ -88,38 +116,12 @@ func NewDatabaseWithCache(db ethdb.Database, cache int) Database { type cachingDB struct { db *trie.Database - mu sync.Mutex - pastTries []*trie.SecureTrie codeSizeCache *lru.Cache } -// OpenTrie opens the main account trie. +// OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - db.mu.Lock() - defer db.mu.Unlock() - - for i := len(db.pastTries) - 1; i >= 0; i-- { - if db.pastTries[i].Hash() == root { - return cachedTrie{db.pastTries[i].Copy(), db}, nil - } - } - tr, err := trie.NewSecure(root, db.db) - if err != nil { - return nil, err - } - return cachedTrie{tr, db}, nil -} - -func (db *cachingDB) pushTrie(t *trie.SecureTrie) { - db.mu.Lock() - defer db.mu.Unlock() - - if len(db.pastTries) >= maxPastTries { - copy(db.pastTries, db.pastTries[1:]) - db.pastTries[len(db.pastTries)-1] = t - } else { - db.pastTries = append(db.pastTries, t) - } + return trie.NewSecure(root, db.db) } // OpenStorageTrie opens the storage trie of an account. @@ -130,8 +132,6 @@ func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { // CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { - case cachedTrie: - return cachedTrie{t.SecureTrie.Copy(), db} case *trie.SecureTrie: return t.Copy() default: @@ -161,21 +161,3 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro func (db *cachingDB) TrieDB() *trie.Database { return db.db } - -// cachedTrie inserts its trie into a cachingDB on commit. -type cachedTrie struct { - *trie.SecureTrie - db *cachingDB -} - -func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) { - root, err := m.SecureTrie.Commit(onleaf) - if err == nil { - m.db.pushTrie(m.SecureTrie) - } - return root, err -} - -func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error { - return m.SecureTrie.Prove(key, fromLevel, proofDb) -} diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 1aaa04b335..fbc591ed10 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -160,12 +160,6 @@ func (t *SecureTrie) Hash() common.Hash { return t.trie.Hash() } -// Root returns the root hash of SecureTrie. -// Deprecated: use Hash instead. -func (t *SecureTrie) Root() []byte { - return t.trie.Root() -} - // Copy returns a copy of SecureTrie. func (t *SecureTrie) Copy() *SecureTrie { cpy := *t diff --git a/trie/sync_test.go b/trie/sync_test.go index d80070f3e8..0d8c29cfe7 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -133,7 +133,7 @@ func testIterativeSync(t *testing.T, batch int) { queue = append(queue[:0], sched.Missing(batch)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only @@ -167,7 +167,7 @@ func TestIterativeDelayedSync(t *testing.T) { queue = append(queue[len(results):], sched.Missing(10000)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that given a root hash, a trie can sync iteratively on a single thread, @@ -212,7 +212,7 @@ func testIterativeRandomSync(t *testing.T, batch int) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only @@ -259,7 +259,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that a trie sync will not request nodes multiple times, even if they @@ -299,7 +299,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) { queue = append(queue[:0], sched.Missing(0)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that at any point in time during a sync, only complete sub-tries are in diff --git a/trie/trie.go b/trie/trie.go index 53cce22b9a..920e331fd6 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -401,10 +401,6 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { return nil, &MissingNodeError{NodeHash: hash, Path: prefix} } -// Root returns the root hash of the trie. -// Deprecated: use Hash instead. -func (t *Trie) Root() []byte { return t.Hash().Bytes() } - // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash {