diff --git a/README.md b/README.md index d3fcac7..e1a42f8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # arbo [![GoDoc](https://godoc.org/github.com/arnaucube/arbo?status.svg)](https://godoc.org/github.com/arnaucube/arbo) [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/arbo)](https://goreportcard.com/report/github.com/arnaucube/arbo) [![Test](https://github.com/arnaucube/arbo/workflows/Test/badge.svg)](https://github.com/arnaucube/arbo/actions?query=workflow%3ATest) +> *arbo*: tree in Esperanto. + MerkleTree implementation in Go. Compatible with the circomlib implementation of the MerkleTree (when using the Poseidon hash function), following the specification from https://docs.iden3.io/publications/pdfs/Merkle-Tree.pdf and diff --git a/addbatch.go b/addbatch.go index d083329..0308bbb 100644 --- a/addbatch.go +++ b/addbatch.go @@ -145,9 +145,10 @@ const ( minLeafsThreshold = 100 // nolint:gomnd // TMP WIP this will be autocalculated ) -// AddBatchOpt is the WIP implementation of the AddBatch method in a more -// optimized approach. -func (t *Tree) AddBatchOpt(keys, values [][]byte) ([]int, error) { +// AddBatch adds a batch of key-values to the Tree. Returns an array containing +// the indexes of the keys failed to add. +func (t *Tree) AddBatch(keys, values [][]byte) ([]int, error) { + // TODO: support vaules=nil t.updateAccessTime() t.Lock() defer t.Unlock() @@ -678,7 +679,7 @@ func (t *Tree) getLeafs(root []byte) ([][]byte, [][]byte, error) { if v[0] != PrefixValueLeaf { return } - leafK, leafV := readLeafValue(v) + leafK, leafV := ReadLeafValue(v) ks = append(ks, leafK) vs = append(vs, leafV) }) diff --git a/addbatch_test.go b/addbatch_test.go index fdfb327..d5d041a 100644 --- a/addbatch_test.go +++ b/addbatch_test.go @@ -75,7 +75,7 @@ func TestAddBatchCaseA(t *testing.T) { values = append(values, v) } start = time.Now() - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) time2 := time.Since(start) debugTime("CASE A, AddBatch", time1, time2) @@ -113,7 +113,7 @@ func TestAddBatchCaseANotPowerOf2(t *testing.T) { keys = append(keys, k) values = append(values, v) } - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) c.Check(len(indexes), qt.Equals, 0) @@ -148,7 +148,7 @@ func TestAddBatchCaseB(t *testing.T) { values = append(values, v) } start = time.Now() - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) time2 := time.Since(start) debugTime("CASE B, AddBatch", time1, time2) @@ -182,7 +182,7 @@ func TestAddBatchCaseBRepeatedLeafs(t *testing.T) { keys = append(keys, k) values = append(values, v) } - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) c.Check(len(indexes), qt.Equals, initialNLeafs) @@ -368,7 +368,7 @@ func TestAddBatchCaseC(t *testing.T) { values = append(values, v) } start = time.Now() - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) time2 := time.Since(start) debugTime("CASE C, AddBatch", time1, time2) @@ -405,7 +405,7 @@ func TestAddBatchCaseD(t *testing.T) { values = append(values, v) } start = time.Now() - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) time2 := time.Since(start) debugTime("CASE D, AddBatch", time1, time2) @@ -462,7 +462,7 @@ func TestAddBatchCaseE(t *testing.T) { values = append(values, v) } start = time.Now() - indexes, err := tree2.AddBatchOpt(keys, values) + indexes, err := tree2.AddBatch(keys, values) c.Assert(err, qt.IsNil) time2 := time.Since(start) debugTime("CASE E, AddBatch", time1, time2) diff --git a/go.mod b/go.mod index 0dd5583..82a6d17 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ module github.com/arnaucube/arbo -go 1.14 +go 1.16 require ( github.com/frankban/quicktest v1.11.3 github.com/iden3/go-iden3-crypto v0.0.6-0.20210308142348-8f85683b2cef github.com/iden3/go-merkletree v0.0.0-20210308143313-8b63ca866189 + golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670 ) diff --git a/go.sum b/go.sum index 850429a..3201b00 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= @@ -226,6 +227,7 @@ github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTw github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -259,6 +261,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= @@ -284,6 +287,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670 h1:gzMM0EjIYiRmJI3+jBdFuoynZlpxa2JQZsolKu09BXo= +golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= @@ -308,6 +313,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -331,8 +337,12 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -379,6 +389,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/hash.go b/hash.go index c1ee64b..c17edb7 100644 --- a/hash.go +++ b/hash.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/iden3/go-iden3-crypto/poseidon" + "golang.org/x/crypto/blake2b" ) var ( @@ -13,6 +14,8 @@ var ( // TypeHashPoseidon represents the label for the HashFunction of // Poseidon TypeHashPoseidon = []byte("poseidon") + // TypeHashBlake2b represents the label for the HashFunction of Blake2b + TypeHashBlake2b = []byte("blake2b") // HashFunctionSha256 contains the HashSha256 struct which implements // the HashFunction interface @@ -20,6 +23,9 @@ var ( // HashFunctionPoseidon contains the HashPoseidon struct which implements // the HashFunction interface HashFunctionPoseidon HashPoseidon + // HashFunctionBlake2b contains the HashBlake2b struct which implements + // the HashFunction interface + HashFunctionBlake2b HashBlake2b ) // Once Generics are at Go, this will be updated (August 2021 @@ -85,3 +91,30 @@ func (f HashPoseidon) Hash(b ...[]byte) ([]byte, error) { hB := BigIntToBytes(h) return hB, nil } + +// HashBlake2b implements the HashFunction interface for the Blake2b hash +type HashBlake2b struct{} + +// Type returns the type of HashFunction for the HashBlake2b +func (f HashBlake2b) Type() []byte { + return TypeHashBlake2b +} + +// Len returns the length of the Hash output +func (f HashBlake2b) Len() int { + return 32 //nolint:gomnd +} + +// Hash implements the hash method for the HashFunction HashBlake2b +func (f HashBlake2b) Hash(b ...[]byte) ([]byte, error) { + hasher, err := blake2b.New256(nil) + if err != nil { + return nil, err + } + for i := 0; i < len(b); i++ { + if _, err = hasher.Write(b[i]); err != nil { + return nil, err + } + } + return hasher.Sum(nil), nil +} diff --git a/hash_test.go b/hash_test.go index 97e550d..65ac535 100644 --- a/hash_test.go +++ b/hash_test.go @@ -38,3 +38,17 @@ func TestHashPoseidon(t *testing.T) { qt.Equals, "7853200120776062878684798364095072458815029376092732009249414926327459813530") } + +func TestHashBlake2b(t *testing.T) { + // Blake2b hash + hashFunc := &HashBlake2b{} + b := []byte("test") + h, err := hashFunc.Hash(b) + if err != nil { + t.Fatal(err) + } + c := qt.New(t) + c.Assert(hex.EncodeToString(h), + qt.Equals, + "928b20366943e2afd11ebc0eae2e53a93bf177a4fcf35bcc64d503704e65e202") +} diff --git a/tree.go b/tree.go index 23bb340..7a17b76 100644 --- a/tree.go +++ b/tree.go @@ -52,7 +52,7 @@ type Tree struct { sync.RWMutex tx db.Tx db db.Storage - lastAccess int64 // in unix time + lastAccess int64 // in unix time // TODO delete, is a feature of a upper abstraction level maxLevels int root []byte @@ -107,45 +107,9 @@ func (t *Tree) Root() []byte { return t.root } -// AddBatch adds a batch of key-values to the Tree. This method will be -// optimized to do some internal parallelization. Returns an array containing -// the indexes of the keys failed to add. -func (t *Tree) AddBatch(keys, values [][]byte) ([]int, error) { - t.updateAccessTime() - if len(keys) != len(values) { - return nil, fmt.Errorf("len(keys)!=len(values) (%d!=%d)", - len(keys), len(values)) - } - - t.Lock() - defer t.Unlock() - - var err error - t.tx, err = t.db.NewTx() - if err != nil { - return nil, err - } - - var indexes []int - for i := 0; i < len(keys); i++ { - err = t.add(0, keys[i], values[i]) - if err != nil { - indexes = append(indexes, i) - } - } - // store root to db - if err := t.tx.Put(dbKeyRoot, t.root); err != nil { - return indexes, err - } - // update nLeafs - if err = t.incNLeafs(len(keys) - len(indexes)); err != nil { - return indexes, err - } - - if err := t.tx.Commit(); err != nil { - return nil, err - } - return indexes, nil +// HashFunction returns Tree.hashFunction +func (t *Tree) HashFunction() HashFunction { + return t.hashFunction } // Add inserts the key-value into the Tree. If the inputs come from a *big.Int, @@ -248,7 +212,7 @@ func (t *Tree) down(newKey, currKey []byte, siblings [][]byte, if getLeaf { return currKey, currValue, siblings, nil } - oldLeafKey, _ := readLeafValue(currValue) + oldLeafKey, _ := ReadLeafValue(currValue) oldLeafKeyFull := make([]byte, t.hashFunction.Len()) copy(oldLeafKeyFull[:], oldLeafKey) @@ -269,12 +233,12 @@ func (t *Tree) down(newKey, currKey []byte, siblings [][]byte, // collect siblings while going down if path[currLvl] { // right - lChild, rChild := readIntermediateChilds(currValue) + lChild, rChild := ReadIntermediateChilds(currValue) siblings = append(siblings, lChild) return t.down(newKey, rChild, siblings, path, currLvl+1, getLeaf) } // left - lChild, rChild := readIntermediateChilds(currValue) + lChild, rChild := ReadIntermediateChilds(currValue) siblings = append(siblings, rChild) return t.down(newKey, lChild, siblings, path, currLvl+1, getLeaf) default: @@ -347,7 +311,8 @@ func newLeafValue(hashFunc HashFunction, k, v []byte) ([]byte, []byte, error) { return leafKey, leafValue, nil } -func readLeafValue(b []byte) ([]byte, []byte) { +// ReadLeafValue reads from a byte array the leaf key & value +func ReadLeafValue(b []byte) ([]byte, []byte) { if len(b) < PrefixValueLen { return []byte{}, []byte{} } @@ -376,7 +341,8 @@ func newIntermediate(hashFunc HashFunction, l, r []byte) ([]byte, []byte, error) return key, b, nil } -func readIntermediateChilds(b []byte) ([]byte, []byte) { +// ReadIntermediateChilds reads from a byte array the two childs keys +func ReadIntermediateChilds(b []byte) ([]byte, []byte) { if len(b) < PrefixValueLen { return []byte{}, []byte{} } @@ -421,7 +387,7 @@ func (t *Tree) Update(k, v []byte) error { if err != nil { return err } - oldKey, _ := readLeafValue(valueAtBottom) + oldKey, _ := ReadLeafValue(valueAtBottom) if !bytes.Equal(oldKey, k) { return fmt.Errorf("key %s does not exist", hex.EncodeToString(k)) } @@ -456,7 +422,7 @@ func (t *Tree) Update(k, v []byte) error { // GenProof generates a MerkleTree proof for the given key. If the key exists in // the Tree, the proof will be of existence, if the key does not exist in the // tree, the proof will be of non-existence. -func (t *Tree) GenProof(k []byte) ([]byte, error) { +func (t *Tree) GenProof(k []byte) ([]byte, []byte, error) { t.updateAccessTime() keyPath := make([]byte, t.hashFunction.Len()) copy(keyPath[:], k) @@ -466,10 +432,10 @@ func (t *Tree) GenProof(k []byte) ([]byte, error) { var siblings [][]byte _, value, siblings, err := t.down(k, t.root, siblings, path, 0, true) if err != nil { - return nil, err + return nil, nil, err } - leafK, leafV := readLeafValue(value) + leafK, leafV := ReadLeafValue(value) if !bytes.Equal(k, leafK) { fmt.Println("key not in Tree") fmt.Println(leafK) @@ -479,7 +445,7 @@ func (t *Tree) GenProof(k []byte) ([]byte, error) { } s := PackSiblings(t.hashFunction, siblings) - return s, nil + return value, s, nil } // PackSiblings packs the siblings into a byte array. @@ -567,7 +533,7 @@ func (t *Tree) Get(k []byte) ([]byte, []byte, error) { if err != nil { return nil, nil, err } - leafK, leafV := readLeafValue(value) + leafK, leafV := ReadLeafValue(value) if !bytes.Equal(k, leafK) { panic(fmt.Errorf("%s != %s", BytesToBigInt(k), BytesToBigInt(leafK))) } @@ -662,6 +628,7 @@ func (t *Tree) GetNLeafs() (int, error) { // Iterate iterates through the full Tree, executing the given function on each // node of the Tree. func (t *Tree) Iterate(f func([]byte, []byte)) error { + // TODO allow to define which root to use t.updateAccessTime() return t.iter(t.root, f) } @@ -691,7 +658,7 @@ func (t *Tree) iterWithStop(k []byte, currLevel int, f func(int, []byte, []byte) if stop { return nil } - l, r := readIntermediateChilds(v) + l, r := ReadIntermediateChilds(v) if err = t.iterWithStop(l, currLevel, f); err != nil { return err } @@ -719,6 +686,8 @@ func (t *Tree) iter(k []byte, f func([]byte, []byte)) error { // Where S is the size of the output of the hash function used for the Tree. func (t *Tree) Dump() ([]byte, error) { t.updateAccessTime() + // TODO allow to define which root to use + // WARNING current encoding only supports key & values of 255 bytes each // (due using only 1 byte for the length headers). var b []byte @@ -726,7 +695,7 @@ func (t *Tree) Dump() ([]byte, error) { if v[0] != PrefixValueLeaf { return } - leafK, leafV := readLeafValue(v) + leafK, leafV := ReadLeafValue(v) kv := make([]byte, 2+len(leafK)+len(leafV)) kv[0] = byte(len(leafK)) kv[1] = byte(len(leafV)) @@ -809,14 +778,14 @@ node [fontname=Monospace,fontsize=10,shape=box] case PrefixValueLeaf: fmt.Fprintf(w, "\"%v\" [style=filled];\n", hex.EncodeToString(k[:nChars])) // key & value from the leaf - kB, vB := readLeafValue(v) + kB, vB := ReadLeafValue(v) fmt.Fprintf(w, "\"%v\" -> {\"k:%v\\nv:%v\"}\n", hex.EncodeToString(k[:nChars]), hex.EncodeToString(kB[:nChars]), hex.EncodeToString(vB[:nChars])) fmt.Fprintf(w, "\"k:%v\\nv:%v\" [style=dashed]\n", hex.EncodeToString(kB[:nChars]), hex.EncodeToString(vB[:nChars])) case PrefixValueIntermediate: - l, r := readIntermediateChilds(v) + l, r := ReadIntermediateChilds(v) lStr := hex.EncodeToString(l[:nChars]) rStr := hex.EncodeToString(r[:nChars]) eStr := "" diff --git a/tree_test.go b/tree_test.go index f1647b8..93a52e2 100644 --- a/tree_test.go +++ b/tree_test.go @@ -267,7 +267,7 @@ func TestGenProofAndVerify(t *testing.T) { } k := BigIntToBytes(big.NewInt(int64(7))) - siblings, err := tree.GenProof(k) + _, siblings, err := tree.GenProof(k) c.Assert(err, qt.IsNil) k = BigIntToBytes(big.NewInt(int64(7)))