Browse Source

Add thresholdNLeafs configurable

ThresholdNLeafs defines the threshold number of leafs in the tree that
determines if AddBatch will work in memory or in disk. It is defined
when calling NewTree, and if set to 0 it will work always in disk.
master
arnaucube 3 years ago
parent
commit
4b6d6efdca
8 changed files with 172 additions and 86 deletions
  1. +64
    -35
      addbatch_test.go
  2. +2
    -1
      circomproofs_test.go
  3. +3
    -1
      hash.go
  4. +4
    -2
      helpers_test.go
  5. +2
    -1
      testvectors/circom/go-data-generator/generator_test.go
  6. +49
    -22
      tree.go
  7. +44
    -22
      tree_test.go
  8. +4
    -2
      vt_test.go

+ 64
- 35
addbatch_test.go

@ -41,12 +41,14 @@ func debugTime(descr string, time1, time2 time.Duration) {
func testInit(c *qt.C, n int) (*Tree, *Tree) { func testInit(c *qt.C, n int) (*Tree, *Tree) {
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionPoseidon)
tree1, err := NewTree(Config{Database: database1, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{Database: database2, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
bLen := HashFunctionPoseidon.Len() bLen := HashFunctionPoseidon.Len()
@ -72,7 +74,8 @@ func TestAddBatchTreeEmpty(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -95,7 +98,8 @@ func TestAddBatchTreeEmpty(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
tree2.dbgInit() tree2.dbgInit()
@ -122,7 +126,8 @@ func TestAddBatchTreeEmptyNotPowerOf2(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -137,7 +142,8 @@ func TestAddBatchTreeEmptyNotPowerOf2(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -169,13 +175,15 @@ func TestAddBatchTestVector1(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -209,13 +217,15 @@ func TestAddBatchTestVector1(t *testing.T) {
// 2nd test vectors // 2nd test vectors
database1, err = badgerdb.New(db.Options{Path: c.TempDir()}) database1, err = badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err = NewTree(database1, 256, HashFunctionBlake2b)
tree1, err = NewTree(Config{database1, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err = badgerdb.New(db.Options{Path: c.TempDir()}) database2, err = badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err = NewTree(database2, 256, HashFunctionBlake2b)
tree2, err = NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -257,13 +267,15 @@ func TestAddBatchTestVector2(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database, 256, HashFunctionPoseidon)
tree1, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -302,13 +314,15 @@ func TestAddBatchTestVector3(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database, 256, HashFunctionPoseidon)
tree1, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -351,13 +365,15 @@ func TestAddBatchTreeEmptyRandomKeys(t *testing.T) {
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -701,7 +717,8 @@ func TestAddBatchNotEmptyUnbalanced(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
tree2.dbgInit() tree2.dbgInit()
@ -778,7 +795,8 @@ func benchAdd(t *testing.T, ks, vs [][]byte) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionBlake2b)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -798,7 +816,8 @@ func benchAddBatch(t *testing.T, ks, vs [][]byte) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionBlake2b)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -831,7 +850,8 @@ func TestDbgStats(t *testing.T) {
// 1 // 1
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
@ -845,7 +865,8 @@ func TestDbgStats(t *testing.T) {
// 2 // 2
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -858,7 +879,8 @@ func TestDbgStats(t *testing.T) {
// 3 // 3
database3, err := badgerdb.New(db.Options{Path: c.TempDir()}) database3, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree3, err := NewTree(database3, 256, HashFunctionBlake2b)
tree3, err := NewTree(Config{database3, 256, DefaultThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree3.db.Close() //nolint:errcheck defer tree3.db.Close() //nolint:errcheck
@ -893,7 +915,8 @@ func TestLoadVT(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -929,7 +952,8 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -950,7 +974,8 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
tree2.dbgInit() tree2.dbgInit()
@ -964,7 +989,8 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
// use tree3 to add nil value array // use tree3 to add nil value array
database3, err := badgerdb.New(db.Options{Path: c.TempDir()}) database3, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree3, err := NewTree(database3, 256, HashFunctionPoseidon)
tree3, err := NewTree(Config{database3, 256, DefaultThresholdNLeafs,
HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree3.db.Close() //nolint:errcheck defer tree3.db.Close() //nolint:errcheck
@ -1008,35 +1034,38 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
func TestAddBatchThresholdInDisk(t *testing.T) { func TestAddBatchThresholdInDisk(t *testing.T) {
c := qt.New(t) c := qt.New(t)
// customize thresholdNLeafs for the test
testThresholdNLeafs := 1024
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
tree1, err := NewTree(Config{database1, 256, testThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
database2, err := pebbledb.New(db.Options{Path: c.TempDir()}) database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
tree2, err := NewTree(Config{database2, 256, testThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
database3, err := pebbledb.New(db.Options{Path: c.TempDir()}) database3, err := pebbledb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree3, err := NewTree(database3, 256, HashFunctionBlake2b)
tree3, err := NewTree(Config{database3, 256, testThresholdNLeafs,
HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree3.db.Close() //nolint:errcheck defer tree3.db.Close() //nolint:errcheck
// customize thresholdNLeafs for the test
thresholdNLeafs = 1024
var keys, values [][]byte var keys, values [][]byte
for i := 0; i < 3*thresholdNLeafs; i++ {
for i := 0; i < 3*testThresholdNLeafs; i++ {
k := randomBytes(32) k := randomBytes(32)
v := randomBytes(32) v := randomBytes(32)
if err := tree1.Add(k, v); err != nil { if err := tree1.Add(k, v); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if i < thresholdNLeafs+1 {
if i < testThresholdNLeafs+1 {
if err := tree2.Add(k, v); err != nil { if err := tree2.Add(k, v); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1046,7 +1075,7 @@ func TestAddBatchThresholdInDisk(t *testing.T) {
values = append(values, v) values = append(values, v)
} }
invalids, err := tree2.AddBatch(keys[thresholdNLeafs+1:], values[thresholdNLeafs+1:])
invalids, err := tree2.AddBatch(keys[testThresholdNLeafs+1:], values[testThresholdNLeafs+1:])
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
c.Check(len(invalids), qt.Equals, 0) c.Check(len(invalids), qt.Equals, 0)
// check that both trees roots are equal // check that both trees roots are equal

+ 2
- 1
circomproofs_test.go

@ -14,7 +14,8 @@ func TestCircomVerifierProof(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 4, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 4,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck

+ 3
- 1
hash.go

@ -77,7 +77,9 @@ func (f HashPoseidon) Len() int {
return 32 //nolint:gomnd return 32 //nolint:gomnd
} }
// Hash implements the hash method for the HashFunction HashPoseidon
// Hash implements the hash method for the HashFunction HashPoseidon. It
// expects the byte arrays to be little-endian representations of big.Int
// values.
func (f HashPoseidon) Hash(b ...[]byte) ([]byte, error) { func (f HashPoseidon) Hash(b ...[]byte) ([]byte, error) {
var toHash []*big.Int var toHash []*big.Int
for i := 0; i < len(b); i++ { for i := 0; i < len(b); i++ {

+ 4
- 2
helpers_test.go

@ -90,12 +90,14 @@ func TestReadTreeDBG(t *testing.T) {
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 100, HashFunctionBlake2b)
tree1, err := NewTree(Config{Database: database1, MaxLevels: 100,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 100, HashFunctionBlake2b)
tree2, err := NewTree(Config{Database: database2, MaxLevels: 100,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
// tree1 is generated by a loop of .Add // tree1 is generated by a loop of .Add

+ 2
- 1
testvectors/circom/go-data-generator/generator_test.go

@ -16,7 +16,8 @@ func TestGenerator(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := arbo.NewTree(database, 4, arbo.HashFunctionPoseidon)
tree, err := arbo.NewTree(arbo.Config{Database: database, MaxLevels: 4,
HashFunction: arbo.HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
testVector := [][]int64{ testVector := [][]int64{

+ 49
- 22
tree.go

@ -46,11 +46,11 @@ const (
) )
var ( var (
// thresholdNLeafs defines the threshold number of leafs in the tree
// that determines if AddBatch will work in memory or in disk. Is
// defined as a var in order to have the ability to modify it for
// testing purposes.
thresholdNLeafs = 1024 // TODO define a reasonable value
// DefaultThresholdNLeafs defines the threshold number of leafs in the
// tree that determines if AddBatch will work in memory or in disk. It
// is defined when calling NewTree, and if set to 0 it will work always
// in disk.
DefaultThresholdNLeafs = 65536
dbKeyRoot = []byte("root") dbKeyRoot = []byte("root")
dbKeyNLeafs = []byte("nleafs") dbKeyNLeafs = []byte("nleafs")
@ -85,9 +85,14 @@ var (
type Tree struct { type Tree struct {
sync.Mutex sync.Mutex
db db.Database
maxLevels int
snapshotRoot []byte
db db.Database
maxLevels int
// thresholdNLeafs defines the threshold number of leafs in the tree
// that determines if AddBatch will work in memory or in disk. It is
// defined when calling NewTree, and if set to 0 it will work always in
// disk.
thresholdNLeafs int
snapshotRoot []byte
hashFunction HashFunction hashFunction HashFunction
// TODO in the methods that use it, check if emptyHash param is len>0 // TODO in the methods that use it, check if emptyHash param is len>0
@ -97,13 +102,21 @@ type Tree struct {
dbg *dbgStats dbg *dbgStats
} }
// Config defines the configuration for calling NewTree & NewTreeWithTx methods
type Config struct {
Database db.Database
MaxLevels int
ThresholdNLeafs int
HashFunction HashFunction
}
// NewTree returns a new Tree, if there is a Tree still in the given database, it // NewTree returns a new Tree, if there is a Tree still in the given database, it
// will load it. // will load it.
func NewTree(database db.Database, maxLevels int, hash HashFunction) (*Tree, error) {
wTx := database.WriteTx()
func NewTree(cfg Config) (*Tree, error) {
wTx := cfg.Database.WriteTx()
defer wTx.Discard() defer wTx.Discard()
t, err := NewTreeWithTx(wTx, database, maxLevels, hash)
t, err := NewTreeWithTx(wTx, cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -117,9 +130,10 @@ func NewTree(database db.Database, maxLevels int, hash HashFunction) (*Tree, err
// NewTreeWithTx returns a new Tree using the given db.WriteTx, which will not // NewTreeWithTx returns a new Tree using the given db.WriteTx, which will not
// be ccommited inside this method, if there is a Tree still in the given // be ccommited inside this method, if there is a Tree still in the given
// database, it will load it. // database, it will load it.
func NewTreeWithTx(wTx db.WriteTx, database db.Database,
maxLevels int, hash HashFunction) (*Tree, error) {
t := Tree{db: database, maxLevels: maxLevels, hashFunction: hash}
func NewTreeWithTx(wTx db.WriteTx, cfg Config) (*Tree, error) {
// if thresholdNLeafs is set to 0, use the DefaultThresholdNLeafs
t := Tree{db: cfg.Database, maxLevels: cfg.MaxLevels,
thresholdNLeafs: cfg.ThresholdNLeafs, hashFunction: cfg.HashFunction}
t.emptyHash = make([]byte, t.hashFunction.Len()) // empty t.emptyHash = make([]byte, t.hashFunction.Len()) // empty
_, err := wTx.Get(dbKeyRoot) _, err := wTx.Get(dbKeyRoot)
@ -220,7 +234,7 @@ func (t *Tree) AddBatchWithTx(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
if err != nil { if err != nil {
return nil, err return nil, err
} }
if nLeafs > thresholdNLeafs {
if nLeafs > t.thresholdNLeafs {
return t.addBatchInDisk(wTx, keys, values) return t.addBatchInDisk(wTx, keys, values)
} }
return t.addBatchInMemory(wTx, keys, values) return t.addBatchInMemory(wTx, keys, values)
@ -231,7 +245,7 @@ func (t *Tree) addBatchInDisk(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
if nCPU == 1 || len(keys) < nCPU { if nCPU == 1 || len(keys) < nCPU {
var invalids []Invalid var invalids []Invalid
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
if err := t.AddWithTx(wTx, keys[i], values[i]); err != nil {
if err := t.addWithTx(wTx, keys[i], values[i]); err != nil {
invalids = append(invalids, Invalid{i, err}) invalids = append(invalids, Invalid{i, err})
} }
} }
@ -265,7 +279,8 @@ func (t *Tree) addBatchInDisk(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
// (until one is added) // (until one is added)
inserted := -1 inserted := -1
for j := 0; j < len(buckets[i]); j++ { for j := 0; j < len(buckets[i]); j++ {
if newRoot, err := t.add(wTx, root, 0, buckets[i][j].k, buckets[i][j].v); err == nil {
if newRoot, err := t.add(wTx, root, 0,
buckets[i][j].k, buckets[i][j].v); err == nil {
inserted = j inserted = j
root = newRoot root = newRoot
break break
@ -308,10 +323,15 @@ func (t *Tree) addBatchInDisk(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
// are done, iter over the cpuWTxs and copy their // are done, iter over the cpuWTxs and copy their
// content into the main wTx // content into the main wTx
for j := 0; j < len(buckets[cpu]); j++ { for j := 0; j < len(buckets[cpu]); j++ {
subRoots[cpu], err = t.add(txs[cpu], subRoots[cpu], l, buckets[cpu][j].k, buckets[cpu][j].v)
newSubRoot, err := t.add(txs[cpu], subRoots[cpu],
l, buckets[cpu][j].k, buckets[cpu][j].v)
if err != nil { if err != nil {
invalidsInBucket[cpu] = append(invalidsInBucket[cpu], Invalid{buckets[cpu][j].pos, err})
invalidsInBucket[cpu] = append(invalidsInBucket[cpu],
Invalid{buckets[cpu][j].pos, err})
continue
} }
// if there has not been errors, set the new subRoots[cpu]
subRoots[cpu] = newSubRoot
} }
wg.Done() wg.Done()
}(i) }(i)
@ -346,6 +366,7 @@ func (t *Tree) addBatchInDisk(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
return invalids, nil return invalids, nil
} }
func (t *Tree) upFromSubRoots(wTx db.WriteTx, subRoots [][]byte) ([]byte, error) { func (t *Tree) upFromSubRoots(wTx db.WriteTx, subRoots [][]byte) ([]byte, error) {
// is a method of Tree just to get access to t.hashFunction and // is a method of Tree just to get access to t.hashFunction and
// t.emptyHash. // t.emptyHash.
@ -495,7 +516,12 @@ func (t *Tree) AddWithTx(wTx db.WriteTx, k, v []byte) error {
if !t.editable() { if !t.editable() {
return ErrSnapshotNotEditable return ErrSnapshotNotEditable
} }
return t.addWithTx(wTx, k, v)
}
// warning: addWithTx does not use the Tree mutex, the mutex is responsibility
// of the methods calling this method, and same with t.editable().
func (t *Tree) addWithTx(wTx db.WriteTx, k, v []byte) error {
root, err := t.RootWithTx(wTx) root, err := t.RootWithTx(wTx)
if err != nil { if err != nil {
return err return err
@ -1132,7 +1158,8 @@ func (t *Tree) SetRootWithTx(wTx db.WriteTx, root []byte) error {
// check that the root exists in the db // check that the root exists in the db
if !bytes.Equal(root, t.emptyHash) { if !bytes.Equal(root, t.emptyHash) {
if _, err := wTx.Get(root); err == ErrKeyNotFound { if _, err := wTx.Get(root); err == ErrKeyNotFound {
return fmt.Errorf("can not SetRoot with root %x, as it does not exist in the db", root)
return fmt.Errorf("can not SetRoot with root %x, as it"+
" does not exist in the db", root)
} else if err != nil { } else if err != nil {
return err return err
} }
@ -1157,8 +1184,8 @@ func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) {
if !bytes.Equal(fromRoot, t.emptyHash) { if !bytes.Equal(fromRoot, t.emptyHash) {
if _, err := rTx.Get(fromRoot); err == ErrKeyNotFound { if _, err := rTx.Get(fromRoot); err == ErrKeyNotFound {
return nil, return nil,
fmt.Errorf("can not do a Snapshot with root %x, as it does not exist in the db",
fromRoot)
fmt.Errorf("can not do a Snapshot with root %x,"+
" as it does not exist in the db", fromRoot)
} else if err != nil { } else if err != nil {
return nil, err return nil, err
} }

+ 44
- 22
tree_test.go

@ -72,7 +72,8 @@ func TestAddTestVectors(t *testing.T) {
func testAdd(c *qt.C, hashFunc HashFunction, testVectors []string) { func testAdd(c *qt.C, hashFunc HashFunction, testVectors []string) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, hashFunc)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: hashFunc})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -104,7 +105,8 @@ func TestAddBatch(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -122,7 +124,8 @@ func TestAddBatch(t *testing.T) {
database, err = badgerdb.New(db.Options{Path: c.TempDir()}) database, err = badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -145,7 +148,8 @@ func TestAddDifferentOrder(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionPoseidon)
tree1, err := NewTree(Config{Database: database1, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
@ -160,7 +164,8 @@ func TestAddDifferentOrder(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{Database: database2, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
@ -185,7 +190,8 @@ func TestAddRepeatedIndex(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -203,7 +209,8 @@ func TestUpdate(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -256,7 +263,8 @@ func TestAux(t *testing.T) { // TODO split in proper tests
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -295,7 +303,8 @@ func TestGet(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -319,7 +328,8 @@ func TestGenProofAndVerify(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -351,7 +361,8 @@ func TestDumpAndImportDump(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 256, HashFunctionPoseidon)
tree1, err := NewTree(Config{Database: database1, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree1.db.Close() //nolint:errcheck defer tree1.db.Close() //nolint:errcheck
@ -369,7 +380,8 @@ func TestDumpAndImportDump(t *testing.T) {
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
tree2, err := NewTree(Config{Database: database2, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree2.db.Close() //nolint:errcheck defer tree2.db.Close() //nolint:errcheck
err = tree2.ImportDump(e) err = tree2.ImportDump(e)
@ -388,7 +400,8 @@ func TestRWMutex(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -471,12 +484,14 @@ func TestAddBatchFullyUsed(t *testing.T) {
database1, err := badgerdb.New(db.Options{Path: c.TempDir()}) database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree1, err := NewTree(database1, 4, HashFunctionPoseidon)
tree1, err := NewTree(Config{Database: database1, MaxLevels: 4,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
database2, err := badgerdb.New(db.Options{Path: c.TempDir()}) database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree2, err := NewTree(database2, 4, HashFunctionPoseidon)
tree2, err := NewTree(Config{Database: database2, MaxLevels: 4,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
var keys, values [][]byte var keys, values [][]byte
@ -530,7 +545,8 @@ func TestSetRoot(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
expectedRoot := "13742386369878513332697380582061714160370929283209286127733983161245560237407" expectedRoot := "13742386369878513332697380582061714160370929283209286127733983161245560237407"
@ -586,7 +602,8 @@ func TestSnapshot(t *testing.T) {
c := qt.New(t) c := qt.New(t)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
// fill the tree // fill the tree
@ -636,7 +653,8 @@ func TestGetFromSnapshotExpectArboErrKeyNotFound(t *testing.T) {
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 256, HashFunctionPoseidon)
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
HashFunction: HashFunctionPoseidon})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck
@ -658,7 +676,8 @@ func TestKeyLen(t *testing.T) {
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
// maxLevels is 100, keyPath length = ceil(maxLevels/8) = 13 // maxLevels is 100, keyPath length = ceil(maxLevels/8) = 13
maxLevels := 100 maxLevels := 100
tree, err := NewTree(database, maxLevels, HashFunctionBlake2b)
tree, err := NewTree(Config{Database: database, MaxLevels: maxLevels,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
// expect no errors when adding a key of only 4 bytes (when the // expect no errors when adding a key of only 4 bytes (when the
@ -690,7 +709,8 @@ func TestKeyLen(t *testing.T) {
maxLevels = 32 maxLevels = 32
database, err = badgerdb.New(db.Options{Path: c.TempDir()}) database, err = badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err = NewTree(database, maxLevels, HashFunctionBlake2b)
tree, err = NewTree(Config{Database: database, MaxLevels: maxLevels,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
maxKeyLen := int(math.Ceil(float64(maxLevels) / float64(8))) //nolint:gomnd maxKeyLen := int(math.Ceil(float64(maxLevels) / float64(8))) //nolint:gomnd
@ -760,7 +780,8 @@ func TestKeyLenBiggerThan32(t *testing.T) {
maxLevels := 264 maxLevels := 264
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, maxLevels, HashFunctionBlake2b)
tree, err := NewTree(Config{Database: database, MaxLevels: maxLevels,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
bLen := 33 bLen := 33
@ -802,7 +823,8 @@ func benchmarkAdd(b *testing.B, hashFunc HashFunction, ks, vs [][]byte) {
c := qt.New(b) c := qt.New(b)
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, 140, hashFunc)
tree, err := NewTree(Config{Database: database, MaxLevels: 140,
HashFunction: hashFunc})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
defer tree.db.Close() //nolint:errcheck defer tree.db.Close() //nolint:errcheck

+ 4
- 2
vt_test.go

@ -19,7 +19,8 @@ func testVirtualTree(c *qt.C, maxLevels int, keys, values [][]byte) {
// normal tree, to have an expected root value // normal tree, to have an expected root value
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, maxLevels, HashFunctionSha256)
tree, err := NewTree(Config{Database: database, MaxLevels: maxLevels,
HashFunction: HashFunctionSha256})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
err := tree.Add(keys[i], values[i]) err := tree.Add(keys[i], values[i])
@ -124,7 +125,8 @@ func TestVirtualTreeAddBatch(t *testing.T) {
// normal tree, to have an expected root value // normal tree, to have an expected root value
database, err := badgerdb.New(db.Options{Path: c.TempDir()}) database, err := badgerdb.New(db.Options{Path: c.TempDir()})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
tree, err := NewTree(database, maxLevels, HashFunctionBlake2b)
tree, err := NewTree(Config{Database: database, MaxLevels: maxLevels,
HashFunction: HashFunctionBlake2b})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
err := tree.Add(keys[i], values[i]) err := tree.Add(keys[i], values[i])

Loading…
Cancel
Save