go-dvote/tree/tree.go
tree/tree.goRaw
1package tree
2
3import (
4 "errors"
5 "fmt"
6 "os/user"
7 "strings"
8 "time"
9
10 common3 "github.com/vocdoni/go-iden3/common"
11 mkcore "github.com/vocdoni/go-iden3/core"
12 "github.com/vocdoni/go-iden3/db"
13 "github.com/vocdoni/go-iden3/merkletree"
14)
15
16type Tree struct {
17 Namespace string
18 Storage string
19 Tree *merkletree.MerkleTree
20 DbStorage *db.LevelDbStorage
21}
22
23func (t *Tree) Init() error {
24 if len(t.Storage) < 1 {
25 usr, err := user.Current()
26 if err == nil {
27 t.Storage = usr.HomeDir + "/.dvote/Tree"
28 } else {
29 t.Storage = "./dvoteTree"
30 }
31 }
32 mtdb, err := db.NewLevelDbStorage(t.Storage, false)
33 if err != nil {
34 return err
35 }
36 mt, err := merkletree.New(mtdb, 140)
37 if err != nil {
38 return err
39 }
40 t.DbStorage = mtdb
41 t.Tree = mt
42 return nil
43}
44
45func (t *Tree) Close() {
46 defer t.Tree.Storage().Close()
47}
48
49func (t *Tree) AddClaim(data []byte) error {
50 isSnapshot := strings.Contains(t.Namespace, "snapshot.")
51 if isSnapshot {
52 return errors.New("No new claims can be added to a Snapshot")
53 }
54 claim := mkcore.NewGenericClaim(t.Namespace, "default", data, nil)
55 return t.Tree.Add(claim)
56}
57
58func (t *Tree) GenProof(data []byte) (string, error) {
59 claim := mkcore.NewGenericClaim(t.Namespace, "default", data, nil)
60 mp, err := t.Tree.GenerateProof(claim.Hi())
61 if err != nil {
62 return "", err
63 }
64 mpHex := common3.BytesToHex(mp)
65 return mpHex, nil
66}
67
68func (t *Tree) CheckProof(data []byte, mpHex string) (bool, error) {
69 mp, err := common3.HexToBytes(mpHex)
70 if err != nil {
71 return false, err
72 }
73 claim := mkcore.NewGenericClaim(t.Namespace, "default", data, nil)
74 return merkletree.CheckProof(t.Tree.Root(), mp, claim.Hi(), claim.Ht(), t.Tree.NumLevels()), nil
75}
76
77func (t *Tree) GetRoot() string {
78 return t.Tree.Root().Hex()
79}
80
81/* Dump, Export and Snapshot functions are a bit tricky.
82 Since go-iden3 does not provide the necessary tools. Low level operations must be performed.
83 Once go-iden3 API is mature enough, these functions must be adapted.
84
85 To explore: Values are stored twice in the BD?
86*/
87func (t *Tree) Dump() ([]string, error) {
88 var response []string
89 substorage := t.DbStorage.WithPrefix([]byte(t.Namespace))
90 nsHash := merkletree.HashBytes([]byte(t.Namespace))
91 substorage.Iterate(func(key, value []byte) {
92 nsValue := value[5:37]
93 if fmt.Sprint(nsHash) == fmt.Sprint(nsValue) {
94 response = append(response, string(value[69:]))
95 }
96 })
97 return response, nil
98}
99
100func (t *Tree) Snapshot() (string, error) {
101 substorage := t.DbStorage.WithPrefix([]byte(t.Namespace))
102 nsHash := merkletree.HashBytes([]byte(t.Namespace))
103 currentTime := int64(time.Now().Unix())
104 snapshotNamespace := fmt.Sprintf("snapshot.%s.%d", t.Namespace, currentTime)
105 substorage.Iterate(func(key, value []byte) {
106 nsValue := value[5:37]
107 if fmt.Sprint(nsHash) == fmt.Sprint(nsValue) {
108 data := value[69:]
109 //fmt.Printf(" Adding value: %s\n", data)
110 claim := mkcore.NewGenericClaim(snapshotNamespace, "default", data, nil)
111 err := t.Tree.Add(claim)
112 if err != nil {
113 fmt.Println(err)
114 }
115 }
116 })
117 return snapshotNamespace, nil
118}