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).
|
// 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
|
// 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
|
||||||
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
|
// 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
|
||||||
|
|
|
||||||
|
|
@ -362,7 +362,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
|
||||||
for i, key := range result.keys {
|
for i, key := range result.keys {
|
||||||
snapTrie.Update(key, result.vals[i])
|
snapTrie.Update(key, result.vals[i])
|
||||||
}
|
}
|
||||||
root, nodes, err := snapTrie.Commit(false)
|
root, nodes, _, err := snapTrie.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
||||||
if !commit {
|
if !commit {
|
||||||
return stTrie.Hash()
|
return stTrie.Hash()
|
||||||
}
|
}
|
||||||
root, nodes, _ := stTrie.Commit(false)
|
root, nodes, _, _ := stTrie.Commit(false)
|
||||||
if nodes != nil {
|
if nodes != nil {
|
||||||
t.nodes.Merge(nodes)
|
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 {
|
func (t *testHelper) Commit() common.Hash {
|
||||||
root, nodes, _ := t.accTrie.Commit(true)
|
root, nodes, _, _ := t.accTrie.Commit(true)
|
||||||
if nodes != nil {
|
if nodes != nil {
|
||||||
t.nodes.Merge(nodes)
|
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
|
// 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, _, err := s.trie.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1222,7 +1222,7 @@ 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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
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
|
// Commit the state changes into db and re-create the trie
|
||||||
// for accessing later.
|
// for accessing later.
|
||||||
root, nodes, _ := accTrie.Commit(false)
|
root, nodes, _, _ := accTrie.Commit(false)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
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
|
// Commit the state changes into db and re-create the trie
|
||||||
// for accessing later.
|
// for accessing later.
|
||||||
root, nodes, _ := accTrie.Commit(false)
|
root, nodes, _, _ := accTrie.Commit(false)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||||
|
|
@ -1590,7 +1590,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
|
||||||
slices.SortFunc(entries, (*kv).cmp)
|
slices.SortFunc(entries, (*kv).cmp)
|
||||||
|
|
||||||
// Commit account trie
|
// Commit account trie
|
||||||
root, set, _ := accTrie.Commit(true)
|
root, set, _, _ := accTrie.Commit(true)
|
||||||
nodes.Merge(set)
|
nodes.Merge(set)
|
||||||
|
|
||||||
// Commit gathered dirty nodes into database
|
// Commit gathered dirty nodes into database
|
||||||
|
|
@ -1655,7 +1655,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
|
||||||
slices.SortFunc(entries, (*kv).cmp)
|
slices.SortFunc(entries, (*kv).cmp)
|
||||||
|
|
||||||
// Commit account trie
|
// Commit account trie
|
||||||
root, set, _ := accTrie.Commit(true)
|
root, set, _, _ := accTrie.Commit(true)
|
||||||
nodes.Merge(set)
|
nodes.Merge(set)
|
||||||
|
|
||||||
// Commit gathered dirty nodes into database
|
// 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)
|
entries = append(entries, elem)
|
||||||
}
|
}
|
||||||
slices.SortFunc(entries, (*kv).cmp)
|
slices.SortFunc(entries, (*kv).cmp)
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
return root, nodes, entries
|
return root, nodes, entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1748,7 +1748,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
|
||||||
entries = append(entries, elem)
|
entries = append(entries, elem)
|
||||||
}
|
}
|
||||||
slices.SortFunc(entries, (*kv).cmp)
|
slices.SortFunc(entries, (*kv).cmp)
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
return root, nodes, entries
|
return root, nodes, entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e
|
||||||
|
|
||||||
// Commit implements core.ChainIndexerBackend
|
// Commit implements core.ChainIndexerBackend
|
||||||
func (c *ChtIndexerBackend) Commit() error {
|
func (c *ChtIndexerBackend) Commit() error {
|
||||||
root, nodes, err := c.trie.Commit(false)
|
root, nodes, _, err := c.trie.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +467,7 @@ func (b *BloomTrieIndexerBackend) Commit() error {
|
||||||
return terr
|
return terr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, nodes, err := b.trie.Commit(false)
|
root, nodes, _, err := b.trie.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if t.trie == nil {
|
||||||
return t.id.Root, nil, nil
|
return t.id.Root, nil, nil, nil
|
||||||
}
|
}
|
||||||
return t.trie.Commit(collectLeaf)
|
return t.trie.Commit(collectLeaf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ func (f *fuzzer) fuzz() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
// Flush trie -> database
|
// Flush trie -> database
|
||||||
rootA, nodes, err := trieA.Commit(false)
|
rootA, nodes, _, err := trieA.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ func runRandTest(rt randTest) error {
|
||||||
case opHash:
|
case opHash:
|
||||||
tr.Hash()
|
tr.Hash()
|
||||||
case opCommit:
|
case opCommit:
|
||||||
hash, nodes, err := tr.Commit(false)
|
hash, nodes, _, err := tr.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,15 @@ import (
|
||||||
// insertion order.
|
// insertion order.
|
||||||
type committer struct {
|
type committer struct {
|
||||||
nodes *trienode.NodeSet
|
nodes *trienode.NodeSet
|
||||||
tracer *tracer
|
witness *trienode.Witness
|
||||||
collectLeaf bool
|
collectLeaf bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCommitter creates a new committer or picks one from the pool.
|
// 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{
|
return &committer{
|
||||||
nodes: nodeset,
|
nodes: nodeset,
|
||||||
tracer: tracer,
|
witness: witness,
|
||||||
collectLeaf: collectLeaf,
|
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
|
// The node is embedded in its parent, in other words, this node
|
||||||
// will not be stored in the database independently, mark it as
|
// will not be stored in the database independently, mark it as
|
||||||
// deleted only if the node was existent in database before.
|
// deleted only if the node was existent in database before.
|
||||||
_, ok := c.tracer.accessList[string(path)]
|
if c.witness.Has(string(path)) {
|
||||||
if ok {
|
|
||||||
c.nodes.AddNode(path, trienode.NewDeleted())
|
c.nodes.AddNode(path, trienode.NewDeleted())
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func TestIterator(t *testing.T) {
|
||||||
all[val.k] = val.v
|
all[val.k] = val.v
|
||||||
trie.MustUpdate([]byte(val.k), []byte(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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -251,7 +251,7 @@ func TestDifferenceIterator(t *testing.T) {
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
triea.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
|
||||||
triea, _ = New(TrieID(rootA), dba)
|
triea, _ = New(TrieID(rootA), dba)
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ func TestDifferenceIterator(t *testing.T) {
|
||||||
for _, val := range testdata2 {
|
for _, val := range testdata2 {
|
||||||
trieb.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
|
||||||
trieb, _ = New(TrieID(rootB), dbb)
|
trieb, _ = New(TrieID(rootB), dbb)
|
||||||
|
|
||||||
|
|
@ -293,7 +293,7 @@ func TestUnionIterator(t *testing.T) {
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
triea.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
|
||||||
triea, _ = New(TrieID(rootA), dba)
|
triea, _ = New(TrieID(rootA), dba)
|
||||||
|
|
||||||
|
|
@ -302,7 +302,7 @@ func TestUnionIterator(t *testing.T) {
|
||||||
for _, val := range testdata2 {
|
for _, val := range testdata2 {
|
||||||
trieb.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
|
||||||
trieb, _ = New(TrieID(rootB), dbb)
|
trieb, _ = New(TrieID(rootB), dbb)
|
||||||
|
|
||||||
|
|
@ -364,7 +364,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) {
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
tr.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
if !memonly {
|
if !memonly {
|
||||||
tdb.Commit(root, false)
|
tdb.Commit(root, false)
|
||||||
|
|
@ -474,7 +474,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
ctr.MustUpdate([]byte(val.k), []byte(val.v))
|
ctr.MustUpdate([]byte(val.k), []byte(val.v))
|
||||||
}
|
}
|
||||||
root, nodes, _ := ctr.Commit(false)
|
root, nodes, _, _ := ctr.Commit(false)
|
||||||
for path, n := range nodes.Nodes {
|
for path, n := range nodes.Nodes {
|
||||||
if n.Hash == barNodeHash {
|
if n.Hash == barNodeHash {
|
||||||
barNodePath = []byte(path)
|
barNodePath = []byte(path)
|
||||||
|
|
@ -554,7 +554,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) {
|
||||||
all[val.k] = val.v
|
all[val.k] = val.v
|
||||||
trie.MustUpdate([]byte(val.k), []byte(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.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
triedb.Commit(root, false)
|
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.
|
// 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
|
// 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 *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
|
// Write all the pre-images to the actual disk database
|
||||||
if len(t.getSecKeyCache()) > 0 {
|
if len(t.getSecKeyCache()) > 0 {
|
||||||
if t.preimages != nil {
|
if t.preimages != nil {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) {
|
||||||
trie.MustUpdate(key, val)
|
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 {
|
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||||
panic(fmt.Errorf("failed to commit db %v", err))
|
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)
|
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 {
|
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||||
panic(fmt.Errorf("failed to commit db %v", err))
|
panic(fmt.Errorf("failed to commit db %v", err))
|
||||||
}
|
}
|
||||||
|
|
@ -759,7 +759,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
|
||||||
srcTrie.MustUpdate(key, val)
|
srcTrie.MustUpdate(key, val)
|
||||||
diff[string(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 {
|
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -784,7 +784,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
|
||||||
srcTrie.MustUpdate([]byte(k), val)
|
srcTrie.MustUpdate([]byte(k), val)
|
||||||
reverted[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 {
|
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -842,7 +842,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
||||||
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA)
|
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA)
|
||||||
writeFn([]byte{0x13, 0x44}, 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 {
|
if err := srcTrieDB.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -861,7 +861,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
||||||
deleteFn([]byte{0x13, 0x44}, srcTrie, stateB)
|
deleteFn([]byte{0x13, 0x44}, srcTrie, stateB)
|
||||||
writeFn([]byte{0x01, 0x24}, nil, 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 {
|
if err := srcTrieDB.Update(rootB, rootA, 0, trienode.NewWithNodeSet(nodesB), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -879,7 +879,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
|
||||||
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC)
|
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC)
|
||||||
writeFn([]byte{0x13, 0x44}, 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 {
|
if err := srcTrieDB.Update(rootC, rootB, 0, trienode.NewWithNodeSet(nodesC), nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@
|
||||||
|
|
||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// tracer tracks the changes of trie nodes. During the trie operations,
|
// tracer tracks the changes of trie nodes. During the trie operations,
|
||||||
// some nodes can be deleted from the trie, while these deleted nodes
|
// 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
|
// won't be captured by trie.Hasher or trie.Committer. Thus, these deleted
|
||||||
|
|
@ -33,16 +29,11 @@ import (
|
||||||
// This tool can track all of them no matter the node is embedded in its
|
// This tool can track all of them no matter the node is embedded in its
|
||||||
// parent or not, but valueNode is never tracked.
|
// 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
|
// Note tracer is not thread-safe, callers should be responsible for handling
|
||||||
// the concurrency issues by themselves.
|
// the concurrency issues by themselves.
|
||||||
type tracer struct {
|
type tracer struct {
|
||||||
inserts map[string]struct{}
|
inserts map[string]struct{}
|
||||||
deletes map[string]struct{}
|
deletes map[string]struct{}
|
||||||
accessList map[string][]byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTracer initializes the tracer for capturing trie changes.
|
// newTracer initializes the tracer for capturing trie changes.
|
||||||
|
|
@ -50,17 +41,9 @@ func newTracer() *tracer {
|
||||||
return &tracer{
|
return &tracer{
|
||||||
inserts: make(map[string]struct{}),
|
inserts: make(map[string]struct{}),
|
||||||
deletes: make(map[string]struct{}),
|
deletes: make(map[string]struct{}),
|
||||||
accessList: make(map[string][]byte),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// onInsert tracks the newly inserted trie node. If it's already
|
||||||
// in the deletion set (resurrected node), then just wipe it from
|
// in the deletion set (resurrected node), then just wipe it from
|
||||||
// the deletion set as it's "untouched".
|
// the deletion set as it's "untouched".
|
||||||
|
|
@ -83,19 +66,11 @@ func (t *tracer) onDelete(path []byte) {
|
||||||
t.deletes[string(path)] = struct{}{}
|
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.
|
// copy returns a deep copied tracer instance.
|
||||||
func (t *tracer) copy() *tracer {
|
func (t *tracer) copy() *tracer {
|
||||||
var (
|
var (
|
||||||
inserts = make(map[string]struct{})
|
inserts = make(map[string]struct{})
|
||||||
deletes = make(map[string]struct{})
|
deletes = make(map[string]struct{})
|
||||||
accessList = make(map[string][]byte)
|
|
||||||
)
|
)
|
||||||
for path := range t.inserts {
|
for path := range t.inserts {
|
||||||
inserts[path] = struct{}{}
|
inserts[path] = struct{}{}
|
||||||
|
|
@ -103,27 +78,16 @@ func (t *tracer) copy() *tracer {
|
||||||
for path := range t.deletes {
|
for path := range t.deletes {
|
||||||
deletes[path] = struct{}{}
|
deletes[path] = struct{}{}
|
||||||
}
|
}
|
||||||
for path, blob := range t.accessList {
|
|
||||||
accessList[path] = common.CopyBytes(blob)
|
|
||||||
}
|
|
||||||
return &tracer{
|
return &tracer{
|
||||||
inserts: inserts,
|
inserts: inserts,
|
||||||
deletes: deletes,
|
deletes: deletes,
|
||||||
accessList: accessList,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletedNodes returns a list of node paths which are deleted from the trie.
|
// deleteList returns a list of node paths which are marked as deleted.
|
||||||
func (t *tracer) deletedNodes() []string {
|
func (t *tracer) deleteList() []string {
|
||||||
var paths []string
|
var paths []string
|
||||||
for path := range t.deletes {
|
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)
|
paths = append(paths, path)
|
||||||
}
|
}
|
||||||
return paths
|
return paths
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
|
||||||
}
|
}
|
||||||
insertSet := copySet(trie.tracer.inserts) // copy before commit
|
insertSet := copySet(trie.tracer.inserts) // copy before commit
|
||||||
deleteSet := copySet(trie.tracer.deletes) // 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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
seen := setKeys(iterNodes(db, root))
|
seen := setKeys(iterNodes(db, root))
|
||||||
|
|
@ -136,7 +136,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
trie.MustUpdate([]byte(val.k), []byte(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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -151,7 +151,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
trie.MustUpdate([]byte(val.k), randBytes(32))
|
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)
|
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -169,7 +169,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
||||||
keys = append(keys, string(key))
|
keys = append(keys, string(key))
|
||||||
trie.MustUpdate(key, randBytes(32))
|
trie.MustUpdate(key, randBytes(32))
|
||||||
}
|
}
|
||||||
root, nodes, _ = trie.Commit(false)
|
root, nodes, _, _ = trie.Commit(false)
|
||||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -184,7 +184,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
trie.MustUpdate([]byte(key), nil)
|
trie.MustUpdate([]byte(key), nil)
|
||||||
}
|
}
|
||||||
root, nodes, _ = trie.Commit(false)
|
root, nodes, _, _ = trie.Commit(false)
|
||||||
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -199,7 +199,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
trie.MustUpdate([]byte(val.k), nil)
|
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)
|
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
@ -218,7 +218,7 @@ func TestAccessListLeak(t *testing.T) {
|
||||||
for _, val := range standard {
|
for _, val := range standard {
|
||||||
trie.MustUpdate([]byte(val.k), []byte(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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
|
|
@ -248,9 +248,9 @@ func TestAccessListLeak(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
n1 := len(trie.tracer.accessList)
|
n1 := trie.witness.Len()
|
||||||
c.op(trie)
|
c.op(trie)
|
||||||
n2 := len(trie.tracer.accessList)
|
n2 := trie.witness.Len()
|
||||||
|
|
||||||
if n1 != n2 {
|
if n1 != n2 {
|
||||||
t.Fatalf("AccessList is leaked, prev %d after %d", 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 {
|
for _, val := range tiny {
|
||||||
trie.MustUpdate([]byte(val.k), randBytes(32))
|
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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(set), nil)
|
||||||
|
|
||||||
parent := root
|
parent := root
|
||||||
|
|
@ -277,7 +277,7 @@ func TestTinyTree(t *testing.T) {
|
||||||
for _, val := range tiny {
|
for _, val := range tiny {
|
||||||
trie.MustUpdate([]byte(val.k), []byte(val.v))
|
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)
|
db.Update(root, parent, 0, trienode.NewWithNodeSet(set), nil)
|
||||||
|
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
|
|
|
||||||
42
trie/trie.go
42
trie/trie.go
|
|
@ -54,6 +54,7 @@ type Trie struct {
|
||||||
// tracer is the tool to track the trie changes.
|
// tracer is the tool to track the trie changes.
|
||||||
// It will be reset after each commit operation.
|
// 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.
|
// newFlag returns the cache flag value for a newly created node.
|
||||||
|
|
@ -70,6 +71,7 @@ func (t *Trie) Copy() *Trie {
|
||||||
unhashed: t.unhashed,
|
unhashed: t.unhashed,
|
||||||
reader: t.reader,
|
reader: t.reader,
|
||||||
tracer: t.tracer.copy(),
|
tracer: t.tracer.copy(),
|
||||||
|
witness: t.witness.Copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +90,7 @@ func New(id *ID, db *Database) (*Trie, error) {
|
||||||
owner: id.Owner,
|
owner: id.Owner,
|
||||||
reader: reader,
|
reader: reader,
|
||||||
tracer: newTracer(),
|
tracer: newTracer(),
|
||||||
|
witness: trienode.NewWitness(id.Owner),
|
||||||
}
|
}
|
||||||
if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash {
|
if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash {
|
||||||
rootnode, err := trie.resolveAndTrack(id.Root[:], nil)
|
rootnode, err := trie.resolveAndTrack(id.Root[:], nil)
|
||||||
|
|
@ -589,7 +592,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.tracer.onRead(prefix, blob)
|
t.witness.Add(string(prefix), blob)
|
||||||
return mustDecodeNode(n, blob), nil
|
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).
|
// 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
|
// 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, *trienode.Witness, error) {
|
||||||
defer t.tracer.reset()
|
// Reset the trie internal states at the end.
|
||||||
defer func() {
|
defer func() {
|
||||||
|
t.tracer = newTracer()
|
||||||
|
t.witness = trienode.NewWitness(t.owner)
|
||||||
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:
|
||||||
|
|
@ -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
|
// (b) The trie was non-empty and all nodes are dropped => return
|
||||||
// the node set includes all deleted nodes
|
// the node set includes all deleted nodes
|
||||||
if t.root == nil {
|
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 {
|
if len(paths) == 0 {
|
||||||
return types.EmptyRootHash, nil, nil // case (a)
|
return types.EmptyRootHash, nil, nil, nil // case (a)
|
||||||
}
|
}
|
||||||
nodes := trienode.NewNodeSet(t.owner)
|
nodes := trienode.NewNodeSet(t.owner)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
nodes.AddNode([]byte(path), trienode.NewDeleted())
|
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
|
// Derive the hash for all dirty nodes first. We hold the assumption
|
||||||
// in the following procedure that all nodes are hashed.
|
// 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
|
// Replace the root node with the origin hash in order to
|
||||||
// ensure all resolved nodes are dropped after the commit.
|
// ensure all resolved nodes are dropped after the commit.
|
||||||
t.root = hashedNode
|
t.root = hashedNode
|
||||||
return rootHash, nil, nil
|
return rootHash, nil, t.witness, nil
|
||||||
}
|
}
|
||||||
nodes := trienode.NewNodeSet(t.owner)
|
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
|
// hashRoot calculates the root hash of the given trie
|
||||||
|
|
@ -667,6 +684,7 @@ func (t *Trie) Reset() {
|
||||||
t.root = nil
|
t.root = nil
|
||||||
t.owner = common.Hash{}
|
t.owner = common.Hash{}
|
||||||
t.unhashed = 0
|
t.unhashed = 0
|
||||||
t.tracer.reset()
|
t.tracer = newTracer()
|
||||||
|
t.witness = trienode.NewWitness(common.Hash{})
|
||||||
t.committed = false
|
t.committed = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) {
|
||||||
trie := NewEmpty(triedb)
|
trie := NewEmpty(triedb)
|
||||||
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
|
||||||
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
if !memonly {
|
if !memonly {
|
||||||
|
|
@ -182,7 +182,7 @@ func TestInsert(t *testing.T) {
|
||||||
updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||||
|
|
||||||
exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
|
exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
|
||||||
root, _, _ = trie.Commit(false)
|
root, _, _, _ = trie.Commit(false)
|
||||||
if root != exp {
|
if root != exp {
|
||||||
t.Errorf("case 2: exp %x got %x", exp, root)
|
t.Errorf("case 2: exp %x got %x", exp, root)
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +207,7 @@ func TestGet(t *testing.T) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
trie, _ = New(TrieID(root), db)
|
trie, _ = New(TrieID(root), db)
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +279,7 @@ func TestReplication(t *testing.T) {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
updateString(trie, val.k, val.v)
|
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)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
|
|
||||||
// create a new trie on top of the database and check that lookups work.
|
// 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)
|
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 {
|
if hash != root {
|
||||||
t.Errorf("root failure. expected %x got %x", root, hash)
|
t.Errorf("root failure. expected %x got %x", root, hash)
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +506,7 @@ func runRandTest(rt randTest) bool {
|
||||||
case opHash:
|
case opHash:
|
||||||
tr.Hash()
|
tr.Hash()
|
||||||
case opCommit:
|
case opCommit:
|
||||||
root, nodes, _ := tr.Commit(true)
|
root, nodes, _, _ := tr.Commit(true)
|
||||||
if nodes != nil {
|
if nodes != nil {
|
||||||
triedb.Update(root, origin, 0, trienode.NewWithNodeSet(nodes), nil)
|
triedb.Update(root, origin, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
}
|
}
|
||||||
|
|
@ -743,7 +743,7 @@ func TestCommitAfterHash(t *testing.T) {
|
||||||
if exp != root {
|
if exp != root {
|
||||||
t.Errorf("got %x, exp %x", root, exp)
|
t.Errorf("got %x, exp %x", root, exp)
|
||||||
}
|
}
|
||||||
root, _, _ = trie.Commit(false)
|
root, _, _, _ = trie.Commit(false)
|
||||||
if exp != root {
|
if exp != root {
|
||||||
t.Errorf("got %x, exp %x", root, exp)
|
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])
|
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
|
||||||
}
|
}
|
||||||
// Flush trie -> database
|
// Flush trie -> database
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
// Flush memdb -> disk (sponge)
|
// Flush memdb -> disk (sponge)
|
||||||
db.Commit(root, false)
|
db.Commit(root, false)
|
||||||
|
|
@ -893,7 +893,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
|
||||||
trie.MustUpdate(key, val)
|
trie.MustUpdate(key, val)
|
||||||
}
|
}
|
||||||
// Flush trie -> database
|
// Flush trie -> database
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
// Flush memdb -> disk (sponge)
|
// Flush memdb -> disk (sponge)
|
||||||
db.Commit(root, false)
|
db.Commit(root, false)
|
||||||
|
|
@ -932,7 +932,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
|
||||||
stTrie.Update(key, val)
|
stTrie.Update(key, val)
|
||||||
}
|
}
|
||||||
// Flush trie -> database
|
// Flush trie -> database
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
// Flush memdb -> disk (sponge)
|
// Flush memdb -> disk (sponge)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
db.Commit(root, false)
|
db.Commit(root, false)
|
||||||
|
|
@ -980,7 +980,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
|
||||||
trie.Update(key, []byte{0x1})
|
trie.Update(key, []byte{0x1})
|
||||||
stTrie.Update(key, []byte{0x1})
|
stTrie.Update(key, []byte{0x1})
|
||||||
// Flush trie -> database
|
// Flush trie -> database
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
// Flush memdb -> disk (sponge)
|
// Flush memdb -> disk (sponge)
|
||||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
db.Commit(root, false)
|
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])
|
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
|
||||||
}
|
}
|
||||||
h := trie.Hash()
|
h := trie.Hash()
|
||||||
root, nodes, _ := trie.Commit(false)
|
root, nodes, _, _ := trie.Commit(false)
|
||||||
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
triedb.Dereference(h)
|
triedb.Dereference(h)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm
|
||||||
h.Update(key.Bytes(), val)
|
h.Update(key.Bytes(), val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, nodes, _ := h.Commit(false)
|
root, nodes, _, _ := h.Commit(false)
|
||||||
return root, nodes
|
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
|
// Commit computes the new hash of the states and returns the set with all
|
||||||
// state changes.
|
// 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 (
|
var (
|
||||||
nodes = make(map[common.Hash][]byte)
|
nodes = make(map[common.Hash][]byte)
|
||||||
set = trienode.NewNodeSet(h.owner)
|
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 {
|
if root == types.EmptyRootHash && h.root != types.EmptyRootHash {
|
||||||
set.AddNode(nil, trienode.NewDeleted())
|
set.AddNode(nil, trienode.NewDeleted())
|
||||||
}
|
}
|
||||||
return root, set, nil
|
return root, set, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash performs the hash computation upon the provided states.
|
// 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
|
// Commit the trie and returns a set of dirty nodes generated along with
|
||||||
// the new root hash.
|
// 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.
|
// 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)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +184,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, result, err := st.Commit(false)
|
root, result, _, err := st.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -238,7 +238,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, result, err := st.Commit(false)
|
root, result, _, err := st.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue