mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
integrate trie batch update into statedb intermediate root calculation
This commit is contained in:
parent
cd191ed55a
commit
0dcd0e26f7
5 changed files with 70 additions and 10 deletions
|
|
@ -160,6 +160,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
||||||
} else if res.Requests != nil {
|
} else if res.Requests != nil {
|
||||||
return errors.New("block has requests before prague fork")
|
return errors.New("block has requests before prague fork")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the state root against the received state root and throw
|
// Validate the state root against the received state root and throw
|
||||||
// an error if they don't match.
|
// an error if they don't match.
|
||||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
|
|
|
||||||
|
|
@ -322,8 +322,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
// into a shortnode. This requires `B` to be resolved from disk.
|
// into a shortnode. This requires `B` to be resolved from disk.
|
||||||
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
||||||
var (
|
var (
|
||||||
deletions []common.Hash
|
deletions []common.Hash
|
||||||
used = make([]common.Hash, 0, len(s.uncommittedStorage))
|
used = make([]common.Hash, 0, len(s.uncommittedStorage))
|
||||||
|
updateKeys [][]byte
|
||||||
|
updateValues [][]byte
|
||||||
)
|
)
|
||||||
for key, origin := range s.uncommittedStorage {
|
for key, origin := range s.uncommittedStorage {
|
||||||
// Skip noop changes, persist actual changes
|
// Skip noop changes, persist actual changes
|
||||||
|
|
@ -337,10 +339,8 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (value != common.Hash{}) {
|
if (value != common.Hash{}) {
|
||||||
if err := tr.UpdateStorage(s.address, key[:], common.TrimLeftZeroes(value[:])); err != nil {
|
updateKeys = append(updateKeys, key[:])
|
||||||
s.db.setError(err)
|
updateValues = append(updateValues, common.TrimLeftZeroes(value[:]))
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.db.StorageUpdated.Add(1)
|
s.db.StorageUpdated.Add(1)
|
||||||
} else {
|
} else {
|
||||||
deletions = append(deletions, key)
|
deletions = append(deletions, key)
|
||||||
|
|
@ -348,6 +348,12 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
// Cache the items for preloading
|
// Cache the items for preloading
|
||||||
used = append(used, key) // Copy needed for closure
|
used = append(used, key) // Copy needed for closure
|
||||||
}
|
}
|
||||||
|
if len(updateKeys) > 0 {
|
||||||
|
if err := tr.UpdateStorageBatch(common.Address{}, updateKeys, updateValues); err != nil {
|
||||||
|
s.db.setError(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, key := range deletions {
|
for _, key := range deletions {
|
||||||
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
|
|
|
||||||
|
|
@ -574,6 +574,25 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
|
||||||
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (s *StateDB) updateStateObjects(objs []*stateObject) {
|
||||||
|
var addrs []common.Address
|
||||||
|
var accts []*types.StateAccount
|
||||||
|
|
||||||
|
for _, obj := range objs {
|
||||||
|
addrs = append(addrs, obj.Address())
|
||||||
|
accts = append(accts, &obj.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.trie.UpdateAccountBatch(addrs, accts, nil); err != nil {
|
||||||
|
s.setError(fmt.Errorf("updateStateObjects error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, obj := range objs {
|
||||||
|
if obj.dirtyCode {
|
||||||
|
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// deleteStateObject removes the given object from the state trie.
|
// deleteStateObject removes the given object from the state trie.
|
||||||
func (s *StateDB) deleteStateObject(addr common.Address) {
|
func (s *StateDB) deleteStateObject(addr common.Address) {
|
||||||
|
|
@ -883,6 +902,31 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
workers.Wait()
|
workers.Wait()
|
||||||
s.StorageUpdates += time.Since(start)
|
s.StorageUpdates += time.Since(start)
|
||||||
|
|
||||||
|
/*
|
||||||
|
fmt.Println("begin print mutations")
|
||||||
|
fmt.Println(s.txIndex)
|
||||||
|
for addr, _ := range s.mutations {
|
||||||
|
if _, ok := s.stateObjects[addr]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.stateObjects[addr].trie == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("mut %x/%x:\n", addr, s.stateObjects[addr].addrHash)
|
||||||
|
it, err := s.stateObjects[addr].trie.NodeIterator([]byte{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for it.Next(true) {
|
||||||
|
if it.Leaf() {
|
||||||
|
fmt.Printf("%x: %x\n", it.Path(), it.LeafBlob())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%x: %x\n", it.Path(), it.Hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Now we're about to start to write changes to the trie. The trie is so far
|
// Now we're about to start to write changes to the trie. The trie is so far
|
||||||
// _untouched_. We can check with the prefetcher, if it can give us a trie
|
// _untouched_. We can check with the prefetcher, if it can give us a trie
|
||||||
// which has the same root, but also has some content loaded into it.
|
// which has the same root, but also has some content loaded into it.
|
||||||
|
|
@ -911,6 +955,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
var (
|
var (
|
||||||
usedAddrs []common.Address
|
usedAddrs []common.Address
|
||||||
deletedAddrs []common.Address
|
deletedAddrs []common.Address
|
||||||
|
updatedObjs []*stateObject
|
||||||
)
|
)
|
||||||
for addr, op := range s.mutations {
|
for addr, op := range s.mutations {
|
||||||
if op.applied {
|
if op.applied {
|
||||||
|
|
@ -921,11 +966,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
if op.isDelete() {
|
if op.isDelete() {
|
||||||
deletedAddrs = append(deletedAddrs, addr)
|
deletedAddrs = append(deletedAddrs, addr)
|
||||||
} else {
|
} else {
|
||||||
s.updateStateObject(s.stateObjects[addr])
|
updatedObjs = append(updatedObjs, s.stateObjects[addr])
|
||||||
s.AccountUpdated += 1
|
s.AccountUpdated += 1
|
||||||
}
|
}
|
||||||
usedAddrs = append(usedAddrs, addr) // Copy needed for closure
|
usedAddrs = append(usedAddrs, addr) // Copy needed for closure
|
||||||
}
|
}
|
||||||
|
if len(updatedObjs) > 0 {
|
||||||
|
s.updateStateObjects(updatedObjs)
|
||||||
|
}
|
||||||
for _, deletedAddr := range deletedAddrs {
|
for _, deletedAddr := range deletedAddrs {
|
||||||
s.deleteStateObject(deletedAddr)
|
s.deleteStateObject(deletedAddr)
|
||||||
s.AccountDeleted += 1
|
s.AccountDeleted += 1
|
||||||
|
|
@ -937,7 +985,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
}
|
}
|
||||||
// Track the amount of time wasted on hashing the account trie
|
// Track the amount of time wasted on hashing the account trie
|
||||||
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
||||||
|
|
||||||
hash := s.trie.Hash()
|
hash := s.trie.Hash()
|
||||||
|
|
||||||
// If witness building is enabled, gather the account trie witness
|
// If witness building is enabled, gather the account trie witness
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) {
|
||||||
}
|
}
|
||||||
for _, snapshot := range snapshotConf {
|
for _, snapshot := range snapshotConf {
|
||||||
for _, dbscheme := range dbschemeConf {
|
for _, dbscheme := range dbschemeConf {
|
||||||
if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil {
|
if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, false, nil, nil)); err != nil {
|
||||||
t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err)
|
t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,7 @@ func (t *Trie) UpdateBatch(keys [][]byte, values [][]byte) error {
|
||||||
// Insert the entries sequentially if there are not too many
|
// Insert the entries sequentially if there are not too many
|
||||||
// trie nodes in the trie.
|
// trie nodes in the trie.
|
||||||
fn, ok := t.root.(*fullNode)
|
fn, ok := t.root.(*fullNode)
|
||||||
|
|
||||||
if !ok || len(keys) < 4 { // TODO(rjl493456442) the parallelism threshold should be twisted
|
if !ok || len(keys) < 4 { // TODO(rjl493456442) the parallelism threshold should be twisted
|
||||||
for i, key := range keys {
|
for i, key := range keys {
|
||||||
err := t.Update(key, values[i])
|
err := t.Update(key, values[i])
|
||||||
|
|
@ -438,7 +439,12 @@ func (t *Trie) UpdateBatch(keys [][]byte, values [][]byte) error {
|
||||||
ikeys[hkey[0]] = append(ikeys[hkey[0]], hkey)
|
ikeys[hkey[0]] = append(ikeys[hkey[0]], hkey)
|
||||||
ivals[hkey[0]] = append(ivals[hkey[0]], values[i])
|
ivals[hkey[0]] = append(ivals[hkey[0]], values[i])
|
||||||
}
|
}
|
||||||
for pos, ks := range ikeys {
|
if len(keys) > 0 {
|
||||||
|
fn.flags = t.newFlag()
|
||||||
|
}
|
||||||
|
for p, k := range ikeys {
|
||||||
|
pos := p
|
||||||
|
ks := k
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
vs := ivals[pos]
|
vs := ivals[pos]
|
||||||
for i, k := range ks {
|
for i, k := range ks {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue