Browse Source

Replace naive AddBatch by optimized AddBatch

- Replace naive AddBatch by optimized AddBatch
- Add blake2b hash support
- Expose needed methods for external usage (ReadLeafValue,
ReadIntermediateChilds)
- Return 'value' in GenProof
master
arnaucube 3 years ago
parent
commit
6dcbbdf4a5
9 changed files with 99 additions and 68 deletions
  1. +2
    -0
      README.md
  2. +5
    -4
      addbatch.go
  3. +7
    -7
      addbatch_test.go
  4. +2
    -1
      go.mod
  5. +11
    -0
      go.sum
  6. +33
    -0
      hash.go
  7. +14
    -0
      hash_test.go
  8. +24
    -55
      tree.go
  9. +1
    -1
      tree_test.go

+ 2
- 0
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

+ 5
- 4
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)
})

+ 7
- 7
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)

+ 2
- 1
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
)

+ 11
- 0
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=

+ 33
- 0
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
}

+ 14
- 0
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")
}

+ 24
- 55
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 := ""

+ 1
- 1
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)))

Loading…
Cancel
Save