From 6687e6b4d60b4b87636a54a814e92bca8f6c2295 Mon Sep 17 00:00:00 2001 From: Artem Tsebrovskiy Date: Tue, 15 Mar 2022 20:01:51 +0300 Subject: [PATCH] during computeCommitment exits with RootHash when there are no updates to apply (#366) --- aggregator/aggregator.go | 6 +++ commitment/hex_patricia_hashed.go | 3 +- commitment/hex_patricia_hashed_test.go | 66 +++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/aggregator/aggregator.go b/aggregator/aggregator.go index a3a4d659c..97465cc2e 100644 --- a/aggregator/aggregator.go +++ b/aggregator/aggregator.go @@ -2326,6 +2326,11 @@ func (w *Writer) computeCommitment(trace bool) ([]byte, error) { j++ return true }) + + if len(updates) == 0 { + return w.a.hph.RootHash() + } + w.a.hph.Reset() w.a.hph.ResetFns(w.branchFn, w.accountFn, w.storageFn, w.lockFn, w.unlockFn) w.a.hph.SetTrace(trace) @@ -2376,6 +2381,7 @@ func (w *Writer) computeCommitment(trace bool) ([]byte, error) { } } } + var rootHash []byte if rootHash, err = w.a.hph.RootHash(); err != nil { return nil, err diff --git a/commitment/hex_patricia_hashed.go b/commitment/hex_patricia_hashed.go index 1d3d7da7b..d124e7977 100644 --- a/commitment/hex_patricia_hashed.go +++ b/commitment/hex_patricia_hashed.go @@ -27,9 +27,10 @@ import ( "strings" "github.com/holiman/uint256" + "golang.org/x/crypto/sha3" + "github.com/ledgerwatch/erigon-lib/common/length" "github.com/ledgerwatch/erigon-lib/rlp" - "golang.org/x/crypto/sha3" ) // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports diff --git a/commitment/hex_patricia_hashed_test.go b/commitment/hex_patricia_hashed_test.go index 0e5e6dbb7..b42816534 100644 --- a/commitment/hex_patricia_hashed_test.go +++ b/commitment/hex_patricia_hashed_test.go @@ -17,6 +17,7 @@ package commitment import ( + "bytes" "encoding/binary" "encoding/hex" "fmt" @@ -24,8 +25,9 @@ import ( "testing" "github.com/holiman/uint256" - "github.com/ledgerwatch/erigon-lib/common" "golang.org/x/crypto/sha3" + + "github.com/ledgerwatch/erigon-lib/common" ) // In memory commitment and state to use with the tests @@ -481,3 +483,65 @@ func TestEmptyState(t *testing.T) { fmt.Printf("%x => %s\n", CompactToHex([]byte(key)), branchToString(branchNodeUpdate)) } } + +func TestEmptyUpdateState(t *testing.T) { + ms := NewMockState(t) + hph := NewHexPatriciaHashed(1, ms.branchFn, ms.accountFn, ms.storageFn, ms.lockFn, ms.unlockFn) + hph.SetTrace(false) + plainKeys, hashedKeys, updates := NewUpdateBuilder(). + Balance("00", 4). + Balance("01", 5). + Build() + if err := ms.applyPlainUpdates(plainKeys, updates); err != nil { + t.Fatal(err) + } + branchNodeUpdates, err := hph.ProcessUpdates(plainKeys, hashedKeys, updates) + if err != nil { + t.Fatal(err) + } + + rh, err := hph.RootHash() + if err != nil { + t.Fatal(err) + } + + fmt.Printf("root %v\n", hex.EncodeToString(rh)) + + ms.applyBranchNodeUpdates(branchNodeUpdates) + + fmt.Println("1. Updates applied") + var keys []string + for key := range branchNodeUpdates { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + branchNodeUpdate := branchNodeUpdates[key] + fmt.Printf("%x => %s\n", CompactToHex([]byte(key)), branchToString(branchNodeUpdate)) + } + + // generate empty updates and do NOT reset tree + //hph.Reset() + hph.SetTrace(true) + plainKeys, hashedKeys, updates = NewUpdateBuilder().Build() + if err := ms.applyPlainUpdates(plainKeys, updates); err != nil { + t.Fatal(err) + } + + branchNodeUpdates, err = hph.ProcessUpdates(plainKeys, hashedKeys, updates) + if err != nil { + t.Fatal(err) + } + ms.applyBranchNodeUpdates(branchNodeUpdates) + fmt.Println("2. empty updates applied without state reset") + + firstRH := rh + rh, err = hph.RootHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(firstRH, rh) { + t.Fatalf("expected root hash [%v] after update but got [%v]", hex.EncodeToString(firstRH), hex.EncodeToString(rh)) + } + fmt.Printf("root %v\n", hex.EncodeToString(rh)) +}