mirror of
https://github.com/arnaucube/kesto.git
synced 2026-02-06 19:16:44 +01:00
Add arbotree interface wrapper
This commit is contained in:
11
treeinterface/arbotree/go.mod
Normal file
11
treeinterface/arbotree/go.mod
Normal file
@@ -0,0 +1,11 @@
|
||||
module github.com/arnaucube/kesto/treeinterface/arbotree
|
||||
|
||||
go 1.16
|
||||
|
||||
// replace github.com/arnaucube/arbo => ../../../arbo
|
||||
|
||||
require (
|
||||
github.com/arnaucube/arbo v0.0.0-20210508150807-6dcbbdf4a51a // indirect
|
||||
github.com/iden3/go-merkletree v0.0.0-20210308143313-8b63ca866189
|
||||
go.vocdoni.io/dvote v0.6.1-0.20210508104027-72380d23da7f
|
||||
)
|
||||
2061
treeinterface/arbotree/go.sum
Normal file
2061
treeinterface/arbotree/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
142
treeinterface/arbotree/wrapper.go
Normal file
142
treeinterface/arbotree/wrapper.go
Normal file
@@ -0,0 +1,142 @@
|
||||
// Package arbotree provides the functions for creating and managing an arbo
|
||||
// merkletree adapted to the CensusTree interface
|
||||
package arbotree
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/arnaucube/arbo"
|
||||
"github.com/iden3/go-merkletree/db/pebble"
|
||||
"go.vocdoni.io/dvote/censustree"
|
||||
)
|
||||
|
||||
type Tree struct {
|
||||
Tree *arbo.Tree
|
||||
public uint32
|
||||
lastAccessUnix int64 // a unix timestamp, used via sync/atomic
|
||||
}
|
||||
|
||||
func (t *Tree) Init(name, storageDir string) error {
|
||||
dbDir := filepath.Join(storageDir, "arbotree.db."+strings.TrimSpace(name))
|
||||
storage, err := pebble.NewPebbleStorage(dbDir, false) // TODO TMP
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mt, err := arbo.NewTree(storage, 140, arbo.HashFunctionBlake2b) // TODO here the hash function would depend on the usage
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Tree = mt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tree) MaxKeySize() int {
|
||||
return t.Tree.HashFunction().Len()
|
||||
}
|
||||
|
||||
func (t *Tree) LastAccess() int64 {
|
||||
return atomic.LoadInt64(&t.lastAccessUnix)
|
||||
}
|
||||
|
||||
func (t *Tree) updateAccessTime() {
|
||||
atomic.StoreInt64(&t.lastAccessUnix, time.Now().Unix())
|
||||
}
|
||||
|
||||
// Publish makes a merkle tree available for queries.
|
||||
// Application layer should check IsPublish() before considering the Tree available.
|
||||
func (t *Tree) Publish() {
|
||||
atomic.StoreUint32(&t.public, 1)
|
||||
}
|
||||
|
||||
// UnPublish makes a merkle tree not available for queries
|
||||
func (t *Tree) UnPublish() {
|
||||
atomic.StoreUint32(&t.public, 0)
|
||||
}
|
||||
|
||||
// IsPublic returns true if the tree is available
|
||||
func (t *Tree) IsPublic() bool {
|
||||
return atomic.LoadUint32(&t.public) == 1
|
||||
}
|
||||
|
||||
func (t *Tree) Add(index, value []byte) error {
|
||||
t.updateAccessTime()
|
||||
return t.Tree.Add(index, value)
|
||||
}
|
||||
|
||||
func (t *Tree) AddBatch(indexes, values [][]byte) ([]int, error) {
|
||||
t.updateAccessTime()
|
||||
return t.Tree.AddBatch(indexes, values)
|
||||
}
|
||||
|
||||
func (t *Tree) GenProof(index, value []byte) ([]byte, error) {
|
||||
t.updateAccessTime()
|
||||
v, siblings, err := t.Tree.GenProof(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.Equal(v, value) {
|
||||
return nil, fmt.Errorf("value does not match %s!=%s", hex.EncodeToString(v), hex.EncodeToString(value))
|
||||
}
|
||||
return siblings, nil
|
||||
}
|
||||
|
||||
func (t *Tree) CheckProof(index, value, root, mproof []byte) (bool, error) {
|
||||
t.updateAccessTime()
|
||||
if root == nil {
|
||||
root = t.Root()
|
||||
}
|
||||
return arbo.CheckProof(t.Tree.HashFunction(), index, value, root, mproof)
|
||||
}
|
||||
|
||||
func (t *Tree) Root() []byte {
|
||||
t.updateAccessTime()
|
||||
return t.Tree.Root()
|
||||
}
|
||||
|
||||
func (t *Tree) Dump(root []byte) ([]byte, error) {
|
||||
return t.Tree.Dump() // TODO pass root once arbo is updated
|
||||
}
|
||||
|
||||
func (t *Tree) DumpPlain(root []byte) ([][]byte, [][]byte, error) {
|
||||
t.updateAccessTime()
|
||||
var indexes, values [][]byte
|
||||
// TODO pass root once arbo is updated
|
||||
err := t.Tree.Iterate(func(k, v []byte) {
|
||||
if v[0] != arbo.PrefixValueLeaf {
|
||||
return
|
||||
}
|
||||
leafK, leafV := arbo.ReadLeafValue(v)
|
||||
indexes = append(indexes, leafK)
|
||||
values = append(values, leafV)
|
||||
})
|
||||
return indexes, values, err
|
||||
}
|
||||
|
||||
func (t *Tree) ImportDump(data []byte) error {
|
||||
t.updateAccessTime()
|
||||
return t.Tree.ImportDump(data)
|
||||
}
|
||||
|
||||
func (t *Tree) Size(root []byte) (int64, error) {
|
||||
// TODO
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (t *Tree) Snapshot(root []byte) (censustree.Tree, error) {
|
||||
// TODO
|
||||
return t, nil
|
||||
}
|
||||
func (t *Tree) HashExists(hash []byte) (bool, error) {
|
||||
_, _, err := t.Tree.Get(hash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
22
treeinterface/arbotree/wrapper_test.go
Normal file
22
treeinterface/arbotree/wrapper_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package arbotree
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.vocdoni.io/dvote/censustree"
|
||||
)
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
storage := t.TempDir()
|
||||
tree := &Tree{}
|
||||
err := tree.Init("test", storage)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var i interface{} = tree
|
||||
_, ok := i.(censustree.Tree)
|
||||
if !ok {
|
||||
t.Fatal("censustree interface not matched by arbotree wrapper")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user