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.

1070 lines
28 KiB

  1. package arbo
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "fmt"
  6. "math/big"
  7. "runtime"
  8. "sort"
  9. "testing"
  10. "time"
  11. qt "github.com/frankban/quicktest"
  12. "go.vocdoni.io/dvote/db"
  13. "go.vocdoni.io/dvote/db/badgerdb"
  14. "go.vocdoni.io/dvote/db/pebbledb"
  15. )
  16. var debug = true
  17. func printTestContext(prefix string, nLeafs int, hashName, dbName string) {
  18. if debug {
  19. fmt.Printf("%snCPU: %d, nLeafs: %d, hash: %s, db: %s\n",
  20. prefix, runtime.NumCPU(), nLeafs, hashName, dbName)
  21. }
  22. }
  23. func printRes(name string, duration time.Duration) {
  24. if debug {
  25. fmt.Printf("%s: %s \n", name, duration)
  26. }
  27. }
  28. func debugTime(descr string, time1, time2 time.Duration) {
  29. if debug {
  30. fmt.Printf("%s was %.02fx times faster than without AddBatch\n",
  31. descr, float64(time1)/float64(time2))
  32. }
  33. }
  34. func testInit(c *qt.C, n int) (*Tree, *Tree) {
  35. database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
  36. c.Assert(err, qt.IsNil)
  37. tree1, err := NewTree(database1, 256, HashFunctionPoseidon)
  38. c.Assert(err, qt.IsNil)
  39. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  40. c.Assert(err, qt.IsNil)
  41. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  42. c.Assert(err, qt.IsNil)
  43. bLen := HashFunctionPoseidon.Len()
  44. // add the initial leafs to fill a bit the trees before calling the
  45. // AddBatch method
  46. for i := 0; i < n; i++ {
  47. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  48. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  49. if err := tree1.Add(k, v); err != nil {
  50. c.Fatal(err)
  51. }
  52. if err := tree2.Add(k, v); err != nil {
  53. c.Fatal(err)
  54. }
  55. }
  56. return tree1, tree2
  57. }
  58. func TestAddBatchTreeEmpty(t *testing.T) {
  59. c := qt.New(t)
  60. nLeafs := 1024
  61. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  62. c.Assert(err, qt.IsNil)
  63. tree, err := NewTree(database, 256, HashFunctionPoseidon)
  64. c.Assert(err, qt.IsNil)
  65. defer tree.db.Close() //nolint:errcheck
  66. bLen := 32
  67. var keys, values [][]byte
  68. for i := 0; i < nLeafs; i++ {
  69. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  70. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  71. keys = append(keys, k)
  72. values = append(values, v)
  73. }
  74. start := time.Now()
  75. for i := 0; i < nLeafs; i++ {
  76. if err := tree.Add(keys[i], values[i]); err != nil {
  77. t.Fatal(err)
  78. }
  79. }
  80. time1 := time.Since(start)
  81. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  82. c.Assert(err, qt.IsNil)
  83. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  84. c.Assert(err, qt.IsNil)
  85. defer tree2.db.Close() //nolint:errcheck
  86. tree2.dbgInit()
  87. start = time.Now()
  88. invalids, err := tree2.AddBatch(keys, values)
  89. c.Assert(err, qt.IsNil)
  90. time2 := time.Since(start)
  91. if debug {
  92. debugTime("Case tree empty, AddBatch", time1, time2)
  93. printTestContext(" ", nLeafs, "Poseidon", "memory")
  94. tree2.dbg.print(" ")
  95. }
  96. c.Check(len(invalids), qt.Equals, 0)
  97. // check that both trees roots are equal
  98. checkRoots(c, tree, tree2)
  99. }
  100. func TestAddBatchTreeEmptyNotPowerOf2(t *testing.T) {
  101. c := qt.New(t)
  102. nLeafs := 1027
  103. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  104. c.Assert(err, qt.IsNil)
  105. tree, err := NewTree(database, 256, HashFunctionPoseidon)
  106. c.Assert(err, qt.IsNil)
  107. defer tree.db.Close() //nolint:errcheck
  108. bLen := 32
  109. for i := 0; i < nLeafs; i++ {
  110. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  111. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  112. if err := tree.Add(k, v); err != nil {
  113. t.Fatal(err)
  114. }
  115. }
  116. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  117. c.Assert(err, qt.IsNil)
  118. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  119. c.Assert(err, qt.IsNil)
  120. defer tree2.db.Close() //nolint:errcheck
  121. var keys, values [][]byte
  122. for i := 0; i < nLeafs; i++ {
  123. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  124. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  125. keys = append(keys, k)
  126. values = append(values, v)
  127. }
  128. invalids, err := tree2.AddBatch(keys, values)
  129. c.Assert(err, qt.IsNil)
  130. c.Check(len(invalids), qt.Equals, 0)
  131. // check that both trees roots are equal
  132. checkRoots(c, tree, tree2)
  133. }
  134. func randomBytes(n int) []byte {
  135. b := make([]byte, n)
  136. _, err := rand.Read(b)
  137. if err != nil {
  138. panic(err)
  139. }
  140. return b
  141. }
  142. func TestAddBatchTestVector1(t *testing.T) {
  143. c := qt.New(t)
  144. database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
  145. c.Assert(err, qt.IsNil)
  146. tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
  147. c.Assert(err, qt.IsNil)
  148. defer tree1.db.Close() //nolint:errcheck
  149. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  150. c.Assert(err, qt.IsNil)
  151. tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
  152. c.Assert(err, qt.IsNil)
  153. defer tree2.db.Close() //nolint:errcheck
  154. // leafs in 2nd level subtrees: [ 6, 0, 1, 1]
  155. testvectorKeys := []string{
  156. "1c7c2265e368314ca58ed2e1f33a326f1220e234a566d55c3605439dbe411642",
  157. "2c9f0a578afff5bfa4e0992a43066460faaab9e8e500db0b16647c701cdb16bf",
  158. "1c45cb31f2fa39ec7b9ebf0fad40e0b8296016b5ce8844ae06ff77226379d9a5",
  159. "d8af98bbbb585129798ae54d5eabbc9d0561d583faf1663b3a3724d15bda4ec7",
  160. }
  161. var keys, values [][]byte
  162. for i := 0; i < len(testvectorKeys); i++ {
  163. key, err := hex.DecodeString(testvectorKeys[i])
  164. c.Assert(err, qt.IsNil)
  165. keys = append(keys, key)
  166. values = append(values, []byte{0})
  167. }
  168. for i := 0; i < len(keys); i++ {
  169. if err := tree1.Add(keys[i], values[i]); err != nil {
  170. t.Fatal(err)
  171. }
  172. }
  173. invalids, err := tree2.AddBatch(keys, values)
  174. c.Assert(err, qt.IsNil)
  175. c.Check(len(invalids), qt.Equals, 0)
  176. // check that both trees roots are equal
  177. checkRoots(c, tree1, tree2)
  178. // 2nd test vectors
  179. database1, err = badgerdb.New(db.Options{Path: c.TempDir()})
  180. c.Assert(err, qt.IsNil)
  181. tree1, err = NewTree(database1, 256, HashFunctionBlake2b)
  182. c.Assert(err, qt.IsNil)
  183. defer tree1.db.Close() //nolint:errcheck
  184. database2, err = badgerdb.New(db.Options{Path: c.TempDir()})
  185. c.Assert(err, qt.IsNil)
  186. tree2, err = NewTree(database2, 256, HashFunctionBlake2b)
  187. c.Assert(err, qt.IsNil)
  188. defer tree2.db.Close() //nolint:errcheck
  189. testvectorKeys = []string{
  190. "1c7c2265e368314ca58ed2e1f33a326f1220e234a566d55c3605439dbe411642",
  191. "2c9f0a578afff5bfa4e0992a43066460faaab9e8e500db0b16647c701cdb16bf",
  192. "9cb87ec67e875c61390edcd1ab517f443591047709a4d4e45b0f9ed980857b8e",
  193. "9b4e9e92e974a589f426ceeb4cb291dc24893513fecf8e8460992dcf52621d4d",
  194. "1c45cb31f2fa39ec7b9ebf0fad40e0b8296016b5ce8844ae06ff77226379d9a5",
  195. "d8af98bbbb585129798ae54d5eabbc9d0561d583faf1663b3a3724d15bda4ec7",
  196. "3cd55dbfb8f975f20a0925dfbdabe79fa2d51dd0268afbb8ba6b01de9dfcdd3c",
  197. "5d0a9d6d9f197c091bf054fac9cb60e11ec723d6610ed8578e617b4d46cb43d5",
  198. }
  199. keys = [][]byte{}
  200. values = [][]byte{}
  201. for i := 0; i < len(testvectorKeys); i++ {
  202. key, err := hex.DecodeString(testvectorKeys[i])
  203. c.Assert(err, qt.IsNil)
  204. keys = append(keys, key)
  205. values = append(values, []byte{0})
  206. }
  207. for i := 0; i < len(keys); i++ {
  208. if err := tree1.Add(keys[i], values[i]); err != nil {
  209. t.Fatal(err)
  210. }
  211. }
  212. invalids, err = tree2.AddBatch(keys, values)
  213. c.Assert(err, qt.IsNil)
  214. c.Check(len(invalids), qt.Equals, 0)
  215. // check that both trees roots are equal
  216. checkRoots(c, tree1, tree2)
  217. }
  218. func TestAddBatchTestVector2(t *testing.T) {
  219. // test vector with unbalanced tree
  220. c := qt.New(t)
  221. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  222. c.Assert(err, qt.IsNil)
  223. tree1, err := NewTree(database, 256, HashFunctionPoseidon)
  224. c.Assert(err, qt.IsNil)
  225. defer tree1.db.Close() //nolint:errcheck
  226. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  227. c.Assert(err, qt.IsNil)
  228. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  229. c.Assert(err, qt.IsNil)
  230. defer tree2.db.Close() //nolint:errcheck
  231. bLen := tree1.HashFunction().Len()
  232. var keys, values [][]byte
  233. // 1
  234. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(1))))
  235. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(1))))
  236. // 2
  237. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(2))))
  238. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(2))))
  239. // 3
  240. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(3))))
  241. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(3))))
  242. // 5
  243. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(5))))
  244. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(5))))
  245. for i := 0; i < len(keys); i++ {
  246. if err := tree1.Add(keys[i], values[i]); err != nil {
  247. t.Fatal(err)
  248. }
  249. }
  250. invalids, err := tree2.AddBatch(keys, values)
  251. c.Assert(err, qt.IsNil)
  252. c.Check(len(invalids), qt.Equals, 0)
  253. // check that both trees roots are equal
  254. checkRoots(c, tree1, tree2)
  255. }
  256. func TestAddBatchTestVector3(t *testing.T) {
  257. // test vector with unbalanced tree
  258. c := qt.New(t)
  259. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  260. c.Assert(err, qt.IsNil)
  261. tree1, err := NewTree(database, 256, HashFunctionPoseidon)
  262. c.Assert(err, qt.IsNil)
  263. defer tree1.db.Close() //nolint:errcheck
  264. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  265. c.Assert(err, qt.IsNil)
  266. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  267. c.Assert(err, qt.IsNil)
  268. defer tree2.db.Close() //nolint:errcheck
  269. bLen := tree1.HashFunction().Len()
  270. var keys, values [][]byte
  271. // 0
  272. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(0))))
  273. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(0))))
  274. // 3
  275. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(3))))
  276. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(3))))
  277. // 7
  278. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(7))))
  279. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(7))))
  280. // 135
  281. keys = append(keys, BigIntToBytes(bLen, big.NewInt(int64(135))))
  282. values = append(values, BigIntToBytes(bLen, big.NewInt(int64(135))))
  283. for i := 0; i < len(keys); i++ {
  284. if err := tree1.Add(keys[i], values[i]); err != nil {
  285. t.Fatal(err)
  286. }
  287. }
  288. invalids, err := tree2.AddBatch(keys, values)
  289. c.Assert(err, qt.IsNil)
  290. c.Check(len(invalids), qt.Equals, 0)
  291. // check that both trees roots are equal
  292. checkRoots(c, tree1, tree2)
  293. //
  294. // tree1.PrintGraphvizFirstNLevels(nil, 100)
  295. // tree2.PrintGraphvizFirstNLevels(nil, 100)
  296. }
  297. func TestAddBatchTreeEmptyRandomKeys(t *testing.T) {
  298. c := qt.New(t)
  299. nLeafs := 8
  300. database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
  301. c.Assert(err, qt.IsNil)
  302. tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
  303. c.Assert(err, qt.IsNil)
  304. defer tree1.db.Close() //nolint:errcheck
  305. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  306. c.Assert(err, qt.IsNil)
  307. tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
  308. c.Assert(err, qt.IsNil)
  309. defer tree2.db.Close() //nolint:errcheck
  310. var keys, values [][]byte
  311. for i := 0; i < nLeafs; i++ {
  312. keys = append(keys, randomBytes(32))
  313. values = append(values, randomBytes(32))
  314. }
  315. for i := 0; i < len(keys); i++ {
  316. if err := tree1.Add(keys[i], values[i]); err != nil {
  317. t.Fatal(err)
  318. }
  319. }
  320. invalids, err := tree2.AddBatch(keys, values)
  321. c.Assert(err, qt.IsNil)
  322. c.Check(len(invalids), qt.Equals, 0)
  323. // check that both trees roots are equal
  324. checkRoots(c, tree1, tree2)
  325. }
  326. func TestAddBatchTreeNotEmptyFewLeafs(t *testing.T) {
  327. c := qt.New(t)
  328. nLeafs := 1024
  329. initialNLeafs := 99
  330. tree1, tree2 := testInit(c, initialNLeafs)
  331. tree2.dbgInit()
  332. bLen := tree1.HashFunction().Len()
  333. start := time.Now()
  334. for i := initialNLeafs; i < nLeafs; i++ {
  335. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  336. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  337. if err := tree1.Add(k, v); err != nil {
  338. t.Fatal(err)
  339. }
  340. }
  341. time1 := time.Since(start)
  342. // prepare the key-values to be added
  343. var keys, values [][]byte
  344. for i := initialNLeafs; i < nLeafs; i++ {
  345. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  346. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  347. keys = append(keys, k)
  348. values = append(values, v)
  349. }
  350. start = time.Now()
  351. invalids, err := tree2.AddBatch(keys, values)
  352. c.Assert(err, qt.IsNil)
  353. time2 := time.Since(start)
  354. if debug {
  355. debugTime("Case tree not empty w/ few leafs, AddBatch", time1, time2)
  356. printTestContext(" ", nLeafs, "Poseidon", "memory")
  357. tree2.dbg.print(" ")
  358. }
  359. c.Check(len(invalids), qt.Equals, 0)
  360. // check that both trees roots are equal
  361. checkRoots(c, tree1, tree2)
  362. }
  363. func TestAddBatchTreeNotEmptyEnoughLeafs(t *testing.T) {
  364. c := qt.New(t)
  365. nLeafs := 1024
  366. initialNLeafs := 500
  367. tree1, tree2 := testInit(c, initialNLeafs)
  368. tree2.dbgInit()
  369. bLen := tree1.HashFunction().Len()
  370. start := time.Now()
  371. for i := initialNLeafs; i < nLeafs; i++ {
  372. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  373. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  374. if err := tree1.Add(k, v); err != nil {
  375. t.Fatal(err)
  376. }
  377. }
  378. time1 := time.Since(start)
  379. // prepare the key-values to be added
  380. var keys, values [][]byte
  381. for i := initialNLeafs; i < nLeafs; i++ {
  382. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  383. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  384. keys = append(keys, k)
  385. values = append(values, v)
  386. }
  387. start = time.Now()
  388. invalids, err := tree2.AddBatch(keys, values)
  389. c.Assert(err, qt.IsNil)
  390. time2 := time.Since(start)
  391. if debug {
  392. debugTime("Case tree not empty w/ enough leafs, AddBatch", time1, time2)
  393. printTestContext(" ", nLeafs, "Poseidon", "memory")
  394. tree2.dbg.print(" ")
  395. }
  396. c.Check(len(invalids), qt.Equals, 0)
  397. // check that both trees roots are equal
  398. checkRoots(c, tree1, tree2)
  399. }
  400. func TestAddBatchTreeEmptyRepeatedLeafs(t *testing.T) {
  401. c := qt.New(t)
  402. nLeafs := 1024
  403. nRepeatedKeys := 99
  404. tree1, tree2 := testInit(c, 0)
  405. bLen := tree1.HashFunction().Len()
  406. // prepare the key-values to be added
  407. var keys, values [][]byte
  408. for i := 0; i < nLeafs; i++ {
  409. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  410. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  411. keys = append(keys, k)
  412. values = append(values, v)
  413. }
  414. // add repeated key-values
  415. for i := 0; i < nRepeatedKeys; i++ {
  416. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  417. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  418. keys = append(keys, k)
  419. values = append(values, v)
  420. }
  421. // add the non-repeated key-values in tree1 with .Add loop
  422. for i := 0; i < nLeafs; i++ {
  423. if err := tree1.Add(keys[i], values[i]); err != nil {
  424. t.Fatal(err)
  425. }
  426. }
  427. invalids, err := tree2.AddBatch(keys, values)
  428. c.Assert(err, qt.IsNil)
  429. c.Check(len(invalids), qt.Equals, nRepeatedKeys)
  430. // check that both trees roots are equal
  431. checkRoots(c, tree1, tree2)
  432. }
  433. func TestAddBatchTreeNotEmptyFewLeafsRepeatedLeafs(t *testing.T) {
  434. c := qt.New(t)
  435. nLeafs := 1024
  436. initialNLeafs := 99
  437. tree1, tree2 := testInit(c, initialNLeafs)
  438. bLen := tree1.HashFunction().Len()
  439. // prepare the key-values to be added
  440. var keys, values [][]byte
  441. for i := 0; i < nLeafs; i++ {
  442. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  443. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  444. keys = append(keys, k)
  445. values = append(values, v)
  446. }
  447. // add the keys that will be existing when AddBatch is called
  448. for i := initialNLeafs; i < nLeafs; i++ {
  449. if err := tree1.Add(keys[i], values[i]); err != nil {
  450. t.Fatal(err)
  451. }
  452. }
  453. invalids, err := tree2.AddBatch(keys, values)
  454. c.Assert(err, qt.IsNil)
  455. c.Assert(len(invalids), qt.Equals, initialNLeafs)
  456. // check that both trees roots are equal
  457. checkRoots(c, tree1, tree2)
  458. }
  459. func TestSplitInBuckets(t *testing.T) {
  460. c := qt.New(t)
  461. bLen := HashFunctionPoseidon.Len()
  462. nLeafs := 16
  463. kvs := make([]kv, nLeafs)
  464. for i := 0; i < nLeafs; i++ {
  465. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  466. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  467. keyPath := make([]byte, 32)
  468. copy(keyPath[:], k)
  469. kvs[i].pos = i
  470. kvs[i].keyPath = k
  471. kvs[i].k = k
  472. kvs[i].v = v
  473. }
  474. // check keyToBucket results for 4 buckets & 8 keys
  475. c.Assert(keyToBucket(kvs[0].k, 4), qt.Equals, 0)
  476. c.Assert(keyToBucket(kvs[1].k, 4), qt.Equals, 2)
  477. c.Assert(keyToBucket(kvs[2].k, 4), qt.Equals, 1)
  478. c.Assert(keyToBucket(kvs[3].k, 4), qt.Equals, 3)
  479. c.Assert(keyToBucket(kvs[4].k, 4), qt.Equals, 0)
  480. c.Assert(keyToBucket(kvs[5].k, 4), qt.Equals, 2)
  481. c.Assert(keyToBucket(kvs[6].k, 4), qt.Equals, 1)
  482. c.Assert(keyToBucket(kvs[7].k, 4), qt.Equals, 3)
  483. // check keyToBucket results for 8 buckets & 8 keys
  484. c.Assert(keyToBucket(kvs[0].k, 8), qt.Equals, 0)
  485. c.Assert(keyToBucket(kvs[1].k, 8), qt.Equals, 4)
  486. c.Assert(keyToBucket(kvs[2].k, 8), qt.Equals, 2)
  487. c.Assert(keyToBucket(kvs[3].k, 8), qt.Equals, 6)
  488. c.Assert(keyToBucket(kvs[4].k, 8), qt.Equals, 1)
  489. c.Assert(keyToBucket(kvs[5].k, 8), qt.Equals, 5)
  490. c.Assert(keyToBucket(kvs[6].k, 8), qt.Equals, 3)
  491. c.Assert(keyToBucket(kvs[7].k, 8), qt.Equals, 7)
  492. buckets := splitInBuckets(kvs, 4)
  493. expected := [][]string{
  494. {
  495. "00000000", // bucket 0
  496. "08000000",
  497. "04000000",
  498. "0c000000",
  499. },
  500. {
  501. "02000000", // bucket 1
  502. "0a000000",
  503. "06000000",
  504. "0e000000",
  505. },
  506. {
  507. "01000000", // bucket 2
  508. "09000000",
  509. "05000000",
  510. "0d000000",
  511. },
  512. {
  513. "03000000", // bucket 3
  514. "0b000000",
  515. "07000000",
  516. "0f000000",
  517. },
  518. }
  519. for i := 0; i < len(buckets); i++ {
  520. sortKvs(buckets[i])
  521. c.Assert(len(buckets[i]), qt.Equals, len(expected[i]))
  522. for j := 0; j < len(buckets[i]); j++ {
  523. c.Check(hex.EncodeToString(buckets[i][j].k[:4]),
  524. qt.Equals, expected[i][j])
  525. }
  526. }
  527. }
  528. // compareBytes compares byte slices where the bytes are compared from left to
  529. // right and each byte is compared by bit from right to left
  530. func compareBytes(a, b []byte) bool {
  531. // WIP
  532. for i := 0; i < len(a); i++ {
  533. for j := 0; j < 8; j++ {
  534. aBit := a[i] & (1 << j)
  535. bBit := b[i] & (1 << j)
  536. if aBit > bBit {
  537. return false
  538. } else if aBit < bBit {
  539. return true
  540. }
  541. }
  542. }
  543. return false
  544. }
  545. // sortKvs sorts the kv by path
  546. func sortKvs(kvs []kv) {
  547. sort.Slice(kvs, func(i, j int) bool {
  548. return compareBytes(kvs[i].keyPath, kvs[j].keyPath)
  549. })
  550. }
  551. func TestAddBatchTreeNotEmpty(t *testing.T) {
  552. c := qt.New(t)
  553. nLeafs := 4096
  554. initialNLeafs := 900
  555. tree1, tree2 := testInit(c, initialNLeafs)
  556. tree2.dbgInit()
  557. bLen := tree1.HashFunction().Len()
  558. start := time.Now()
  559. for i := initialNLeafs; i < nLeafs; i++ {
  560. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  561. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  562. if err := tree1.Add(k, v); err != nil {
  563. t.Fatal(err)
  564. }
  565. }
  566. time1 := time.Since(start)
  567. // prepare the key-values to be added
  568. var keys, values [][]byte
  569. for i := initialNLeafs; i < nLeafs; i++ {
  570. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  571. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  572. keys = append(keys, k)
  573. values = append(values, v)
  574. }
  575. start = time.Now()
  576. invalids, err := tree2.AddBatch(keys, values)
  577. c.Assert(err, qt.IsNil)
  578. time2 := time.Since(start)
  579. if debug {
  580. debugTime("Case tree not empty, AddBatch", time1, time2)
  581. printTestContext(" ", nLeafs, "Poseidon", "memory")
  582. tree2.dbg.print(" ")
  583. }
  584. c.Check(len(invalids), qt.Equals, 0)
  585. // check that both trees roots are equal
  586. checkRoots(c, tree1, tree2)
  587. }
  588. func TestAddBatchNotEmptyUnbalanced(t *testing.T) {
  589. c := qt.New(t)
  590. nLeafs := 4096
  591. initialNLeafs := 900
  592. tree1, _ := testInit(c, initialNLeafs)
  593. bLen := tree1.HashFunction().Len()
  594. start := time.Now()
  595. for i := initialNLeafs; i < nLeafs; i++ {
  596. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  597. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  598. if err := tree1.Add(k, v); err != nil {
  599. t.Fatal(err)
  600. }
  601. }
  602. time1 := time.Since(start)
  603. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  604. c.Assert(err, qt.IsNil)
  605. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  606. c.Assert(err, qt.IsNil)
  607. defer tree2.db.Close() //nolint:errcheck
  608. tree2.dbgInit()
  609. var keys, values [][]byte
  610. // add the initial leafs to fill a bit the tree before calling the
  611. // AddBatch method
  612. for i := 0; i < initialNLeafs; i++ {
  613. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  614. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  615. // use only the keys of one bucket, store the not used ones for
  616. // later
  617. if i%4 != 0 {
  618. keys = append(keys, k)
  619. values = append(values, v)
  620. continue
  621. }
  622. if err := tree2.Add(k, v); err != nil {
  623. t.Fatal(err)
  624. }
  625. }
  626. for i := initialNLeafs; i < nLeafs; i++ {
  627. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  628. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  629. keys = append(keys, k)
  630. values = append(values, v)
  631. }
  632. start = time.Now()
  633. invalids, err := tree2.AddBatch(keys, values)
  634. c.Assert(err, qt.IsNil)
  635. time2 := time.Since(start)
  636. if debug {
  637. debugTime("Case tree not empty & unbalanced, AddBatch", time1, time2)
  638. printTestContext(" ", nLeafs, "Poseidon", "memory")
  639. tree2.dbg.print(" ")
  640. }
  641. c.Check(len(invalids), qt.Equals, 0)
  642. // check that both trees roots are equal
  643. checkRoots(c, tree1, tree2)
  644. }
  645. func TestFlp2(t *testing.T) {
  646. c := qt.New(t)
  647. c.Assert(flp2(31), qt.Equals, 16)
  648. c.Assert(flp2(32), qt.Equals, 32)
  649. c.Assert(flp2(33), qt.Equals, 32)
  650. c.Assert(flp2(63), qt.Equals, 32)
  651. c.Assert(flp2(64), qt.Equals, 64)
  652. c.Assert(flp2(9000), qt.Equals, 8192)
  653. }
  654. func TestAddBatchBench(t *testing.T) {
  655. nLeafs := 50_000
  656. printTestContext("TestAddBatchBench: ", nLeafs, "Blake2b", "badgerdb")
  657. // prepare inputs
  658. var ks, vs [][]byte
  659. for i := 0; i < nLeafs; i++ {
  660. k := randomBytes(32)
  661. v := randomBytes(32)
  662. ks = append(ks, k)
  663. vs = append(vs, v)
  664. }
  665. benchAdd(t, ks, vs)
  666. benchAddBatch(t, ks, vs)
  667. }
  668. func benchAdd(t *testing.T, ks, vs [][]byte) {
  669. c := qt.New(t)
  670. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  671. c.Assert(err, qt.IsNil)
  672. tree, err := NewTree(database, 256, HashFunctionBlake2b)
  673. c.Assert(err, qt.IsNil)
  674. defer tree.db.Close() //nolint:errcheck
  675. start := time.Now()
  676. for i := 0; i < len(ks); i++ {
  677. err = tree.Add(ks[i], vs[i])
  678. c.Assert(err, qt.IsNil)
  679. }
  680. if debug {
  681. printRes(" Add loop", time.Since(start))
  682. tree.dbg.print(" ")
  683. }
  684. }
  685. func benchAddBatch(t *testing.T, ks, vs [][]byte) {
  686. c := qt.New(t)
  687. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  688. c.Assert(err, qt.IsNil)
  689. tree, err := NewTree(database, 256, HashFunctionBlake2b)
  690. c.Assert(err, qt.IsNil)
  691. defer tree.db.Close() //nolint:errcheck
  692. tree.dbgInit()
  693. start := time.Now()
  694. invalids, err := tree.AddBatch(ks, vs)
  695. if debug {
  696. printRes(" AddBatch", time.Since(start))
  697. tree.dbg.print(" ")
  698. }
  699. c.Assert(err, qt.IsNil)
  700. c.Assert(len(invalids), qt.Equals, 0)
  701. }
  702. func TestDbgStats(t *testing.T) {
  703. c := qt.New(t)
  704. nLeafs := 10_000
  705. // prepare inputs
  706. var ks, vs [][]byte
  707. for i := 0; i < nLeafs; i++ {
  708. k := randomBytes(32)
  709. v := randomBytes(32)
  710. ks = append(ks, k)
  711. vs = append(vs, v)
  712. }
  713. // 1
  714. database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
  715. c.Assert(err, qt.IsNil)
  716. tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
  717. c.Assert(err, qt.IsNil)
  718. defer tree1.db.Close() //nolint:errcheck
  719. tree1.dbgInit()
  720. for i := 0; i < len(ks); i++ {
  721. err = tree1.Add(ks[i], vs[i])
  722. c.Assert(err, qt.IsNil)
  723. }
  724. // 2
  725. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  726. c.Assert(err, qt.IsNil)
  727. tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
  728. c.Assert(err, qt.IsNil)
  729. defer tree2.db.Close() //nolint:errcheck
  730. tree2.dbgInit()
  731. invalids, err := tree2.AddBatch(ks, vs)
  732. c.Assert(err, qt.IsNil)
  733. c.Assert(len(invalids), qt.Equals, 0)
  734. // 3
  735. database3, err := badgerdb.New(db.Options{Path: c.TempDir()})
  736. c.Assert(err, qt.IsNil)
  737. tree3, err := NewTree(database3, 256, HashFunctionBlake2b)
  738. c.Assert(err, qt.IsNil)
  739. defer tree3.db.Close() //nolint:errcheck
  740. tree3.dbgInit()
  741. // add few key-values
  742. // invalids, err = tree3.AddBatch(ks[:], vs[:])
  743. invalids, err = tree3.AddBatch(ks[:1000], vs[:1000])
  744. c.Assert(err, qt.IsNil)
  745. c.Assert(len(invalids), qt.Equals, 0)
  746. // add the rest of key-values
  747. invalids, err = tree3.AddBatch(ks[1000:], vs[1000:])
  748. c.Assert(err, qt.IsNil)
  749. c.Assert(len(invalids), qt.Equals, 0)
  750. checkRoots(c, tree1, tree2)
  751. checkRoots(c, tree1, tree3)
  752. if debug {
  753. fmt.Println("TestDbgStats")
  754. tree1.dbg.print(" add in loop in emptyTree ")
  755. tree2.dbg.print(" addbatch caseEmptyTree ")
  756. tree3.dbg.print(" addbatch caseNotEmptyTree ")
  757. }
  758. }
  759. func TestLoadVT(t *testing.T) {
  760. c := qt.New(t)
  761. nLeafs := 1024
  762. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  763. c.Assert(err, qt.IsNil)
  764. tree, err := NewTree(database, 256, HashFunctionPoseidon)
  765. c.Assert(err, qt.IsNil)
  766. defer tree.db.Close() //nolint:errcheck
  767. var keys, values [][]byte
  768. for i := 0; i < nLeafs; i++ {
  769. k := randomBytes(31)
  770. v := randomBytes(31)
  771. keys = append(keys, k)
  772. values = append(values, v)
  773. }
  774. invalids, err := tree.AddBatch(keys, values)
  775. c.Assert(err, qt.IsNil)
  776. c.Check(len(invalids), qt.Equals, 0)
  777. rTx := tree.db.ReadTx()
  778. defer rTx.Discard()
  779. vt, err := tree.loadVT(rTx)
  780. c.Assert(err, qt.IsNil)
  781. _, err = vt.computeHashes()
  782. c.Assert(err, qt.IsNil)
  783. // check that tree & vt roots are equal
  784. root, err := tree.Root()
  785. c.Assert(err, qt.IsNil)
  786. c.Check(root, qt.DeepEquals, vt.root.h)
  787. }
  788. // TestAddKeysWithEmptyValues calls AddBatch giving an array of empty values
  789. func TestAddKeysWithEmptyValues(t *testing.T) {
  790. c := qt.New(t)
  791. nLeafs := 1024
  792. database, err := badgerdb.New(db.Options{Path: c.TempDir()})
  793. c.Assert(err, qt.IsNil)
  794. tree, err := NewTree(database, 256, HashFunctionPoseidon)
  795. c.Assert(err, qt.IsNil)
  796. defer tree.db.Close() //nolint:errcheck
  797. bLen := 32
  798. var keys, values [][]byte
  799. for i := 0; i < nLeafs; i++ {
  800. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  801. v := []byte{}
  802. keys = append(keys, k)
  803. values = append(values, v)
  804. }
  805. for i := 0; i < nLeafs; i++ {
  806. if err := tree.Add(keys[i], values[i]); err != nil {
  807. t.Fatal(err)
  808. }
  809. }
  810. database2, err := badgerdb.New(db.Options{Path: c.TempDir()})
  811. c.Assert(err, qt.IsNil)
  812. tree2, err := NewTree(database2, 256, HashFunctionPoseidon)
  813. c.Assert(err, qt.IsNil)
  814. defer tree2.db.Close() //nolint:errcheck
  815. tree2.dbgInit()
  816. invalids, err := tree2.AddBatch(keys, values)
  817. c.Assert(err, qt.IsNil)
  818. c.Check(len(invalids), qt.Equals, 0)
  819. // check that both trees roots are equal
  820. checkRoots(c, tree, tree2)
  821. // use tree3 to add nil value array
  822. database3, err := badgerdb.New(db.Options{Path: c.TempDir()})
  823. c.Assert(err, qt.IsNil)
  824. tree3, err := NewTree(database3, 256, HashFunctionPoseidon)
  825. c.Assert(err, qt.IsNil)
  826. defer tree3.db.Close() //nolint:errcheck
  827. invalids, err = tree3.AddBatch(keys, nil)
  828. c.Assert(err, qt.IsNil)
  829. c.Check(len(invalids), qt.Equals, 0)
  830. checkRoots(c, tree, tree3)
  831. kAux, proofV, siblings, existence, err := tree2.GenProof(keys[9])
  832. c.Assert(err, qt.IsNil)
  833. c.Assert(proofV, qt.DeepEquals, values[9])
  834. c.Assert(keys[9], qt.DeepEquals, kAux)
  835. c.Assert(existence, qt.IsTrue)
  836. // check with empty array
  837. root, err := tree.Root()
  838. c.Assert(err, qt.IsNil)
  839. verif, err := CheckProof(tree.hashFunction, keys[9], []byte{}, root, siblings)
  840. c.Assert(err, qt.IsNil)
  841. c.Check(verif, qt.IsTrue)
  842. // check with array with only 1 zero
  843. verif, err = CheckProof(tree.hashFunction, keys[9], []byte{0}, root, siblings)
  844. c.Assert(err, qt.IsNil)
  845. c.Check(verif, qt.IsTrue)
  846. // check with array with 32 zeroes
  847. e32 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  848. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  849. c.Assert(len(e32), qt.Equals, 32)
  850. verif, err = CheckProof(tree.hashFunction, keys[9], e32, root, siblings)
  851. c.Assert(err, qt.IsNil)
  852. c.Check(verif, qt.IsTrue)
  853. // check with array with value!=0 returns false at verification
  854. verif, err = CheckProof(tree.hashFunction, keys[9], []byte{0, 1}, root, siblings)
  855. c.Assert(err, qt.IsNil)
  856. c.Check(verif, qt.IsFalse)
  857. }
  858. func TestAddBatchThresholdInDisk(t *testing.T) {
  859. c := qt.New(t)
  860. database1, err := badgerdb.New(db.Options{Path: c.TempDir()})
  861. c.Assert(err, qt.IsNil)
  862. tree1, err := NewTree(database1, 256, HashFunctionBlake2b)
  863. c.Assert(err, qt.IsNil)
  864. defer tree1.db.Close() //nolint:errcheck
  865. database2, err := pebbledb.New(db.Options{Path: c.TempDir()})
  866. c.Assert(err, qt.IsNil)
  867. tree2, err := NewTree(database2, 256, HashFunctionBlake2b)
  868. c.Assert(err, qt.IsNil)
  869. defer tree2.db.Close() //nolint:errcheck
  870. database3, err := pebbledb.New(db.Options{Path: c.TempDir()})
  871. c.Assert(err, qt.IsNil)
  872. tree3, err := NewTree(database3, 256, HashFunctionBlake2b)
  873. c.Assert(err, qt.IsNil)
  874. defer tree3.db.Close() //nolint:errcheck
  875. // customize thresholdNLeafs for the test
  876. thresholdNLeafs = 1024
  877. var keys, values [][]byte
  878. for i := 0; i < 3*thresholdNLeafs; i++ {
  879. k := randomBytes(32)
  880. v := randomBytes(32)
  881. if err := tree1.Add(k, v); err != nil {
  882. t.Fatal(err)
  883. }
  884. if i < thresholdNLeafs+1 {
  885. if err := tree2.Add(k, v); err != nil {
  886. t.Fatal(err)
  887. }
  888. }
  889. // store for later addition through AddBatch
  890. keys = append(keys, k)
  891. values = append(values, v)
  892. }
  893. invalids, err := tree2.AddBatch(keys[thresholdNLeafs+1:], values[thresholdNLeafs+1:])
  894. c.Assert(err, qt.IsNil)
  895. c.Check(len(invalids), qt.Equals, 0)
  896. // check that both trees roots are equal
  897. checkRoots(c, tree1, tree2)
  898. // call directly the tree3.addBatchInDisk to ensure that is tested
  899. wTx := tree3.db.WriteTx()
  900. defer wTx.Discard()
  901. invalids, err = tree3.addBatchInDisk(wTx, keys, values)
  902. c.Assert(err, qt.IsNil)
  903. err = wTx.Commit()
  904. c.Assert(err, qt.IsNil)
  905. c.Check(len(invalids), qt.Equals, 0)
  906. // check that both trees roots are equal
  907. checkRoots(c, tree1, tree3)
  908. }
  909. // TODO test adding batch with multiple invalid keys
  910. // TODO for tests of AddBatch, if the root does not match the Add root, bulk
  911. // all the leafs of both trees into a log file to later be able to debug and
  912. // recreate the case