diff --git a/core/state/database.go b/core/state/database.go index fd30aca32f..82bb877f22 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -102,7 +102,7 @@ type Trie interface { // UpdateAccountAsync will abstract the write of an account to the secure trie. // The actual value of the account is not resolved from the passed function until // it is needed when hashing the trie. - UpdateAccountAsync(address common.Address, accountResolver func() *types.StateAccount) error + UpdateAccountAsync(address common.Address, accountResolver func() (*types.StateAccount, int)) error // UpdateStorage 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 diff --git a/core/state/statedb.go b/core/state/statedb.go index abf0a02a87..1bc6265528 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -579,7 +579,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) { // updateStateObject writes the given object to the trie. The actual value is // only resolved from the provided function when it is needed during trie hashing. -func (s *StateDB) updateStateObjectAsync(addr common.Address, resolver func() *types.StateAccount) { +func (s *StateDB) updateStateObjectAsync(addr common.Address, resolver func() (*types.StateAccount, int)) { if err := s.trie.UpdateAccountAsync(addr, resolver); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr, err)) } @@ -838,13 +838,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { workers.SetLimit(1) } - stateObjectsResolve := make(map[common.Address]func() *types.StateAccount) + type stateAccountWithCodeLen struct { + *types.StateAccount + codeLen int + } + stateObjectsResolve := make(map[common.Address]func() (*types.StateAccount, int)) for addr, op := range s.mutations { if op.applied || op.isDelete() { continue } obj := s.stateObjects[addr] // closure for the task runner below - complete := make(chan *types.StateAccount) + complete := make(chan stateAccountWithCodeLen) workers.Go(func() error { if s.db.TrieDB().IsVerkle() { obj.updateTrie() @@ -857,12 +861,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.witness.AddState(obj.trie.Witness()) } } - complete <- &obj.data + complete <- stateAccountWithCodeLen{&obj.data, 0} return nil }) - stateObjectsResolve[addr] = func() *types.StateAccount { - return <-complete + stateObjectsResolve[addr] = func() (*types.StateAccount, int) { + res := <-complete + return res.StateAccount, res.codeLen } } // If witness building is enabled, gather all the read-only accesses. @@ -914,6 +919,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } } } + s.StorageUpdates += time.Since(start) // Now we're about to start to write changes to the trie. The trie is so far @@ -954,11 +960,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if op.isDelete() { deletedAddrs = append(deletedAddrs, addr) } else { - if s.db.TrieDB().IsVerkle() { - s.updateStateObject(s.stateObjects[addr]) - } else { - s.updateStateObjectAsync(addr, stateObjectsResolve[addr]) - } + s.updateStateObjectAsync(addr, stateObjectsResolve[addr]) s.AccountUpdated += 1 } usedAddrs = append(usedAddrs, addr) // Copy needed for closure diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 4c8a181acf..461b163a1c 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -229,10 +229,10 @@ func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccoun // UpdateAccountAsync will abstract the write of an account to the secure trie. // The actual value of the account is not resolved from the passed function until // it is needed when hashing the trie. -func (t *StateTrie) UpdateAccountAsync(address common.Address, accountResolve func() *types.StateAccount) error { +func (t *StateTrie) UpdateAccountAsync(address common.Address, accountResolve func() (*types.StateAccount, int)) error { hk := crypto.Keccak256(address.Bytes()) resolve := func() []byte { - acc := accountResolve() + acc, _ := accountResolve() data, err := rlp.EncodeToBytes(acc) if err != nil { panic(err) // TODO: what do do here? diff --git a/trie/transition.go b/trie/transition.go index 573125b833..b53682add5 100644 --- a/trie/transition.go +++ b/trie/transition.go @@ -17,7 +17,6 @@ package trie import ( - "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -139,8 +138,9 @@ func (t *TransitionTrie) UpdateAccount(addr common.Address, account *types.State // only needs to know what the account trie does now. return t.overlay.UpdateAccount(addr, account, codeLen) } -func (t *TransitionTrie) UpdateAccountAsync(address common.Address, accountResolver func() *types.StateAccount) error { - return errors.New("not implemented") +func (t *TransitionTrie) UpdateAccountAsync(address common.Address, accountResolver func() (*types.StateAccount, int)) error { + acct, codeLen := accountResolver() + return t.overlay.UpdateAccount(address, acct, codeLen) } // DeleteStorage removes any existing value for key from the trie. If a node was not diff --git a/trie/verkle.go b/trie/verkle.go index f36f436b4a..caf206f298 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -177,8 +177,9 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, return nil } -func (t *VerkleTrie) UpdateAccountAsync(address common.Address, accountResolver func() *types.StateAccount) error { - return errors.New("not implemented") +func (t *VerkleTrie) UpdateAccountAsync(address common.Address, accountResolver func() (*types.StateAccount, int)) error { + acct, codeSize := accountResolver() + return t.UpdateAccount(address, acct, codeSize) } // UpdateStorage implements state.Trie, writing the provided storage slot into