From ed62ad580f0f7806896315723e71b2bfca51bd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Mon, 11 Jan 2021 10:26:59 +0100 Subject: [PATCH 1/7] Add Delete method to SparseMerkleTree --- smt.go | 5 +++++ smt_test.go | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/smt.go b/smt.go index 78e549e..d3331f4 100644 --- a/smt.go +++ b/smt.go @@ -132,6 +132,11 @@ func (smt *SparseMerkleTree) Update(key []byte, value []byte) ([]byte, error) { return newRoot, err } +// Delete deletes a value from tree. It returns a new root of the tree. +func (smt *SparseMerkleTree) Delete(key []byte) ([]byte, error) { + return smt.Update(key, defaultValue) +} + // UpdateForRoot sets a new value for a key in the tree at a specific root, and returns the new root. func (smt *SparseMerkleTree) UpdateForRoot(key []byte, value []byte, root []byte) ([]byte, error) { path := smt.th.path(key) diff --git a/smt_test.go b/smt_test.go index 4533ec7..d991392 100644 --- a/smt_test.go +++ b/smt_test.go @@ -184,7 +184,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { t.Errorf("returned error when updating empty key: %v", err) } root1 := smt.Root() - _, err = smt.Update([]byte("testKey"), defaultValue) + _, err = smt.Delete([]byte("testKey")) if err != nil { t.Errorf("returned error when deleting key: %v", err) } @@ -215,7 +215,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if err != nil { t.Errorf("returned error when updating empty second key: %v", err) } - _, err = smt.Update([]byte("testKey2"), defaultValue) + _, err = smt.Delete([]byte("testKey2")) if err != nil { t.Errorf("returned error when deleting key: %v", err) } @@ -248,7 +248,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if err != nil { t.Errorf("returned error when updating empty second key: %v", err) } - _, err = smt.Update([]byte("foo"), defaultValue) + _, err = smt.Delete([]byte("foo")) if err != nil { t.Errorf("returned error when deleting key: %v", err) } From 3e9fea3cfbe24d25df109d4bf0a75d9155b7b958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Mon, 11 Jan 2021 21:41:01 +0100 Subject: [PATCH 2/7] Add DeleteForRoot method to SparseMerkleTree --- smt.go | 5 +++++ smt_test.go | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/smt.go b/smt.go index d3331f4..15fde44 100644 --- a/smt.go +++ b/smt.go @@ -160,6 +160,11 @@ func (smt *SparseMerkleTree) UpdateForRoot(key []byte, value []byte, root []byte return newRoot, err } +// Delete deletes a value from tree at a specific root. It returns a new root of the tree. +func (smt *SparseMerkleTree) DeleteForRoot(key, root []byte) ([]byte, error) { + return smt.UpdateForRoot(key, defaultValue, root) +} + func (smt *SparseMerkleTree) deleteWithSideNodes(path []byte, sideNodes [][]byte, oldLeafHash []byte, oldLeafData []byte) ([]byte, error) { if bytes.Equal(oldLeafHash, smt.th.placeholder()) { // This key is already empty as it is a placeholder; return an error. diff --git a/smt_test.go b/smt_test.go index d991392..87fed2b 100644 --- a/smt_test.go +++ b/smt_test.go @@ -115,6 +115,19 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { t.Error("did not get correct value when getting non-empty key") } + // Test that it is possible to delete key in an older root. + root, err = smt.DeleteForRoot([]byte("testKey3"), root) + if err != nil { + t.Errorf("unable to delete key: %v", err) + } + value, err = smt.GetForRoot([]byte("testKey3"), root) + if err != nil { + t.Errorf("returned error when getting empty key: %v", err) + } + if !bytes.Equal(defaultValue, value) { + t.Error("did not get correct value when getting empty key") + } + // Test that a tree can be imported from a MapStore. smt2 := ImportSparseMerkleTree(sm, sha256.New(), smt.Root()) value, err = smt2.Get([]byte("testKey")) From 707a22369acfe6fa40887cc8afcc6e69625d1650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Mon, 11 Jan 2021 22:08:10 +0100 Subject: [PATCH 3/7] Add Has and HasForRoot methods to SparseMerkleTree --- smt.go | 14 ++++++++++++++ smt_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/smt.go b/smt.go index 15fde44..5cb9c79 100644 --- a/smt.go +++ b/smt.go @@ -123,6 +123,20 @@ func (smt *SparseMerkleTree) GetForRoot(key []byte, root []byte) ([]byte, error) return value, nil } +// Has returns true if tree cointains given key, false otherwise. +func (smt *SparseMerkleTree) Has(key []byte) (bool, error) { + val, err := smt.Get(key) + // this covers both val == nil and val == defaultValue + return len(val) > 0, err +} + +// HasForRoot returns true if tree cointains given key at a specific root, false otherwise. +func (smt *SparseMerkleTree) HasForRoot(key, root []byte) (bool, error) { + val, err := smt.GetForRoot(key, root) + // this covers both val == nil and val == defaultValue + return len(val) > 0, err +} + // Update sets a new value for a key in the tree, and sets and returns the new root of the tree. func (smt *SparseMerkleTree) Update(key []byte, value []byte) ([]byte, error) { newRoot, err := smt.UpdateForRoot(key, value, smt.Root()) diff --git a/smt_test.go b/smt_test.go index 87fed2b..80fc73f 100644 --- a/smt_test.go +++ b/smt_test.go @@ -13,6 +13,7 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { sm := NewSimpleMap() smt := NewSparseMerkleTree(sm, sha256.New()) var value []byte + var has bool var err error // Test getting an empty key. @@ -23,6 +24,13 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { if !bytes.Equal(defaultValue, value) { t.Error("did not get default value when getting empty key") } + has, err = smt.Has([]byte("testKey")) + if err != nil { + t.Errorf("returned error when checking presence of empty key: %v", err) + } + if has { + t.Error("did not get 'false' when checking presence of empty key") + } // Test updating the empty key. _, err = smt.Update([]byte("testKey"), []byte("testValue")) @@ -36,6 +44,13 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { if !bytes.Equal([]byte("testValue"), value) { t.Error("did not get correct value when getting non-empty key") } + has, err = smt.Has([]byte("testKey")) + if err != nil { + t.Errorf("returned error when checking presence of non-empty key: %v", err) + } + if !has { + t.Error("did not get 'true' when checking presence of non-empty key") + } // Test updating the non-empty key. _, err = smt.Update([]byte("testKey"), []byte("testValue2")) @@ -114,6 +129,13 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { if !bytes.Equal([]byte("testValue2"), value) { t.Error("did not get correct value when getting non-empty key") } + has, err = smt.HasForRoot([]byte("testKey"), root) + if err != nil { + t.Errorf("returned error when checking presence of non-empty key: %v", err) + } + if !has { + t.Error("did not get 'false' when checking presence of non-empty key") + } // Test that it is possible to delete key in an older root. root, err = smt.DeleteForRoot([]byte("testKey3"), root) @@ -127,6 +149,13 @@ func TestSparseMerkleTreeUpdateBasic(t *testing.T) { if !bytes.Equal(defaultValue, value) { t.Error("did not get correct value when getting empty key") } + has, err = smt.HasForRoot([]byte("testKey3"), root) + if err != nil { + t.Errorf("returned error when checking presence of empty key: %v", err) + } + if has { + t.Error("did not get 'false' when checking presence of empty key") + } // Test that a tree can be imported from a MapStore. smt2 := ImportSparseMerkleTree(sm, sha256.New(), smt.Root()) From 1a264c8cec896cc05bffb348d8c1309aaa79a082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Tue, 12 Jan 2021 13:06:25 +0100 Subject: [PATCH 4/7] Revert to Update with default value in tests As commented by Mustafa, it's important to show the behaviour of Update when empty value is set. --- smt_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/smt_test.go b/smt_test.go index 80fc73f..ff33336 100644 --- a/smt_test.go +++ b/smt_test.go @@ -226,7 +226,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { t.Errorf("returned error when updating empty key: %v", err) } root1 := smt.Root() - _, err = smt.Delete([]byte("testKey")) + _, err = smt.Update([]byte("testKey"), defaultValue) if err != nil { t.Errorf("returned error when deleting key: %v", err) } @@ -257,7 +257,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if err != nil { t.Errorf("returned error when updating empty second key: %v", err) } - _, err = smt.Delete([]byte("testKey2")) + _, err = smt.Update([]byte("testKey2"), defaultValue) if err != nil { t.Errorf("returned error when deleting key: %v", err) } @@ -290,7 +290,7 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if err != nil { t.Errorf("returned error when updating empty second key: %v", err) } - _, err = smt.Delete([]byte("foo")) + _, err = smt.Update([]byte("foo"), defaultValue) if err != nil { t.Errorf("returned error when deleting key: %v", err) } From eed82c2a9729bfb9e9a81045d805a7ea87726bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Tue, 12 Jan 2021 22:47:55 +0100 Subject: [PATCH 5/7] More tests of new functions (Has, Delete) --- smt_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/smt_test.go b/smt_test.go index ff33336..1b9509a 100644 --- a/smt_test.go +++ b/smt_test.go @@ -237,6 +237,13 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if !bytes.Equal(defaultValue, value) { t.Error("did not get default value when getting deleted key") } + has, err := smt.Has([]byte("testKey")) + if err != nil { + t.Errorf("returned error when checking existence of deleted key: %v", err) + } + if has { + t.Error("returned 'true' when checking existernce of deleted key") + } _, err = smt.Update([]byte("testKey"), []byte("testValue")) if err != nil { t.Errorf("returned error when updating empty key: %v", err) @@ -311,6 +318,46 @@ func TestSparseMerkleTreeDeleteBasic(t *testing.T) { if !bytes.Equal(root1, smt.Root()) { t.Error("tree root is not as expected after deleting second key") } + + // Testing inserting, deleting a key, and inserting it again, using Delete + _, err = smt.Update([]byte("testKey"), []byte("testValue")) + if err != nil { + t.Errorf("returned error when updating empty key: %v", err) + } + root1 = smt.Root() + _, err = smt.Delete([]byte("testKey")) + if err != nil { + t.Errorf("returned error when deleting key: %v", err) + } + value, err = smt.Get([]byte("testKey")) + if err != nil { + t.Errorf("returned error when getting deleted key: %v", err) + } + if !bytes.Equal(defaultValue, value) { + t.Error("did not get default value when getting deleted key") + } + has, err = smt.Has([]byte("testKey")) + if err != nil { + t.Errorf("returned error when checking existence of deleted key: %v", err) + } + if has { + t.Error("returned 'true' when checking existernce of deleted key") + } + _, err = smt.Update([]byte("testKey"), []byte("testValue")) + if err != nil { + t.Errorf("returned error when updating empty key: %v", err) + } + value, err = smt.Get([]byte("testKey")) + if err != nil { + t.Errorf("returned error when getting non-empty key: %v", err) + } + if !bytes.Equal([]byte("testValue"), value) { + t.Error("did not get correct value when getting non-empty key") + } + if !bytes.Equal(root1, smt.Root()) { + t.Error("tree root is not as expected after re-inserting key after deletion") + } + } // dummyHasher is a dummy hasher for tests, where the digest of keys is equivalent to the preimage. From bbaeac831529a001f4abb53ba0b65a9400922236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Wed, 13 Jan 2021 13:20:37 +0100 Subject: [PATCH 6/7] Compare with defaultValue in Has and HasForRoot --- smt.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/smt.go b/smt.go index 5cb9c79..01a0cb6 100644 --- a/smt.go +++ b/smt.go @@ -126,15 +126,13 @@ func (smt *SparseMerkleTree) GetForRoot(key []byte, root []byte) ([]byte, error) // Has returns true if tree cointains given key, false otherwise. func (smt *SparseMerkleTree) Has(key []byte) (bool, error) { val, err := smt.Get(key) - // this covers both val == nil and val == defaultValue - return len(val) > 0, err + return !bytes.Equal(defaultValue, val), err } // HasForRoot returns true if tree cointains given key at a specific root, false otherwise. func (smt *SparseMerkleTree) HasForRoot(key, root []byte) (bool, error) { val, err := smt.GetForRoot(key, root) - // this covers both val == nil and val == defaultValue - return len(val) > 0, err + return !bytes.Equal(defaultValue, val), err } // Update sets a new value for a key in the tree, and sets and returns the new root of the tree. From 870d9a953fbb9f8d55e10795a767dbeb9ddbd7fb Mon Sep 17 00:00:00 2001 From: Mustafa Al-Bassam Date: Wed, 13 Jan 2021 14:38:04 +0000 Subject: [PATCH 7/7] "a new root" -> "the new root" --- smt.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smt.go b/smt.go index 01a0cb6..6ffec1e 100644 --- a/smt.go +++ b/smt.go @@ -144,7 +144,7 @@ func (smt *SparseMerkleTree) Update(key []byte, value []byte) ([]byte, error) { return newRoot, err } -// Delete deletes a value from tree. It returns a new root of the tree. +// Delete deletes a value from tree. It returns the new root of the tree. func (smt *SparseMerkleTree) Delete(key []byte) ([]byte, error) { return smt.Update(key, defaultValue) } @@ -172,7 +172,7 @@ func (smt *SparseMerkleTree) UpdateForRoot(key []byte, value []byte, root []byte return newRoot, err } -// Delete deletes a value from tree at a specific root. It returns a new root of the tree. +// Delete deletes a value from tree at a specific root. It returns the new root of the tree. func (smt *SparseMerkleTree) DeleteForRoot(key, root []byte) ([]byte, error) { return smt.UpdateForRoot(key, defaultValue, root) }