From 149419cf09eb4e8016c96af40f81a67b9a289ebf Mon Sep 17 00:00:00 2001 From: Ho Date: Mon, 22 May 2023 15:24:49 +0800 Subject: [PATCH] fix(trace): deletion proof missed path terminated by empty node (#330) * fix deletion proof issue on empty node * refine for better implement and fix unittest * Update version.go --------- Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- params/version.go | 2 +- trie/zk_trie_proof_test.go | 5 +++-- trie/zktrie_deletionproof.go | 13 ++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index b745a58bdc..ce0873da84 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 3 // Major version component of the current release VersionMinor = 2 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release + VersionPatch = 3 // Patch version component of the current release VersionMeta = "alpha" // Version metadata to append to the version string ) diff --git a/trie/zk_trie_proof_test.go b/trie/zk_trie_proof_test.go index 0109e9be85..9246a7a992 100644 --- a/trie/zk_trie_proof_test.go +++ b/trie/zk_trie_proof_test.go @@ -244,11 +244,12 @@ func TestProofWithDeletion(t *testing.T) { // notice the sibling of key `k*32`` is just the leaf of key `m*32` assert.Equal(t, siblings[0][l-33:l-1], nd) - // no effect + // Marking a key that is currently not hit (but terminated by an empty node) + // also causes it to be added to the deletion proof proofTracer.MarkDeletion(s_key2.Bytes()) siblings, err = proofTracer.GetDeletionProofs() assert.NoError(t, err) - assert.Equal(t, 1, len(siblings)) + assert.Equal(t, 2, len(siblings)) key3 := bytes.Repeat([]byte("x"), 32) err = mt.UpdateWord( diff --git a/trie/zktrie_deletionproof.go b/trie/zktrie_deletionproof.go index ebb8419e7a..8547c1eda4 100644 --- a/trie/zktrie_deletionproof.go +++ b/trie/zktrie_deletionproof.go @@ -28,6 +28,7 @@ type ProofTracer struct { *ZkTrie deletionTracer map[zkt.Hash]struct{} rawPaths map[string][]*zktrie.Node + emptyTermPaths map[string][]*zktrie.Node } // NewProofTracer create a proof tracer object @@ -37,6 +38,7 @@ func (t *ZkTrie) NewProofTracer() *ProofTracer { // always consider 0 is "deleted" deletionTracer: map[zkt.Hash]struct{}{zkt.HashZero: {}}, rawPaths: make(map[string][]*zktrie.Node), + emptyTermPaths: make(map[string][]*zktrie.Node), } } @@ -112,9 +114,13 @@ func (t *ProofTracer) GetDeletionProofs() ([][]byte, error) { // MarkDeletion mark a key has been involved into deletion func (t *ProofTracer) MarkDeletion(key []byte) { - if path, existed := t.rawPaths[string(key)]; existed { + if path, existed := t.emptyTermPaths[string(key)]; existed { + // copy empty node terminated path for final scanning + t.rawPaths[string(key)] = path + } else if path, existed = t.rawPaths[string(key)]; existed { // sanity check leafNode := path[len(path)-1] + if leafNode.Type != zktrie.NodeTypeLeaf { panic("all path recorded in proofTrace should be ended with leafNode") } @@ -143,6 +149,11 @@ func (t *ProofTracer) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWr } } else if n.Type == zktrie.NodeTypeParent { mptPath = append(mptPath, n) + } else if n.Type == zktrie.NodeTypeEmpty { + // empty node is considered as "unhit" but it should be also being added + // into a temporary slot for possibly being marked as deletion later + mptPath = append(mptPath, n) + t.emptyTermPaths[string(key)] = mptPath } return proofDb.Put(nodeHash[:], n.Value())