mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
all: implement witness
This commit is contained in:
parent
4e1e37323d
commit
213a0eb149
23 changed files with 173 additions and 131 deletions
|
|
@ -115,7 +115,7 @@ type Trie interface {
|
|||
// The returned nodeset can be nil if the trie is clean(nothing to commit).
|
||||
// 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
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error)
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
|
|||
for i, key := range result.keys {
|
||||
snapTrie.Update(key, result.vals[i])
|
||||
}
|
||||
root, nodes, err := snapTrie.Commit(false)
|
||||
root, nodes, _, err := snapTrie.Commit(false)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
if !commit {
|
||||
return stTrie.Hash()
|
||||
}
|
||||
root, nodes, _ := stTrie.Commit(false)
|
||||
root, nodes, _, _ := stTrie.Commit(false)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
}
|
||||
|
||||
func (t *testHelper) Commit() common.Hash {
|
||||
root, nodes, _ := t.accTrie.Commit(true)
|
||||
root, nodes, _, _ := t.accTrie.Commit(true)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
|||
// 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
|
||||
// modified, the set can be nil if nothing to commit.
|
||||
root, nodes, err := s.trie.Commit(false)
|
||||
root, nodes, _, err := s.trie.Commit(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1222,7 +1222,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
|||
if metrics.EnabledExpensive {
|
||||
start = time.Now()
|
||||
}
|
||||
root, set, err := s.trie.Commit(true)
|
||||
root, set, _, err := s.trie.Commit(true)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1482,7 +1482,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes, _, _ := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1544,7 +1544,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes, _, _ := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1590,7 +1590,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set, _, _ := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1655,7 +1655,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set, _, _ := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1697,7 +1697,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
@ -1748,7 +1748,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e
|
|||
|
||||
// Commit implements core.ChainIndexerBackend
|
||||
func (c *ChtIndexerBackend) Commit() error {
|
||||
root, nodes, err := c.trie.Commit(false)
|
||||
root, nodes, _, err := c.trie.Commit(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -467,7 +467,7 @@ func (b *BloomTrieIndexerBackend) Commit() error {
|
|||
return terr
|
||||
}
|
||||
}
|
||||
root, nodes, err := b.trie.Commit(false)
|
||||
root, nodes, _, err := b.trie.Commit(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,9 +177,9 @@ func (t *odrTrie) DeleteAccount(address common.Address) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
||||
func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
|
||||
if t.trie == nil {
|
||||
return t.id.Root, nil, nil
|
||||
return t.id.Root, nil, nil, nil
|
||||
}
|
||||
return t.trie.Commit(collectLeaf)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ func (f *fuzzer) fuzz() int {
|
|||
return 0
|
||||
}
|
||||
// Flush trie -> database
|
||||
rootA, nodes, err := trieA.Commit(false)
|
||||
rootA, nodes, _, err := trieA.Commit(false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ func runRandTest(rt randTest) error {
|
|||
case opHash:
|
||||
tr.Hash()
|
||||
case opCommit:
|
||||
hash, nodes, err := tr.Commit(false)
|
||||
hash, nodes, _, err := tr.Commit(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,15 +28,15 @@ import (
|
|||
// insertion order.
|
||||
type committer struct {
|
||||
nodes *trienode.NodeSet
|
||||
tracer *tracer
|
||||
witness *trienode.Witness
|
||||
collectLeaf bool
|
||||
}
|
||||
|
||||
// newCommitter creates a new committer or picks one from the pool.
|
||||
func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer {
|
||||
func newCommitter(nodeset *trienode.NodeSet, witness *trienode.Witness, collectLeaf bool) *committer {
|
||||
return &committer{
|
||||
nodes: nodeset,
|
||||
tracer: tracer,
|
||||
witness: witness,
|
||||
collectLeaf: collectLeaf,
|
||||
}
|
||||
}
|
||||
|
|
@ -131,8 +131,7 @@ func (c *committer) store(path []byte, n node) node {
|
|||
// The node is embedded in its parent, in other words, this node
|
||||
// will not be stored in the database independently, mark it as
|
||||
// deleted only if the node was existent in database before.
|
||||
_, ok := c.tracer.accessList[string(path)]
|
||||
if ok {
|
||||
if c.witness.Has(string(path)) {
|
||||
c.nodes.AddNode(path, trienode.NewDeleted())
|
||||
}
|
||||
return n
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func TestIterator(t *testing.T) {
|
|||
all[val.k] = val.v
|
||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -251,7 +251,7 @@ func TestDifferenceIterator(t *testing.T) {
|
|||
for _, val := range testdata1 {
|
||||
triea.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
rootA, nodesA, _ := triea.Commit(false)
|
||||
rootA, nodesA, _, _ := triea.Commit(false)
|
||||
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
|
||||
triea, _ = New(TrieID(rootA), dba)
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ func TestDifferenceIterator(t *testing.T) {
|
|||
for _, val := range testdata2 {
|
||||
trieb.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
rootB, nodesB, _ := trieb.Commit(false)
|
||||
rootB, nodesB, _, _ := trieb.Commit(false)
|
||||
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
|
||||
trieb, _ = New(TrieID(rootB), dbb)
|
||||
|
||||
|
|
@ -293,7 +293,7 @@ func TestUnionIterator(t *testing.T) {
|
|||
for _, val := range testdata1 {
|
||||
triea.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
rootA, nodesA, _ := triea.Commit(false)
|
||||
rootA, nodesA, _, _ := triea.Commit(false)
|
||||
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
|
||||
triea, _ = New(TrieID(rootA), dba)
|
||||
|
||||
|
|
@ -302,7 +302,7 @@ func TestUnionIterator(t *testing.T) {
|
|||
for _, val := range testdata2 {
|
||||
trieb.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
rootB, nodesB, _ := trieb.Commit(false)
|
||||
rootB, nodesB, _, _ := trieb.Commit(false)
|
||||
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
|
||||
trieb, _ = New(TrieID(rootB), dbb)
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) {
|
|||
for _, val := range testdata1 {
|
||||
tr.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := tr.Commit(false)
|
||||
root, nodes, _, _ := tr.Commit(false)
|
||||
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
if !memonly {
|
||||
tdb.Commit(root, false)
|
||||
|
|
@ -474,7 +474,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin
|
|||
for _, val := range testdata1 {
|
||||
ctr.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := ctr.Commit(false)
|
||||
root, nodes, _, _ := ctr.Commit(false)
|
||||
for path, n := range nodes.Nodes {
|
||||
if n.Hash == barNodeHash {
|
||||
barNodePath = []byte(path)
|
||||
|
|
@ -554,7 +554,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) {
|
|||
all[val.k] = val.v
|
||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
triedb.Commit(root, false)
|
||||
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
|
|||
// All cached preimages will be also flushed if preimages recording is enabled.
|
||||
// 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
|
||||
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
||||
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
|
||||
// Write all the pre-images to the actual disk database
|
||||
if len(t.getSecKeyCache()) > 0 {
|
||||
if t.preimages != nil {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) {
|
|||
trie.MustUpdate(key, val)
|
||||
}
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||
panic(fmt.Errorf("failed to commit db %v", err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *Database, *StateTrie, map[str
|
|||
trie.MustUpdate(key, val)
|
||||
}
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||
panic(fmt.Errorf("failed to commit db %v", err))
|
||||
}
|
||||
|
|
@ -759,7 +759,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
|
|||
srcTrie.MustUpdate(key, val)
|
||||
diff[string(key)] = val
|
||||
}
|
||||
root, nodes, _ := srcTrie.Commit(false)
|
||||
root, nodes, _, _ := srcTrie.Commit(false)
|
||||
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -784,7 +784,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
|
|||
srcTrie.MustUpdate([]byte(k), val)
|
||||
reverted[k] = val
|
||||
}
|
||||
root, nodes, _ = srcTrie.Commit(false)
|
||||
root, nodes, _, _ = srcTrie.Commit(false)
|
||||
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -842,7 +842,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
|||
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA)
|
||||
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA)
|
||||
|
||||
rootA, nodesA, _ := srcTrie.Commit(false)
|
||||
rootA, nodesA, _, _ := srcTrie.Commit(false)
|
||||
if err := srcTrieDB.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -861,7 +861,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
|||
deleteFn([]byte{0x13, 0x44}, srcTrie, stateB)
|
||||
writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB)
|
||||
|
||||
rootB, nodesB, _ := srcTrie.Commit(false)
|
||||
rootB, nodesB, _, _ := srcTrie.Commit(false)
|
||||
if err := srcTrieDB.Update(rootB, rootA, 0, trienode.NewWithNodeSet(nodesB), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -879,7 +879,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
|||
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC)
|
||||
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC)
|
||||
|
||||
rootC, nodesC, _ := srcTrie.Commit(false)
|
||||
rootC, nodesC, _, _ := srcTrie.Commit(false)
|
||||
if err := srcTrieDB.Update(rootC, rootB, 0, trienode.NewWithNodeSet(nodesC), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@
|
|||
|
||||
package trie
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// tracer tracks the changes of trie nodes. During the trie operations,
|
||||
// some nodes can be deleted from the trie, while these deleted nodes
|
||||
// won't be captured by trie.Hasher or trie.Committer. Thus, these deleted
|
||||
|
|
@ -33,34 +29,21 @@ import (
|
|||
// This tool can track all of them no matter the node is embedded in its
|
||||
// parent or not, but valueNode is never tracked.
|
||||
//
|
||||
// Besides, it's also used for recording the original value of the nodes
|
||||
// when they are resolved from the disk. The pre-value of the nodes will
|
||||
// be used to construct trie history in the future.
|
||||
//
|
||||
// Note tracer is not thread-safe, callers should be responsible for handling
|
||||
// the concurrency issues by themselves.
|
||||
type tracer struct {
|
||||
inserts map[string]struct{}
|
||||
deletes map[string]struct{}
|
||||
accessList map[string][]byte
|
||||
inserts map[string]struct{}
|
||||
deletes map[string]struct{}
|
||||
}
|
||||
|
||||
// newTracer initializes the tracer for capturing trie changes.
|
||||
func newTracer() *tracer {
|
||||
return &tracer{
|
||||
inserts: make(map[string]struct{}),
|
||||
deletes: make(map[string]struct{}),
|
||||
accessList: make(map[string][]byte),
|
||||
inserts: make(map[string]struct{}),
|
||||
deletes: make(map[string]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// onRead tracks the newly loaded trie node and caches the rlp-encoded
|
||||
// blob internally. Don't change the value outside of function since
|
||||
// it's not deep-copied.
|
||||
func (t *tracer) onRead(path []byte, val []byte) {
|
||||
t.accessList[string(path)] = val
|
||||
}
|
||||
|
||||
// onInsert tracks the newly inserted trie node. If it's already
|
||||
// in the deletion set (resurrected node), then just wipe it from
|
||||
// the deletion set as it's "untouched".
|
||||
|
|
@ -83,19 +66,11 @@ func (t *tracer) onDelete(path []byte) {
|
|||
t.deletes[string(path)] = struct{}{}
|
||||
}
|
||||
|
||||
// reset clears the content tracked by tracer.
|
||||
func (t *tracer) reset() {
|
||||
t.inserts = make(map[string]struct{})
|
||||
t.deletes = make(map[string]struct{})
|
||||
t.accessList = make(map[string][]byte)
|
||||
}
|
||||
|
||||
// copy returns a deep copied tracer instance.
|
||||
func (t *tracer) copy() *tracer {
|
||||
var (
|
||||
inserts = make(map[string]struct{})
|
||||
deletes = make(map[string]struct{})
|
||||
accessList = make(map[string][]byte)
|
||||
inserts = make(map[string]struct{})
|
||||
deletes = make(map[string]struct{})
|
||||
)
|
||||
for path := range t.inserts {
|
||||
inserts[path] = struct{}{}
|
||||
|
|
@ -103,27 +78,16 @@ func (t *tracer) copy() *tracer {
|
|||
for path := range t.deletes {
|
||||
deletes[path] = struct{}{}
|
||||
}
|
||||
for path, blob := range t.accessList {
|
||||
accessList[path] = common.CopyBytes(blob)
|
||||
}
|
||||
return &tracer{
|
||||
inserts: inserts,
|
||||
deletes: deletes,
|
||||
accessList: accessList,
|
||||
inserts: inserts,
|
||||
deletes: deletes,
|
||||
}
|
||||
}
|
||||
|
||||
// deletedNodes returns a list of node paths which are deleted from the trie.
|
||||
func (t *tracer) deletedNodes() []string {
|
||||
// deleteList returns a list of node paths which are marked as deleted.
|
||||
func (t *tracer) deleteList() []string {
|
||||
var paths []string
|
||||
for path := range t.deletes {
|
||||
// It's possible a few deleted nodes were embedded
|
||||
// in their parent before, the deletions can be no
|
||||
// effect by deleting nothing, filter them out.
|
||||
_, ok := t.accessList[path]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
paths = append(paths, path)
|
||||
}
|
||||
return paths
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
|
|||
}
|
||||
insertSet := copySet(trie.tracer.inserts) // copy before commit
|
||||
deleteSet := copySet(trie.tracer.deletes) // copy before commit
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
seen := setKeys(iterNodes(db, root))
|
||||
|
|
@ -136,7 +136,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
|||
for _, val := range vals {
|
||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -151,7 +151,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
|||
for _, val := range vals {
|
||||
trie.MustUpdate([]byte(val.k), randBytes(32))
|
||||
}
|
||||
root, nodes, _ = trie.Commit(false)
|
||||
root, nodes, _, _ = trie.Commit(false)
|
||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -169,7 +169,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
|||
keys = append(keys, string(key))
|
||||
trie.MustUpdate(key, randBytes(32))
|
||||
}
|
||||
root, nodes, _ = trie.Commit(false)
|
||||
root, nodes, _, _ = trie.Commit(false)
|
||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -184,7 +184,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
|||
for _, key := range keys {
|
||||
trie.MustUpdate([]byte(key), nil)
|
||||
}
|
||||
root, nodes, _ = trie.Commit(false)
|
||||
root, nodes, _, _ = trie.Commit(false)
|
||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -199,7 +199,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
|||
for _, val := range vals {
|
||||
trie.MustUpdate([]byte(val.k), nil)
|
||||
}
|
||||
root, nodes, _ = trie.Commit(false)
|
||||
root, nodes, _, _ = trie.Commit(false)
|
||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
@ -218,7 +218,7 @@ func TestAccessListLeak(t *testing.T) {
|
|||
for _, val := range standard {
|
||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
var cases = []struct {
|
||||
|
|
@ -248,9 +248,9 @@ func TestAccessListLeak(t *testing.T) {
|
|||
}
|
||||
for _, c := range cases {
|
||||
trie, _ = New(TrieID(root), db)
|
||||
n1 := len(trie.tracer.accessList)
|
||||
n1 := trie.witness.Len()
|
||||
c.op(trie)
|
||||
n2 := len(trie.tracer.accessList)
|
||||
n2 := trie.witness.Len()
|
||||
|
||||
if n1 != n2 {
|
||||
t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2)
|
||||
|
|
@ -268,7 +268,7 @@ func TestTinyTree(t *testing.T) {
|
|||
for _, val := range tiny {
|
||||
trie.MustUpdate([]byte(val.k), randBytes(32))
|
||||
}
|
||||
root, set, _ := trie.Commit(false)
|
||||
root, set, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(set), nil)
|
||||
|
||||
parent := root
|
||||
|
|
@ -277,7 +277,7 @@ func TestTinyTree(t *testing.T) {
|
|||
for _, val := range tiny {
|
||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
||||
}
|
||||
root, set, _ = trie.Commit(false)
|
||||
root, set, _, _ = trie.Commit(false)
|
||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(set), nil)
|
||||
|
||||
trie, _ = New(TrieID(root), db)
|
||||
|
|
|
|||
50
trie/trie.go
50
trie/trie.go
|
|
@ -53,7 +53,8 @@ type Trie struct {
|
|||
|
||||
// tracer is the tool to track the trie changes.
|
||||
// It will be reset after each commit operation.
|
||||
tracer *tracer
|
||||
tracer *tracer
|
||||
witness *trienode.Witness
|
||||
}
|
||||
|
||||
// newFlag returns the cache flag value for a newly created node.
|
||||
|
|
@ -70,6 +71,7 @@ func (t *Trie) Copy() *Trie {
|
|||
unhashed: t.unhashed,
|
||||
reader: t.reader,
|
||||
tracer: t.tracer.copy(),
|
||||
witness: t.witness.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,9 +87,10 @@ func New(id *ID, db *Database) (*Trie, error) {
|
|||
return nil, err
|
||||
}
|
||||
trie := &Trie{
|
||||
owner: id.Owner,
|
||||
reader: reader,
|
||||
tracer: newTracer(),
|
||||
owner: id.Owner,
|
||||
reader: reader,
|
||||
tracer: newTracer(),
|
||||
witness: trienode.NewWitness(id.Owner),
|
||||
}
|
||||
if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash {
|
||||
rootnode, err := trie.resolveAndTrack(id.Root[:], nil)
|
||||
|
|
@ -589,7 +592,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.tracer.onRead(prefix, blob)
|
||||
t.witness.Add(string(prefix), blob)
|
||||
return mustDecodeNode(n, blob), nil
|
||||
}
|
||||
|
||||
|
|
@ -607,9 +610,11 @@ func (t *Trie) Hash() common.Hash {
|
|||
// The returned nodeset can be nil if the trie is clean (nothing to commit).
|
||||
// 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
|
||||
func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
||||
defer t.tracer.reset()
|
||||
func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
|
||||
// Reset the trie internal states at the end.
|
||||
defer func() {
|
||||
t.tracer = newTracer()
|
||||
t.witness = trienode.NewWitness(t.owner)
|
||||
t.committed = true
|
||||
}()
|
||||
// Trie is empty and can be classified into two types of situations:
|
||||
|
|
@ -617,15 +622,22 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
|||
// (b) The trie was non-empty and all nodes are dropped => return
|
||||
// the node set includes all deleted nodes
|
||||
if t.root == nil {
|
||||
paths := t.tracer.deletedNodes()
|
||||
// It's possible a few deleted nodes were embedded in their parent before,
|
||||
// the deletions can be no effect by deleting nothing, filter them out.
|
||||
var paths []string
|
||||
for _, p := range t.tracer.deleteList() {
|
||||
if t.witness.Has(p) {
|
||||
paths = append(paths, p)
|
||||
}
|
||||
}
|
||||
if len(paths) == 0 {
|
||||
return types.EmptyRootHash, nil, nil // case (a)
|
||||
return types.EmptyRootHash, nil, nil, nil // case (a)
|
||||
}
|
||||
nodes := trienode.NewNodeSet(t.owner)
|
||||
for _, path := range paths {
|
||||
nodes.AddNode([]byte(path), trienode.NewDeleted())
|
||||
}
|
||||
return types.EmptyRootHash, nodes, nil // case (b)
|
||||
return types.EmptyRootHash, nodes, t.witness, nil // case (b)
|
||||
}
|
||||
// Derive the hash for all dirty nodes first. We hold the assumption
|
||||
// in the following procedure that all nodes are hashed.
|
||||
|
|
@ -637,14 +649,19 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
|||
// Replace the root node with the origin hash in order to
|
||||
// ensure all resolved nodes are dropped after the commit.
|
||||
t.root = hashedNode
|
||||
return rootHash, nil, nil
|
||||
return rootHash, nil, t.witness, nil
|
||||
}
|
||||
nodes := trienode.NewNodeSet(t.owner)
|
||||
for _, path := range t.tracer.deletedNodes() {
|
||||
nodes.AddNode([]byte(path), trienode.NewDeleted())
|
||||
|
||||
// It's possible a few deleted nodes were embedded in their parent before,
|
||||
// the deletions can be no effect by deleting nothing, filter them out.
|
||||
for _, p := range t.tracer.deleteList() {
|
||||
if t.witness.Has(p) {
|
||||
nodes.AddNode([]byte(p), trienode.NewDeleted())
|
||||
}
|
||||
}
|
||||
t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root)
|
||||
return rootHash, nodes, nil
|
||||
t.root = newCommitter(nodes, t.witness, collectLeaf).Commit(t.root)
|
||||
return rootHash, nodes, t.witness, nil
|
||||
}
|
||||
|
||||
// hashRoot calculates the root hash of the given trie
|
||||
|
|
@ -667,6 +684,7 @@ func (t *Trie) Reset() {
|
|||
t.root = nil
|
||||
t.owner = common.Hash{}
|
||||
t.unhashed = 0
|
||||
t.tracer.reset()
|
||||
t.tracer = newTracer()
|
||||
t.witness = trienode.NewWitness(common.Hash{})
|
||||
t.committed = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) {
|
|||
trie := NewEmpty(triedb)
|
||||
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
||||
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
if !memonly {
|
||||
|
|
@ -182,7 +182,7 @@ func TestInsert(t *testing.T) {
|
|||
updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
|
||||
exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
|
||||
root, _, _ = trie.Commit(false)
|
||||
root, _, _, _ = trie.Commit(false)
|
||||
if root != exp {
|
||||
t.Errorf("case 2: exp %x got %x", exp, root)
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ func TestGet(t *testing.T) {
|
|||
if i == 1 {
|
||||
return
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
trie, _ = New(TrieID(root), db)
|
||||
}
|
||||
|
|
@ -279,7 +279,7 @@ func TestReplication(t *testing.T) {
|
|||
for _, val := range vals {
|
||||
updateString(trie, val.k, val.v)
|
||||
}
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
// create a new trie on top of the database and check that lookups work.
|
||||
|
|
@ -292,7 +292,7 @@ func TestReplication(t *testing.T) {
|
|||
t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
|
||||
}
|
||||
}
|
||||
hash, nodes, _ := trie2.Commit(false)
|
||||
hash, nodes, _, _ := trie2.Commit(false)
|
||||
if hash != root {
|
||||
t.Errorf("root failure. expected %x got %x", root, hash)
|
||||
}
|
||||
|
|
@ -506,7 +506,7 @@ func runRandTest(rt randTest) bool {
|
|||
case opHash:
|
||||
tr.Hash()
|
||||
case opCommit:
|
||||
root, nodes, _ := tr.Commit(true)
|
||||
root, nodes, _, _ := tr.Commit(true)
|
||||
if nodes != nil {
|
||||
triedb.Update(root, origin, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
}
|
||||
|
|
@ -743,7 +743,7 @@ func TestCommitAfterHash(t *testing.T) {
|
|||
if exp != root {
|
||||
t.Errorf("got %x, exp %x", root, exp)
|
||||
}
|
||||
root, _, _ = trie.Commit(false)
|
||||
root, _, _, _ = trie.Commit(false)
|
||||
if exp != root {
|
||||
t.Errorf("got %x, exp %x", root, exp)
|
||||
}
|
||||
|
|
@ -852,7 +852,7 @@ func TestCommitSequence(t *testing.T) {
|
|||
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
|
||||
}
|
||||
// Flush trie -> database
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Commit(root, false)
|
||||
|
|
@ -893,7 +893,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
|
|||
trie.MustUpdate(key, val)
|
||||
}
|
||||
// Flush trie -> database
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Commit(root, false)
|
||||
|
|
@ -932,7 +932,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
|
|||
stTrie.Update(key, val)
|
||||
}
|
||||
// Flush trie -> database
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
db.Commit(root, false)
|
||||
|
|
@ -980,7 +980,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
|
|||
trie.Update(key, []byte{0x1})
|
||||
stTrie.Update(key, []byte{0x1})
|
||||
// Flush trie -> database
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
db.Commit(root, false)
|
||||
|
|
@ -1153,7 +1153,7 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts []
|
|||
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
|
||||
}
|
||||
h := trie.Hash()
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes, _, _ := trie.Commit(false)
|
||||
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
b.StartTimer()
|
||||
triedb.Dereference(h)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm
|
|||
h.Update(key.Bytes(), val)
|
||||
}
|
||||
}
|
||||
root, nodes, _ := h.Commit(false)
|
||||
root, nodes, _, _ := h.Commit(false)
|
||||
return root, nodes
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error {
|
|||
|
||||
// Commit computes the new hash of the states and returns the set with all
|
||||
// state changes.
|
||||
func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
||||
func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
|
||||
var (
|
||||
nodes = make(map[common.Hash][]byte)
|
||||
set = trienode.NewNodeSet(h.owner)
|
||||
|
|
@ -108,7 +108,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e
|
|||
if root == types.EmptyRootHash && h.root != types.EmptyRootHash {
|
||||
set.AddNode(nil, trienode.NewDeleted())
|
||||
}
|
||||
return root, set, nil
|
||||
return root, set, nil, nil
|
||||
}
|
||||
|
||||
// hash performs the hash computation upon the provided states.
|
||||
|
|
|
|||
61
trie/trienode/witness.go
Normal file
61
trie/trienode/witness.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2023 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/
|
||||
|
||||
package trienode
|
||||
|
||||
import "github.com/ethereum/go-ethereum/common"
|
||||
|
||||
// Witness is the set of nodes retrieved from the database for executing a state
|
||||
// transition. It can be considered as the previous state for the state transition,
|
||||
// effectively serving as the witness for that transition.
|
||||
type Witness struct {
|
||||
Owner common.Hash
|
||||
Nodes map[string][]byte
|
||||
}
|
||||
|
||||
// NewWitness constructs a witness structure.
|
||||
func NewWitness(owner common.Hash) *Witness {
|
||||
return &Witness{Owner: owner, Nodes: make(map[string][]byte)}
|
||||
}
|
||||
|
||||
// Add tracks the node resolved from database. Don't change the blob outside of
|
||||
// function since it's not deep-copied.
|
||||
func (w *Witness) Add(path string, blob []byte) {
|
||||
w.Nodes[path] = common.CopyBytes(blob)
|
||||
}
|
||||
|
||||
// Has returns the indicator whether the specified node is in witness.
|
||||
func (w *Witness) Has(path string) bool {
|
||||
_, ok := w.Nodes[path]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Len returns the number of nodes resolved in the witness.
|
||||
func (w *Witness) Len() int {
|
||||
return len(w.Nodes)
|
||||
}
|
||||
|
||||
// Copy returns a deep copied witness structure.
|
||||
func (w *Witness) Copy() *Witness {
|
||||
cpy := &Witness{
|
||||
Owner: w.Owner,
|
||||
Nodes: make(map[string][]byte),
|
||||
}
|
||||
for p, n := range w.Nodes {
|
||||
cpy.Nodes[p] = n // it's not deep-copied
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ type Trie interface {
|
|||
|
||||
// Commit the trie and returns a set of dirty nodes generated along with
|
||||
// the new root hash.
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error)
|
||||
}
|
||||
|
||||
// TrieLoader wraps functions to load tries.
|
||||
|
|
@ -129,7 +129,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre
|
|||
return nil, fmt.Errorf("failed to revert state, err: %w", err)
|
||||
}
|
||||
}
|
||||
root, result, err := tr.Commit(false)
|
||||
root, result, _, err := tr.Commit(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -184,7 +184,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
root, result, err := st.Commit(false)
|
||||
root, result, _, err := st.Commit(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
root, result, err := st.Commit(false)
|
||||
root, result, _, err := st.Commit(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue