diff --git a/core/state/database.go b/core/state/database.go index d3c36c10a..a67c414d9 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -68,10 +68,10 @@ type Trie interface { // TODO(fjl): remove this when StateTrie 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) + // TryGetStorage 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. + TryGetStorage(addr common.Address, key []byte) ([]byte, error) // TryGetAccount abstracts an account read from the trie. It retrieves the // account blob from the trie with provided account address and decodes it @@ -81,20 +81,20 @@ type Trie interface { // be returned. TryGetAccount(address common.Address) (*types.StateAccount, 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 + // TryUpdateStorage 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 + TryUpdateStorage(addr common.Address, key, value []byte) error // TryUpdateAccount abstracts an account write to the trie. It encodes the // provided account object with associated algorithm and then updates it // in the trie with provided address. TryUpdateAccount(address common.Address, account *types.StateAccount) 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 + // TryDeleteStorage removes any existing value for key from the trie. If a node + // was not found in the database, a trie.MissingNodeError is returned. + TryDeleteStorage(addr common.Address, key []byte) error // TryDeleteAccount abstracts an account deletion from the trie. TryDeleteAccount(address common.Address) error diff --git a/core/state/state_object.go b/core/state/state_object.go index 7e34cba44..936f6dae2 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.TryGet(key.Bytes()) + enc, err = tr.TryGetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -253,7 +253,7 @@ func (s *stateObject) finalise(prefetch bool) { } } if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) + s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { - if err := tr.TryDelete(key[:]); err != nil { + if err := tr.TryDeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) return nil, err } @@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.TryUpdate(key[:], v); err != nil { + if err := tr.TryUpdateStorage(s.address, key[:], v); err != nil { s.db.setError(err) return nil, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 54d504045..38583f51d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -871,7 +871,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(common.Hash{}, s.originalRoot, addressesToPrefetch) + s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch) } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index f142c86bb..edd370fbd 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -141,7 +141,7 @@ func (p *triePrefetcher) copy() *triePrefetcher { } // prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]byte) { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) { // If the prefetcher is an inactive one, bail out if p.fetches != nil { return @@ -150,7 +150,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][] id := p.trieID(owner, root) fetcher := p.fetchers[id] if fetcher == nil { - fetcher = newSubfetcher(p.db, p.root, owner, root) + fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } fetcher.schedule(keys) @@ -205,11 +205,12 @@ func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { // main prefetcher is paused and either all requested items are processed or if // the trie being worked on is retrieved from the prefetcher. type subfetcher struct { - db Database // Database to load trie nodes through - state common.Hash // Root hash of the state to prefetch - owner common.Hash // Owner of the trie, usually account hash - root common.Hash // Root hash of the trie to prefetch - trie Trie // Trie being populated with nodes + db Database // Database to load trie nodes through + state common.Hash // Root hash of the state to prefetch + owner common.Hash // Owner of the trie, usually account hash + root common.Hash // Root hash of the trie to prefetch + addr common.Address // Address of the account that the trie belongs to + trie Trie // Trie being populated with nodes tasks [][]byte // Items queued up for retrieval lock sync.Mutex // Lock protecting the task queue @@ -226,12 +227,13 @@ type subfetcher struct { // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. -func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash) *subfetcher { +func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { sf := &subfetcher{ db: db, state: state, owner: owner, root: root, + addr: addr, wake: make(chan struct{}, 1), stop: make(chan struct{}), term: make(chan struct{}), @@ -336,7 +338,11 @@ func (sf *subfetcher) loop() { if _, ok := sf.seen[string(task)]; ok { sf.dups++ } else { - sf.trie.TryGet(task) + if len(task) == common.AddressLength { + sf.trie.TryGetAccount(common.BytesToAddress(task)) + } else { + sf.trie.TryGetStorage(sf.addr, task) + } sf.seen[string(task)] = struct{}{} } } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index cb0b67d7e..501bb7084 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,19 +47,19 @@ func TestCopyAndClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) time.Sleep(1 * time.Second) a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) b := prefetcher.trie(common.Hash{}, db.originalRoot) cpy := prefetcher.copy() - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) c := cpy.trie(common.Hash{}, db.originalRoot) prefetcher.close() cpy2 := cpy.copy() - cpy2.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) d := cpy2.trie(common.Hash{}, db.originalRoot) cpy.close() cpy2.close() @@ -72,7 +72,7 @@ func TestUseAfterClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) a := prefetcher.trie(common.Hash{}, db.originalRoot) prefetcher.close() b := prefetcher.trie(common.Hash{}, db.originalRoot) @@ -88,7 +88,7 @@ func TestCopyClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) cpy := prefetcher.copy() a := prefetcher.trie(common.Hash{}, db.originalRoot) b := cpy.trie(common.Hash{}, db.originalRoot) diff --git a/light/trie.go b/light/trie.go index 0ccab1588..0f05a8000 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGet(key []byte) ([]byte, error) { +func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -142,14 +142,14 @@ func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccou }) } -func (t *odrTrie) TryUpdate(key, value []byte) error { +func (t *odrTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDelete(key []byte) error { +func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryDelete(key) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 83b92cebd..01e004d02 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,7 +75,7 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGet(key) + res, err := t.TryGetStorage(common.Address{}, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } @@ -86,7 +86,7 @@ func (t *StateTrie) Get(key []byte) []byte { // The value bytes must not be modified by the caller. // If the specified node is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGet(key []byte) ([]byte, error) { +func (t *StateTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } @@ -131,7 +131,7 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { + if err := t.TryUpdateStorage(common.Address{}, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdate(key, value []byte) error { +func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -171,7 +171,7 @@ func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAcc // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { + if err := t.TryDeleteStorage(common.Address{}, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } @@ -179,7 +179,7 @@ func (t *StateTrie) Delete(key []byte) { // TryDelete removes any existing value for key from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDelete(key []byte) error { +func (t *StateTrie) TryDeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk)