mirror of
https://github.com/vocdoni/arbo.git
synced 2026-01-10 06:17:58 -05:00
dirty commit
This commit is contained in:
@@ -76,7 +76,7 @@ func TestAddBatchTreeEmpty(t *testing.T) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
var keys, values [][]byte
|
||||
@@ -100,7 +100,7 @@ func TestAddBatchTreeEmpty(t *testing.T) {
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
tree2.dbgInit()
|
||||
|
||||
start = time.Now()
|
||||
@@ -128,7 +128,7 @@ func TestAddBatchTreeEmptyNotPowerOf2(t *testing.T) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < nLeafs; i++ {
|
||||
@@ -144,7 +144,7 @@ func TestAddBatchTreeEmptyNotPowerOf2(t *testing.T) {
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 0; i < nLeafs; i++ {
|
||||
@@ -177,14 +177,14 @@ func TestAddBatchTestVector1(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
// leafs in 2nd level subtrees: [ 6, 0, 1, 1]
|
||||
testvectorKeys := []string{
|
||||
@@ -219,14 +219,14 @@ func TestAddBatchTestVector1(t *testing.T) {
|
||||
tree1, err = NewTree(Config{database1, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err = pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err = NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
testvectorKeys = []string{
|
||||
"1c7c2265e368314ca58ed2e1f33a326f1220e234a566d55c3605439dbe411642",
|
||||
@@ -269,14 +269,14 @@ func TestAddBatchTestVector2(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := tree1.HashFunction().Len()
|
||||
var keys, values [][]byte
|
||||
@@ -316,14 +316,14 @@ func TestAddBatchTestVector3(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := tree1.HashFunction().Len()
|
||||
var keys, values [][]byte
|
||||
@@ -367,14 +367,14 @@ func TestAddBatchTreeEmptyRandomKeys(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 0; i < nLeafs; i++ {
|
||||
@@ -719,7 +719,7 @@ func TestAddBatchNotEmptyUnbalanced(t *testing.T) {
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
tree2.dbgInit()
|
||||
|
||||
var keys, values [][]byte
|
||||
@@ -797,7 +797,7 @@ func benchAdd(t *testing.T, ks, vs [][]byte) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
start := time.Now()
|
||||
for i := 0; i < len(ks); i++ {
|
||||
@@ -818,7 +818,7 @@ func benchAddBatch(t *testing.T, ks, vs [][]byte) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
tree.dbgInit()
|
||||
|
||||
@@ -852,7 +852,7 @@ func TestDbgStats(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database1, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
tree1.dbgInit()
|
||||
|
||||
@@ -867,7 +867,7 @@ func TestDbgStats(t *testing.T) {
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
tree2.dbgInit()
|
||||
|
||||
@@ -881,7 +881,7 @@ func TestDbgStats(t *testing.T) {
|
||||
tree3, err := NewTree(Config{database3, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree3.db.Close() //nolint:errcheck
|
||||
defer tree3.treedb.Close() //nolint:errcheck
|
||||
|
||||
tree3.dbgInit()
|
||||
|
||||
@@ -916,7 +916,7 @@ func TestLoadVT(t *testing.T) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 0; i < nLeafs; i++ {
|
||||
@@ -951,7 +951,7 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
|
||||
tree, err := NewTree(Config{database, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
var keys, values [][]byte
|
||||
@@ -973,7 +973,7 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
|
||||
tree2, err := NewTree(Config{database2, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
tree2.dbgInit()
|
||||
|
||||
invalids, err := tree2.AddBatch(keys, values)
|
||||
@@ -988,7 +988,7 @@ func TestAddKeysWithEmptyValues(t *testing.T) {
|
||||
tree3, err := NewTree(Config{database3, 256, DefaultThresholdNLeafs,
|
||||
HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree3.db.Close() //nolint:errcheck
|
||||
defer tree3.treedb.Close() //nolint:errcheck
|
||||
|
||||
invalids, err = tree3.AddBatch(keys, nil)
|
||||
c.Assert(err, qt.IsNil)
|
||||
@@ -1038,21 +1038,21 @@ func TestAddBatchThresholdInDisk(t *testing.T) {
|
||||
tree1, err := NewTree(Config{database1, 256, testThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree2, err := NewTree(Config{database2, 256, testThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
database3, err := pebbledb.New(db.Options{Path: c.TempDir()})
|
||||
c.Assert(err, qt.IsNil)
|
||||
tree3, err := NewTree(Config{database3, 256, testThresholdNLeafs,
|
||||
HashFunctionBlake2b})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree3.db.Close() //nolint:errcheck
|
||||
defer tree3.treedb.Close() //nolint:errcheck
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 0; i < 3*testThresholdNLeafs; i++ {
|
||||
@@ -1078,7 +1078,7 @@ func TestAddBatchThresholdInDisk(t *testing.T) {
|
||||
checkRoots(c, tree1, tree2)
|
||||
|
||||
// call directly the tree3.addBatchInDisk to ensure that is tested
|
||||
wTx := tree3.db.WriteTx()
|
||||
wTx := tree3.treedb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
invalids, err = tree3.addBatchInDisk(wTx, keys, values)
|
||||
c.Assert(err, qt.IsNil)
|
||||
@@ -1127,7 +1127,7 @@ func testUpFromSubRoots(c *qt.C, tree1, tree2 *Tree, preSubRoots [][]byte) {
|
||||
root1, err := tree1.Root()
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
wTx := tree2.db.WriteTx()
|
||||
wTx := tree2.treedb.WriteTx()
|
||||
subRoots := make([][]byte, len(preSubRoots))
|
||||
for i := 0; i < len(preSubRoots); i++ {
|
||||
if preSubRoots[i] == nil || bytes.Equal(preSubRoots[i], tree1.emptyHash) {
|
||||
@@ -1159,8 +1159,8 @@ func testUpFromSubRoots(c *qt.C, tree1, tree2 *Tree, preSubRoots [][]byte) {
|
||||
|
||||
func testUpFromSubRootsWithEmpties(c *qt.C, preSubRoots [][]byte, indexEmpties []int) {
|
||||
tree1, tree2 := initTestUpFromSubRoots(c)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
testPreSubRoots := make([][]byte, len(preSubRoots))
|
||||
copy(testPreSubRoots[:], preSubRoots[:])
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestCircomVerifierProof(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 4,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
testVector := [][]int64{
|
||||
{1, 11},
|
||||
|
||||
63
tree.go
63
tree.go
@@ -22,6 +22,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"go.vocdoni.io/dvote/db"
|
||||
"go.vocdoni.io/dvote/db/prefixeddb"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,9 +56,11 @@ var (
|
||||
// in disk.
|
||||
DefaultThresholdNLeafs = 65536
|
||||
|
||||
dbKeyRoot = []byte("root")
|
||||
dbKeyNLeafs = []byte("nleafs")
|
||||
emptyValue = []byte{0}
|
||||
dbTreePrefix = []byte("tree")
|
||||
dbValuesPrefix = []byte("values")
|
||||
dbKeyRoot = []byte("root")
|
||||
dbKeyNLeafs = []byte("nleafs")
|
||||
emptyValue = []byte{0}
|
||||
|
||||
// ErrKeyNotFound is used when a key is not found in the db neither in
|
||||
// the current db Batch.
|
||||
@@ -88,7 +91,8 @@ var (
|
||||
type Tree struct {
|
||||
sync.Mutex
|
||||
|
||||
db db.Database
|
||||
treedb db.Database
|
||||
valuesdb 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
|
||||
@@ -138,9 +142,16 @@ func NewTreeWithTx(wTx db.WriteTx, cfg Config) (*Tree, error) {
|
||||
if cfg.ThresholdNLeafs == 0 {
|
||||
cfg.ThresholdNLeafs = DefaultThresholdNLeafs
|
||||
}
|
||||
t := Tree{db: cfg.Database, maxLevels: cfg.MaxLevels,
|
||||
thresholdNLeafs: cfg.ThresholdNLeafs, hashFunction: cfg.HashFunction}
|
||||
t.emptyHash = make([]byte, t.hashFunction.Len()) // empty
|
||||
treedb := prefixeddb.NewPrefixedDatabase(cfg.Database, dbTreePrefix)
|
||||
valuesdb := prefixeddb.NewPrefixedDatabase(cfg.Database, dbValuesPrefix)
|
||||
t := Tree{
|
||||
treedb: treedb,
|
||||
valuesdb: valuesdb,
|
||||
maxLevels: cfg.MaxLevels,
|
||||
thresholdNLeafs: cfg.ThresholdNLeafs,
|
||||
hashFunction: cfg.HashFunction,
|
||||
emptyHash: make([]byte, cfg.HashFunction.Len()),
|
||||
}
|
||||
|
||||
_, err := wTx.Get(dbKeyRoot)
|
||||
if err == db.ErrKeyNotFound {
|
||||
@@ -160,7 +171,7 @@ func NewTreeWithTx(wTx db.WriteTx, cfg Config) (*Tree, error) {
|
||||
|
||||
// Root returns the root of the Tree
|
||||
func (t *Tree) Root() ([]byte, error) {
|
||||
return t.RootWithTx(t.db)
|
||||
return t.RootWithTx(t.treedb)
|
||||
}
|
||||
|
||||
// RootWithTx returns the root of the Tree using the given db.ReadTx
|
||||
@@ -201,7 +212,7 @@ type Invalid struct {
|
||||
// the indexes of the keys failed to add. Supports empty values as input
|
||||
// parameters, which is equivalent to 0 valued byte array.
|
||||
func (t *Tree) AddBatch(keys, values [][]byte) ([]Invalid, error) {
|
||||
wTx := t.db.WriteTx()
|
||||
wTx := t.treedb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
|
||||
invalids, err := t.AddBatchWithTx(wTx, keys, values)
|
||||
@@ -312,7 +323,7 @@ func (t *Tree) addBatchInDisk(wTx db.WriteTx, keys, values [][]byte) ([]Invalid,
|
||||
invalidsInBucket := make([][]Invalid, nCPU)
|
||||
txs := make([]db.WriteTx, nCPU)
|
||||
for i := 0; i < nCPU; i++ {
|
||||
txs[i] = t.db.WriteTx()
|
||||
txs[i] = t.treedb.WriteTx()
|
||||
err := txs[i].Apply(wTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -493,7 +504,7 @@ func (t *Tree) loadVT() (vt, error) {
|
||||
vt := newVT(t.maxLevels, t.hashFunction)
|
||||
vt.params.dbg = t.dbg
|
||||
var callbackErr error
|
||||
err := t.IterateWithStopWithTx(t.db, nil, func(_ int, k, v []byte) bool {
|
||||
err := t.IterateWithStopWithTx(t.treedb, nil, func(_ int, k, v []byte) bool {
|
||||
if v[0] != PrefixValueLeaf {
|
||||
return false
|
||||
}
|
||||
@@ -515,7 +526,7 @@ func (t *Tree) loadVT() (vt, error) {
|
||||
// *big.Int, is expected that are represented by a Little-Endian byte array
|
||||
// (for circom compatibility).
|
||||
func (t *Tree) Add(k, v []byte) error {
|
||||
wTx := t.db.WriteTx()
|
||||
wTx := t.treedb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
|
||||
if err := t.AddWithTx(wTx, k, v); err != nil {
|
||||
@@ -860,7 +871,7 @@ func getPath(numLevels int, k []byte) []bool {
|
||||
// Update updates the value for a given existing key. If the given key does not
|
||||
// exist, returns an error.
|
||||
func (t *Tree) Update(k, v []byte) error {
|
||||
wTx := t.db.WriteTx()
|
||||
wTx := t.treedb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
|
||||
if err := t.UpdateWithTx(wTx, k, v); err != nil {
|
||||
@@ -930,7 +941,7 @@ func (t *Tree) UpdateWithTx(wTx db.WriteTx, k, v []byte) error {
|
||||
// returned, together with the packed siblings of the proof, and a boolean
|
||||
// parameter that indicates if the proof is of existence (true) or not (false).
|
||||
func (t *Tree) GenProof(k []byte) ([]byte, []byte, []byte, bool, error) {
|
||||
return t.GenProofWithTx(t.db, k)
|
||||
return t.GenProofWithTx(t.treedb, k)
|
||||
}
|
||||
|
||||
// GenProofWithTx does the same than the GenProof method, but allowing to pass
|
||||
@@ -1062,7 +1073,7 @@ func bytesToBitmap(b []byte) []bool {
|
||||
// will be placed the data found in the tree in the leaf that was on the path
|
||||
// going to the input key.
|
||||
func (t *Tree) Get(k []byte) ([]byte, []byte, error) {
|
||||
return t.GetWithTx(t.db, k)
|
||||
return t.GetWithTx(t.treedb, k)
|
||||
}
|
||||
|
||||
// GetWithTx does the same than the Get method, but allowing to pass the
|
||||
@@ -1151,7 +1162,7 @@ func (t *Tree) setNLeafs(wTx db.WriteTx, nLeafs int) error {
|
||||
|
||||
// GetNLeafs returns the number of Leafs of the Tree.
|
||||
func (t *Tree) GetNLeafs() (int, error) {
|
||||
return t.GetNLeafsWithTx(t.db)
|
||||
return t.GetNLeafsWithTx(t.treedb)
|
||||
}
|
||||
|
||||
// GetNLeafsWithTx does the same than the GetNLeafs method, but allowing to
|
||||
@@ -1167,7 +1178,7 @@ func (t *Tree) GetNLeafsWithTx(rTx db.Reader) (int, error) {
|
||||
|
||||
// SetRoot sets the root to the given root
|
||||
func (t *Tree) SetRoot(root []byte) error {
|
||||
wTx := t.db.WriteTx()
|
||||
wTx := t.treedb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
|
||||
if err := t.SetRootWithTx(wTx, root); err != nil {
|
||||
@@ -1209,7 +1220,7 @@ func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rTx := t.db
|
||||
rTx := t.treedb
|
||||
// check that the root exists in the db
|
||||
if !bytes.Equal(fromRoot, t.emptyHash) {
|
||||
if _, err := rTx.Get(fromRoot); err == ErrKeyNotFound {
|
||||
@@ -1222,7 +1233,7 @@ func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) {
|
||||
}
|
||||
|
||||
return &Tree{
|
||||
db: t.db,
|
||||
treedb: t.treedb,
|
||||
maxLevels: t.maxLevels,
|
||||
snapshotRoot: fromRoot,
|
||||
emptyHash: t.emptyHash,
|
||||
@@ -1234,7 +1245,7 @@ func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) {
|
||||
// Iterate iterates through the full Tree, executing the given function on each
|
||||
// node of the Tree.
|
||||
func (t *Tree) Iterate(fromRoot []byte, f func([]byte, []byte)) error {
|
||||
return t.IterateWithTx(t.db, fromRoot, f)
|
||||
return t.IterateWithTx(t.treedb, fromRoot, f)
|
||||
}
|
||||
|
||||
// IterateWithTx does the same than the Iterate method, but allowing to pass
|
||||
@@ -1258,12 +1269,12 @@ func (t *Tree) IterateWithStop(fromRoot []byte, f func(int, []byte, []byte) bool
|
||||
// allow to define which root to use
|
||||
if fromRoot == nil {
|
||||
var err error
|
||||
fromRoot, err = t.RootWithTx(t.db)
|
||||
fromRoot, err = t.RootWithTx(t.treedb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return t.iterWithStop(t.db, fromRoot, 0, f)
|
||||
return t.iterWithStop(t.treedb, fromRoot, 0, f)
|
||||
}
|
||||
|
||||
// IterateWithStopWithTx does the same than the IterateWithStop method, but
|
||||
@@ -1470,14 +1481,14 @@ node [fontname=Monospace,fontsize=10,shape=box]
|
||||
}
|
||||
if fromRoot == nil {
|
||||
var err error
|
||||
fromRoot, err = t.RootWithTx(t.db)
|
||||
fromRoot, err = t.RootWithTx(t.treedb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
nEmpties := 0
|
||||
err := t.iterWithStop(t.db, fromRoot, 0, func(currLvl int, k, v []byte) bool {
|
||||
err := t.iterWithStop(t.treedb, fromRoot, 0, func(currLvl int, k, v []byte) bool {
|
||||
if currLvl == untilLvl {
|
||||
return true // to stop the iter from going down
|
||||
}
|
||||
@@ -1575,3 +1586,7 @@ func (t *Tree) PrintGraphvizFirstNLevels(fromRoot []byte, untilLvl int) error {
|
||||
// TODO circom proofs
|
||||
// TODO data structure for proofs (including root, key, value, siblings,
|
||||
// hashFunction) + method to verify that data structure
|
||||
|
||||
func (t *Tree) MaxKeyLen() int {
|
||||
return min(int(math.Ceil(float64(t.maxLevels)/8)), t.HashFunction().Len())
|
||||
}
|
||||
|
||||
122
tree_big.go
Normal file
122
tree_big.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package arbo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
)
|
||||
|
||||
func (t *Tree) AddBigInt(k *big.Int, v ...*big.Int) error {
|
||||
bk, bv, fbv, err := bigIntLeaf(t.HashFunction(), k, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.Add(bk, bv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wTx := t.valuesdb.WriteTx()
|
||||
defer wTx.Discard()
|
||||
|
||||
if err := wTx.Set(bk, fbv); err != nil {
|
||||
return err
|
||||
}
|
||||
return wTx.Commit()
|
||||
}
|
||||
|
||||
func (t *Tree) GetBigInt(k *big.Int) (*big.Int, []*big.Int, error) {
|
||||
bk, bv, err := t.Get(bigIntToKey(t.HashFunction(), k))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return t.leafToBigInts(bk, bv)
|
||||
}
|
||||
|
||||
func (t *Tree) GenProofBigInts(k *big.Int) (*big.Int, []*big.Int, []byte, bool, error) {
|
||||
bk, bv, siblings, exists, err := t.GenProof(bigIntToKey(t.HashFunction(), k))
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
}
|
||||
k, v, err := t.leafToBigInts(bk, bv)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
}
|
||||
return k, v, siblings, exists, nil
|
||||
}
|
||||
|
||||
func CheckProofBigInts(hFn HashFunction, root, packedSiblings []byte, k *big.Int, v ...*big.Int) (bool, error) {
|
||||
bk, bv, _, err := bigIntLeaf(hFn, k, v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return CheckProof(hFn, bk, bv, root, packedSiblings)
|
||||
}
|
||||
|
||||
func bigIntToKey(hFn HashFunction, b *big.Int) []byte {
|
||||
return BigIntToBytes(hFn.Len(), b)
|
||||
}
|
||||
|
||||
func bigIntLeaf(hFn HashFunction, key *big.Int, values []*big.Int) ([]byte, []byte, []byte, error) {
|
||||
// calculate the bytes of the key
|
||||
bKey := bigIntToKey(hFn, key)
|
||||
// calculate the bytes of the full values (should be reversible)
|
||||
bFullValue := []byte{}
|
||||
for _, v := range values {
|
||||
val := append([]byte{byte(len(v.Bytes()))}, v.Bytes()...)
|
||||
bFullValue = append(bFullValue, val...)
|
||||
}
|
||||
// calculate the value used to build the tree
|
||||
bValue, err := bigIntToLeafValue(hFn, bFullValue)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return bKey, bValue, bFullValue, nil
|
||||
}
|
||||
|
||||
func bigIntToLeafValue(hFn HashFunction, bFullValue []byte) ([]byte, error) {
|
||||
// split the full value in chunks of the size of the hash function output
|
||||
chunks := [][]byte{}
|
||||
chunk := []byte{}
|
||||
for i := range bFullValue {
|
||||
chunk = append(chunk, bFullValue[i])
|
||||
if len(chunk) == hFn.Len() {
|
||||
chunks = append(chunks, chunk)
|
||||
chunk = []byte{}
|
||||
}
|
||||
}
|
||||
// if there is a chunk left, add it to the chunks
|
||||
if len(chunk) > 0 {
|
||||
chunks = append(chunks, chunk)
|
||||
}
|
||||
// hash the chunks
|
||||
bValue, err := hFn.Hash(chunks...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bValue, nil
|
||||
}
|
||||
|
||||
func (t *Tree) leafToBigInts(key, value []byte) (*big.Int, []*big.Int, error) {
|
||||
bFullValue, err := t.valuesdb.Get(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// recalculate the value to check if it matches the stored value
|
||||
expectedFullValue, err := bigIntToLeafValue(t.HashFunction(), bFullValue)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !bytes.Equal(expectedFullValue, value) {
|
||||
return nil, nil, fmt.Errorf("LeafToBigInt: expectedFullValue != value")
|
||||
}
|
||||
// reverse the process of values encoding
|
||||
values := []*big.Int{}
|
||||
for iter := slices.Clone(bFullValue); len(iter) > 0; {
|
||||
lenV := int(bFullValue[0])
|
||||
values = append(values, new(big.Int).SetBytes(bFullValue[1:1+lenV]))
|
||||
iter = iter[1+lenV:]
|
||||
}
|
||||
return BytesToBigInt(key), values, nil
|
||||
}
|
||||
5
tree_big_test.go
Normal file
5
tree_big_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package arbo
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGenCheckProofBigInt(t *testing.T) {}
|
||||
30
tree_test.go
30
tree_test.go
@@ -76,7 +76,7 @@ func testAdd(c *qt.C, hashFunc HashFunction, testVectors []string) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: hashFunc})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
root, err := tree.Root()
|
||||
c.Assert(err, qt.IsNil)
|
||||
@@ -109,7 +109,7 @@ func TestAddBatch(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -128,7 +128,7 @@ func TestAddBatch(t *testing.T) {
|
||||
tree2, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -152,7 +152,7 @@ func TestAddDifferentOrder(t *testing.T) {
|
||||
tree1, err := NewTree(Config{Database: database1, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < 16; i++ {
|
||||
@@ -168,7 +168,7 @@ func TestAddDifferentOrder(t *testing.T) {
|
||||
tree2, err := NewTree(Config{Database: database2, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
for i := 16 - 1; i >= 0; i-- {
|
||||
k := BigIntToBytes(bLen, big.NewInt(int64(i)))
|
||||
@@ -194,7 +194,7 @@ func TestAddRepeatedIndex(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
k := BigIntToBytes(bLen, big.NewInt(int64(3)))
|
||||
@@ -213,7 +213,7 @@ func TestUpdate(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
k := BigIntToBytes(bLen, big.NewInt(int64(20)))
|
||||
@@ -267,7 +267,7 @@ func TestAux(t *testing.T) { // TODO split in proper tests
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
k := BigIntToBytes(bLen, big.NewInt(int64(1)))
|
||||
@@ -307,7 +307,7 @@ func TestGet(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -432,7 +432,7 @@ func TestGenProofAndVerify(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -473,7 +473,7 @@ func testDumpAndImportDump(t *testing.T, inFile bool) {
|
||||
tree1, err := NewTree(Config{Database: database1, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree1.db.Close() //nolint:errcheck
|
||||
defer tree1.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
for i := 0; i < 16; i++ {
|
||||
@@ -502,7 +502,7 @@ func testDumpAndImportDump(t *testing.T, inFile bool) {
|
||||
tree2, err := NewTree(Config{Database: database2, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close() //nolint:errcheck
|
||||
defer tree2.treedb.Close() //nolint:errcheck
|
||||
|
||||
if inFile {
|
||||
f, err := os.Open(filepath.Clean(fileName))
|
||||
@@ -530,7 +530,7 @@ func TestRWMutex(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
var keys, values [][]byte
|
||||
@@ -783,7 +783,7 @@ func TestGetFromSnapshotExpectArboErrKeyNotFound(t *testing.T) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 256,
|
||||
HashFunction: HashFunctionPoseidon})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
bLen := 32
|
||||
k := BigIntToBytes(bLen, big.NewInt(int64(3)))
|
||||
@@ -953,7 +953,7 @@ func benchmarkAdd(b *testing.B, hashFunc HashFunction, ks, vs [][]byte) {
|
||||
tree, err := NewTree(Config{Database: database, MaxLevels: 140,
|
||||
HashFunction: hashFunc})
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close() //nolint:errcheck
|
||||
defer tree.treedb.Close() //nolint:errcheck
|
||||
|
||||
for i := 0; i < len(ks); i++ {
|
||||
if err := tree.Add(ks[i], vs[i]); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user