package tree
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"os/user"
|
|
|
|
common3 "github.com/iden3/go-iden3/common"
|
|
mkcore "github.com/iden3/go-iden3/core"
|
|
db "github.com/iden3/go-iden3/db"
|
|
merkletree "github.com/iden3/go-iden3/merkletree"
|
|
)
|
|
|
|
type Tree struct {
|
|
Storage string
|
|
Tree *merkletree.MerkleTree
|
|
DbStorage *db.LevelDbStorage
|
|
}
|
|
|
|
func (t *Tree) Init(namespace string) error {
|
|
if len(t.Storage) < 1 {
|
|
if len(namespace) < 1 {
|
|
return errors.New("namespace not valid")
|
|
}
|
|
usr, err := user.Current()
|
|
if err == nil {
|
|
t.Storage = usr.HomeDir + "/.dvote/census/" + namespace
|
|
} else {
|
|
t.Storage = "./dvoteTree/" + namespace
|
|
}
|
|
}
|
|
mtdb, err := db.NewLevelDbStorage(t.Storage, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mt, err := merkletree.NewMerkleTree(mtdb, 140)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DbStorage = mtdb
|
|
t.Tree = mt
|
|
return nil
|
|
}
|
|
|
|
func (t *Tree) Close() {
|
|
defer t.Tree.Storage().Close()
|
|
}
|
|
|
|
func (t *Tree) GetClaim(data []byte) (*mkcore.ClaimBasic, error) {
|
|
if len(data) > 496/8 {
|
|
return nil, errors.New("claim data too large")
|
|
}
|
|
for i := len(data); i <= 496/8; i++ {
|
|
data = append(data, byte('.'))
|
|
}
|
|
var indexSlot [400 / 8]byte
|
|
var dataSlot [496 / 8]byte
|
|
copy(indexSlot[:], data[:400/8])
|
|
copy(dataSlot[:], data[:496/8])
|
|
e := mkcore.NewClaimBasic(indexSlot, dataSlot)
|
|
return e, nil
|
|
}
|
|
|
|
func (t *Tree) AddClaim(data []byte) error {
|
|
e, err := t.GetClaim(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return t.Tree.Add(e.Entry())
|
|
}
|
|
|
|
func (t *Tree) GenProof(data []byte) (string, error) {
|
|
e, err := t.GetClaim(data)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
mp, err := t.Tree.GenerateProof(e.Entry().HIndex())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
mpHex := common3.HexEncode(mp.Bytes())
|
|
return mpHex, nil
|
|
}
|
|
|
|
func (t *Tree) CheckProof(data []byte, mpHex string) (bool, error) {
|
|
mpBytes, err := common3.HexDecode(mpHex)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
mp, err := merkletree.NewProofFromBytes(mpBytes)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
e, err := t.GetClaim(data)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return merkletree.VerifyProof(t.Tree.RootKey(), mp,
|
|
e.Entry().HIndex(), e.Entry().HValue()), nil
|
|
}
|
|
|
|
func (t *Tree) GetRoot() string {
|
|
return t.Tree.RootKey().String()
|
|
}
|
|
|
|
func (t *Tree) GetIndex(data []byte) (string, error) {
|
|
e, err := t.GetClaim(data)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
index, err := t.Tree.GetDataByIndex(e.Entry().HIndex())
|
|
return index.String(), err
|
|
}
|
|
|
|
/*
|
|
func (t *Tree) Dump() ([]string, error) {
|
|
var response []string
|
|
|
|
err := t.Tree.Walk(t.Tree.RootKey(), func(n *merkletree.Node) {
|
|
if n.Type == merkletree.NodeTypeLeaf {
|
|
rawValue := n.Value()
|
|
var cleanValue []byte
|
|
for i := 0; i < len(rawValue); i++ {
|
|
if rawValue[i] == byte('.') {
|
|
break
|
|
}
|
|
cleanValue = append(cleanValue, rawValue[i])
|
|
}
|
|
response = append(response, fmt.Sprintf("%s", cleanValue))
|
|
}
|
|
})
|
|
return response, err
|
|
}
|
|
*/
|
|
|
|
func (t *Tree) Dump() (string, error) {
|
|
w := bytes.NewBufferString("")
|
|
err := t.Tree.DumpClaims(w, nil) // as rootKey we can pass a nil pointer, and it will use the current RootKey
|
|
|
|
return w.String(), err
|
|
}
|
|
|
|
func (t *Tree) Snapshot(root string) (*Tree, error) {
|
|
var rootHash merkletree.Hash
|
|
copy(rootHash[:32], root)
|
|
mt, err := t.Tree.Snapshot(&rootHash)
|
|
snapshotTree := new(Tree)
|
|
snapshotTree.Tree = mt
|
|
return snapshotTree, err
|
|
}
|