core, trie: experimentation with state witnesses

This commit is contained in:
Martin Holst Swende 2023-11-27 14:23:20 +01:00
parent 333dd956bf
commit 387b0fe6e8
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
7 changed files with 54 additions and 8 deletions

View file

@ -125,6 +125,8 @@ type Trie interface {
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error)
// NodeIterator returns an iterator that returns nodes of the trie. Iteration // NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key. And error will be returned // starts at the key after the given start key. And error will be returned
// if fails to create node iterator. // if fails to create node iterator.

View file

@ -375,11 +375,11 @@ func (s *stateObject) updateRoot() {
// commit obtains a set of dirty storage trie nodes and updates the account data. // commit obtains a set of dirty storage trie nodes and updates the account data.
// The returned set can be nil if nothing to commit. This function assumes all // The returned set can be nil if nothing to commit. This function assumes all
// storage mutations have already been flushed into trie by updateRoot. // storage mutations have already been flushed into trie by updateRoot.
func (s *stateObject) commit() (*trienode.NodeSet, error) { func (s *stateObject) commit() (*trienode.NodeSet, map[string][]byte, error) {
// Short circuit if trie is not even loaded, don't bother with committing anything // Short circuit if trie is not even loaded, don't bother with committing anything
if s.trie == nil { if s.trie == nil {
s.origin = s.data.Copy() s.origin = s.data.Copy()
return nil, nil return nil, nil, nil
} }
// Track the amount of time wasted on committing the storage trie // Track the amount of time wasted on committing the storage trie
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
@ -388,15 +388,16 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
// The trie is currently in an open state and could potentially contain // The trie is currently in an open state and could potentially contain
// cached mutations. Call commit to acquire a set of nodes that have been // cached mutations. Call commit to acquire a set of nodes that have been
// modified, the set can be nil if nothing to commit. // modified, the set can be nil if nothing to commit.
root, nodes, err := s.trie.Commit(false) root, nodes, accessList, err := s.trie.CommitAndObtainAccessList(false)
//root, nodes, err := s.trie.Commit(false)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
s.data.Root = root s.data.Root = root
// Update original account data after commit // Update original account data after commit
s.origin = s.data.Copy() s.origin = s.data.Copy()
return nodes, nil return nodes, accessList, nil
} }
// AddBalance adds amount to s's balance. // AddBalance adds amount to s's balance.

View file

@ -1169,6 +1169,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
if s.dbErr != nil { if s.dbErr != nil {
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
} }
w := newWitness(s.originalRoot)
// Finalize any pending changes and merge everything into the tries // Finalize any pending changes and merge everything into the tries
s.IntermediateRoot(deleteEmptyObjects) s.IntermediateRoot(deleteEmptyObjects)
@ -1198,7 +1199,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
obj.dirtyCode = false obj.dirtyCode = false
} }
// Write any storage changes in the state object to its storage trie // Write any storage changes in the state object to its storage trie
set, err := obj.commit() set, accessList, err := obj.commit()
w.addAccessList(obj.addrHash, accessList)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -1224,7 +1226,9 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
start = time.Now() start = time.Now()
} }
root, set, err := s.trie.Commit(true) //root, set, err := s.trie.Commit(true)
root, set, accessList, err := s.trie.CommitAndObtainAccessList(true)
w.addAccessList(common.Hash{}, accessList)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -1298,6 +1302,9 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte) s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte)
s.stateObjectsDirty = make(map[common.Address]struct{}) s.stateObjectsDirty = make(map[common.Address]struct{})
s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount)
w.Dump()
return root, nil return root, nil
} }

View file

@ -177,6 +177,10 @@ func (t *odrTrie) DeleteAccount(address common.Address) error {
}) })
} }
func (t *odrTrie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
panic("not implemented")
}
func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
if t.trie == nil { if t.trie == nil {
return t.id.Root, nil, nil return t.id.Root, nil, nil

View file

@ -216,6 +216,22 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
return t.preimages.preimage(common.BytesToHash(shaKey)) return t.preimages.preimage(common.BytesToHash(shaKey))
} }
func (t *StateTrie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
// Write all the pre-images to the actual disk database
if len(t.getSecKeyCache()) > 0 {
if t.preimages != nil {
preimages := make(map[common.Hash][]byte)
for hk, key := range t.secKeyCache {
preimages[common.BytesToHash([]byte(hk))] = key
}
t.preimages.insertPreimage(preimages)
}
t.secKeyCache = make(map[string][]byte)
}
// Commit the trie and return its modified nodeset.
return t.trie.CommitAndObtainAccessList(collectLeaf)
}
// Commit collects all dirty nodes in the trie and replaces them with the // Commit collects all dirty nodes in the trie and replaces them with the
// corresponding node hash. All collected nodes (including dirty leaves if // corresponding node hash. All collected nodes (including dirty leaves if
// collectLeaf is true) will be encapsulated into a nodeset for return. // collectLeaf is true) will be encapsulated into a nodeset for return.

View file

@ -601,6 +601,18 @@ func (t *Trie) Hash() common.Hash {
return common.BytesToHash(hash.(hashNode)) return common.BytesToHash(hash.(hashNode))
} }
func (t *Trie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
accessList := t.tracer.accessList
// Commit will reset the tracer accessList, so after this
// operation, we have full ownership of the map (hence: no need to
// deep-copy or even copy).
rootHash, nodes, err := t.Commit(collectLeaf)
if err != nil {
return rootHash, nodes, nil, err
}
return rootHash, nodes, accessList, err
}
// Commit collects all dirty nodes in the trie and replaces them with the // Commit collects all dirty nodes in the trie and replaces them with the
// corresponding node hash. All collected nodes (including dirty leaves if // corresponding node hash. All collected nodes (including dirty leaves if
// collectLeaf is true) will be encapsulated into a nodeset for return. // collectLeaf is true) will be encapsulated into a nodeset for return.
@ -608,8 +620,8 @@ func (t *Trie) Hash() common.Hash {
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
defer t.tracer.reset()
defer func() { defer func() {
t.tracer.reset()
t.committed = true t.committed = true
}() }()
// Trie is empty and can be classified into two types of situations: // Trie is empty and can be classified into two types of situations:

View file

@ -218,6 +218,10 @@ func (t *VerkleTrie) Hash() common.Hash {
return t.root.Commit().Bytes() return t.root.Commit().Bytes()
} }
func (t *VerkleTrie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
panic("not implemented")
}
// Commit writes all nodes to the tree's memory database. // Commit writes all nodes to the tree's memory database.
func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
root, ok := t.root.(*verkle.InternalNode) root, ok := t.root.(*verkle.InternalNode)