You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
11 KiB

  1. package asmtree
  2. import (
  3. "bytes"
  4. "fmt"
  5. "path"
  6. "sync/atomic"
  7. "time"
  8. "go.vocdoni.io/dvote/log"
  9. "go.vocdoni.io/proto/build/go/models"
  10. "git.sr.ht/~sircmpwn/go-bare"
  11. "github.com/p4u/asmt/db"
  12. asmt "github.com/p4u/asmt/smt"
  13. )
  14. // We use go-bare for export/import the trie. In order to support
  15. // big census (up to 8 Million entries) we need to increase the maximums.
  16. const bareMaxArrayLength uint64 = 1024 * 1014 * 8 // 8 Million
  17. const bareMaxUnmarshalBytes uint64 = bareMaxArrayLength * 32 * 2 // 512 MiB
  18. type Tree struct {
  19. Tree *asmt.Trie
  20. db db.DB
  21. public uint32
  22. lastAccessUnix int64 // a unix timestamp, used via sync/atomic
  23. size uint64
  24. snapshotRoot []byte // if not nil, this trie is considered an inmutable snapshot
  25. snapshotSize uint64
  26. }
  27. type Proof struct {
  28. Bitmap []byte
  29. Length int
  30. Siblings [][]byte
  31. Value []byte
  32. }
  33. type exportElement struct {
  34. Key []byte `bare:"key"`
  35. Value []byte `bare:"value"`
  36. }
  37. type exportData struct {
  38. Elements []exportElement `bare:"elements"`
  39. }
  40. const (
  41. MaxKeySize = 32
  42. MaxValueSize = 64
  43. dbRootPrefix = "this is the last root for the SMT tree"
  44. )
  45. // NewTree initializes a new AergoSMT tree following the Tree interface specification.
  46. func NewTree(name, storageDir string) (*Tree, error) {
  47. tr := &Tree{}
  48. err := tr.Init(name, storageDir)
  49. return tr, err
  50. }
  51. // newTree opens or creates a merkle tree under the given storage.
  52. func newTree(name, storageDir string) (*asmt.Trie, db.DB, error) {
  53. dir := path.Join(storageDir, name)
  54. log.Debugf("creating new tree on %s", dir)
  55. d := db.NewDB(db.LevelImpl, dir)
  56. root := d.Get([]byte(dbRootPrefix))
  57. tr := asmt.NewTrie(root, asmt.Hasher, d)
  58. if root != nil {
  59. if err := tr.LoadCache(root); err != nil {
  60. return nil, nil, err
  61. }
  62. }
  63. return tr, d, nil
  64. }
  65. // Init initializes a new asmt tree
  66. func (t *Tree) Init(name, storageDir string) error {
  67. var err error
  68. t.Tree, t.db, err = newTree(name, storageDir)
  69. t.updateAccessTime()
  70. t.size = 0
  71. return err
  72. }
  73. func (t *Tree) MaxKeySize() int {
  74. return MaxKeySize
  75. }
  76. // LastAccess returns the last time the Tree was accessed, in the form of a unix
  77. // timestamp.
  78. func (t *Tree) LastAccess() int64 {
  79. return atomic.LoadInt64(&t.lastAccessUnix)
  80. }
  81. func (t *Tree) updateAccessTime() {
  82. atomic.StoreInt64(&t.lastAccessUnix, time.Now().Unix())
  83. }
  84. // Publish makes a merkle tree available for queries.
  85. // Application layer should check IsPublish() before considering the Tree available.
  86. func (t *Tree) Publish() {
  87. atomic.StoreUint32(&t.public, 1)
  88. }
  89. // UnPublish makes a merkle tree not available for queries
  90. func (t *Tree) UnPublish() {
  91. atomic.StoreUint32(&t.public, 0)
  92. }
  93. // IsPublic returns true if the tree is available
  94. func (t *Tree) IsPublic() bool {
  95. return atomic.LoadUint32(&t.public) == 1
  96. }
  97. // Type returns the numeric identifier for the censusTree implementation
  98. func (t *Tree) Type() models.Census_Type {
  99. return models.Census_UNKNOWN
  100. }
  101. // TypeString returns the name identifying the censustree implementation
  102. func (t *Tree) TypeString() string {
  103. return models.Census_Type_name[int32(t.Type())] // reuse the naming generated by protobuf
  104. }
  105. // Commit saves permanently the tree on disk
  106. func (t *Tree) Commit() error {
  107. if t.snapshotRoot != nil {
  108. return fmt.Errorf("cannot commit to a snapshot trie")
  109. }
  110. err := t.Tree.Commit()
  111. if err != nil {
  112. return err
  113. }
  114. t.db.Set([]byte(dbRootPrefix), t.Root())
  115. return nil
  116. }
  117. // Add adds a new claim to the merkle tree
  118. // A claim is composed of two parts: index and value
  119. // 1.index is mandatory, the data will be used for indexing the claim into to merkle tree
  120. // 2.value is optional, the data will not affect the indexing
  121. func (t *Tree) Add(index, value []byte) error {
  122. t.updateAccessTime()
  123. if t.snapshotRoot != nil {
  124. return fmt.Errorf("cannot add to a snapshot trie")
  125. }
  126. if len(index) < 4 || len(index) > MaxKeySize {
  127. return fmt.Errorf("wrong key size: %d", len(index))
  128. }
  129. if len(value) > MaxValueSize {
  130. return fmt.Errorf("index or value claim data too big")
  131. }
  132. _, err := t.Tree.Update([][]byte{asmt.Hasher(index)}, [][]byte{asmt.Hasher(value)})
  133. if err != nil {
  134. return err
  135. }
  136. atomic.StoreUint64(&t.size, 0) // TBD: improve this
  137. return t.Commit()
  138. }
  139. // AddBatch adds a list of indexes and values.
  140. // The commit to disk is executed only once.
  141. // The values slince could be empty or as long as indexes.
  142. func (t *Tree) AddBatch(indexes, values [][]byte) ([]int, error) {
  143. var wrongIndexes []int
  144. t.updateAccessTime()
  145. if t.snapshotRoot != nil {
  146. return wrongIndexes, fmt.Errorf("cannot add to a snapshot trie")
  147. }
  148. if len(values) > 0 && len(indexes) != len(values) {
  149. return wrongIndexes, fmt.Errorf("indexes and values have different size")
  150. }
  151. var value []byte
  152. for i, key := range indexes {
  153. if len(key) < 4 || len(key) > MaxKeySize {
  154. wrongIndexes = append(wrongIndexes, i)
  155. continue
  156. }
  157. value = nil
  158. if len(values) > 0 {
  159. if len(values[i]) > MaxValueSize {
  160. wrongIndexes = append(wrongIndexes, i)
  161. continue
  162. }
  163. value = values[i]
  164. }
  165. _, err := t.Tree.Update([][]byte{asmt.Hasher(key)}, [][]byte{asmt.Hasher(value)})
  166. if err != nil {
  167. return wrongIndexes, err
  168. }
  169. }
  170. atomic.StoreUint64(&t.size, 0) // TBD: improve this
  171. return wrongIndexes, t.Commit()
  172. }
  173. // Get returns the value of a key
  174. func (t *Tree) Get(key []byte) []byte { // Do something with error
  175. var value []byte
  176. if t.snapshotRoot != nil {
  177. value, _ = t.Tree.GetWithRoot(key, t.snapshotRoot)
  178. } else {
  179. value, _ = t.Tree.Get(key)
  180. }
  181. return value
  182. }
  183. // GenProof generates a merkle tree proof that can be later used on CheckProof() to validate it.
  184. func (t *Tree) GenProof(index, value []byte) ([]byte, error) {
  185. t.updateAccessTime()
  186. var err error
  187. var ap [][]byte
  188. var pvalue, bitmap []byte
  189. var length int
  190. var included bool
  191. key := asmt.Hasher(index)
  192. if t.snapshotRoot != nil {
  193. bitmap, ap, length, included, _, pvalue, err = t.Tree.MerkleProofCompressedR(key,
  194. t.snapshotRoot)
  195. if err != nil {
  196. return nil, err
  197. }
  198. } else {
  199. bitmap, ap, length, included, _, pvalue, err = t.Tree.MerkleProofCompressed(key)
  200. if err != nil {
  201. return nil, err
  202. }
  203. }
  204. if !included {
  205. return nil, nil
  206. }
  207. if !bytes.Equal(pvalue, asmt.Hasher(value)) {
  208. return nil, fmt.Errorf("incorrect value or key on genProof")
  209. }
  210. return bare.Marshal(&Proof{Bitmap: bitmap, Length: length, Siblings: ap, Value: pvalue})
  211. }
  212. // CheckProof validates a merkle proof and its data.
  213. func (t *Tree) CheckProof(index, value, root, mproof []byte) (bool, error) {
  214. t.updateAccessTime()
  215. p := Proof{}
  216. if err := bare.Unmarshal(mproof, &p); err != nil {
  217. return false, err
  218. }
  219. if !bytes.Equal(p.Value, asmt.Hasher(value)) {
  220. return false, fmt.Errorf("values mismatch %x != %x", p.Value, asmt.Hasher(value))
  221. }
  222. if root != nil {
  223. return t.Tree.VerifyInclusionWithRootC(
  224. root,
  225. p.Bitmap,
  226. asmt.Hasher(index),
  227. p.Value,
  228. p.Siblings,
  229. p.Length), nil
  230. }
  231. if t.snapshotRoot != nil {
  232. return t.Tree.VerifyInclusionWithRootC(
  233. t.snapshotRoot,
  234. p.Bitmap,
  235. asmt.Hasher(index),
  236. p.Value,
  237. p.Siblings,
  238. p.Length), nil
  239. }
  240. return t.Tree.VerifyInclusionC(
  241. p.Bitmap,
  242. asmt.Hasher(index),
  243. p.Value,
  244. p.Siblings,
  245. p.Length), nil
  246. }
  247. // Root returns the current root hash of the merkle tree
  248. func (t *Tree) Root() []byte {
  249. t.updateAccessTime()
  250. if t.snapshotRoot != nil {
  251. return t.snapshotRoot
  252. }
  253. return t.Tree.Root
  254. }
  255. // Dump returns the whole merkle tree serialized in a format that can be used on Import.
  256. // Byte seralization is performed using bare message protocol, it is a 40% size win over JSON.
  257. func (t *Tree) Dump(root []byte) ([]byte, error) {
  258. t.updateAccessTime()
  259. if root == nil && t.snapshotRoot != nil {
  260. root = t.snapshotRoot
  261. }
  262. dump := exportData{}
  263. t.iterateWithRoot(root, nil, func(k, v []byte) bool {
  264. ee := exportElement{Key: make([]byte, len(k)), Value: make([]byte, len(v))}
  265. // Copy elements since it's not safe to hold on to the []byte values from Iterate
  266. copy(ee.Key, k[:])
  267. copy(ee.Value, v[:])
  268. dump.Elements = append(dump.Elements, ee)
  269. return false
  270. })
  271. bare.MaxArrayLength(bareMaxArrayLength)
  272. bare.MaxUnmarshalBytes(bareMaxUnmarshalBytes)
  273. return bare.Marshal(&dump)
  274. }
  275. // String returns a human readable representation of the tree.
  276. func (t *Tree) String() string {
  277. s := bytes.Buffer{}
  278. t.iterate(t.snapshotRoot, func(k, v []byte) bool {
  279. s.WriteString(fmt.Sprintf("%x => %x\n", k, v))
  280. return false
  281. })
  282. return s.String()
  283. }
  284. // Size returns the number of leaf nodes on the merkle tree.
  285. // TO-DO: root is currently ignored
  286. func (t *Tree) Size(root []byte) (int64, error) {
  287. if t.snapshotRoot != nil {
  288. return int64(t.snapshotSize), nil
  289. }
  290. return int64(t.count()), nil
  291. }
  292. // DumpPlain returns the entire list of added claims for a specific root hash.
  293. // First return parametre are the indexes and second the values.
  294. // If root is not specified, the last one is used.
  295. func (t *Tree) DumpPlain(root []byte) ([][]byte, [][]byte, error) {
  296. var indexes, values [][]byte
  297. var err error
  298. t.updateAccessTime()
  299. t.iterateWithRoot(root, nil, func(k, v []byte) bool {
  300. indexes = append(indexes, k)
  301. values = append(values, v)
  302. return false
  303. })
  304. return indexes, values, err
  305. }
  306. // ImportDump imports a partial or whole tree previously exported with Dump()
  307. func (t *Tree) ImportDump(data []byte) error {
  308. t.updateAccessTime()
  309. if t.snapshotRoot != nil {
  310. return fmt.Errorf("cannot import to a snapshot")
  311. }
  312. census := new(exportData)
  313. bare.MaxArrayLength(bareMaxArrayLength)
  314. bare.MaxUnmarshalBytes(bareMaxUnmarshalBytes)
  315. if err := bare.Unmarshal(data, census); err != nil {
  316. return fmt.Errorf("importdump cannot unmarshal data: %w", err)
  317. }
  318. keys := [][]byte{}
  319. values := [][]byte{}
  320. for _, ee := range census.Elements {
  321. keys = append(keys, ee.Key)
  322. values = append(values, ee.Value)
  323. }
  324. _, err := t.Tree.Update(keys, values)
  325. if err != nil {
  326. return err
  327. }
  328. atomic.StoreUint64(&t.size, 0) // TBD: improve this
  329. return t.Commit()
  330. }
  331. // Snapshot returns a Tree instance of a exiting merkle root.
  332. // A Snapshot cannot be modified.
  333. func (t *Tree) Snapshot(root []byte) (*Tree, error) {
  334. exist, err := t.HashExists(root)
  335. if err != nil {
  336. return nil, err
  337. }
  338. if !exist {
  339. return nil, fmt.Errorf("root %x does not exist, cannot build snapshot", root)
  340. }
  341. return &Tree{Tree: t.Tree, public: t.public, snapshotRoot: root, snapshotSize: t.count()}, nil
  342. }
  343. func (t *Tree) Close() error {
  344. t.db.Close()
  345. return nil
  346. }
  347. // HashExists checks if a hash exists as a node in the merkle tree
  348. func (t *Tree) HashExists(hash []byte) (bool, error) {
  349. t.updateAccessTime()
  350. return t.Tree.TrieRootExists(hash), nil
  351. }
  352. func (t *Tree) count() uint64 {
  353. if v := atomic.LoadUint64(&t.size); v != 0 {
  354. return v
  355. }
  356. counter := uint64(0)
  357. if err := t.Tree.Walk(t.snapshotRoot, func(*asmt.WalkResult) int32 {
  358. counter++
  359. return 0
  360. }); err != nil {
  361. return 0
  362. }
  363. atomic.StoreUint64(&t.size, counter)
  364. return counter
  365. }
  366. func (t *Tree) iterate(prefix []byte, callback func(key, value []byte) bool) {
  367. t.Tree.Walk(t.snapshotRoot, func(v *asmt.WalkResult) int32 {
  368. if callback(v.Key, v.Value) {
  369. return 1
  370. } else {
  371. return 0
  372. }
  373. })
  374. }
  375. func (t *Tree) iterateWithRoot(root, prefix []byte, callback func(key, value []byte) bool) {
  376. t.Tree.Walk(root, func(v *asmt.WalkResult) int32 {
  377. if callback(v.Key, v.Value) {
  378. return 1
  379. } else {
  380. return 0
  381. }
  382. })
  383. }