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.

922 lines
24 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. )
  14. var debug = true
  15. func printTestContext(prefix string, nLeafs int, hashName, dbName string) {
  16. if debug {
  17. fmt.Printf("%snCPU: %d, nLeafs: %d, hash: %s, db: %s\n",
  18. prefix, runtime.NumCPU(), nLeafs, hashName, dbName)
  19. }
  20. }
  21. func printRes(name string, duration time.Duration) {
  22. if debug {
  23. fmt.Printf("%s: %s \n", name, duration)
  24. }
  25. }
  26. func debugTime(descr string, time1, time2 time.Duration) {
  27. if debug {
  28. fmt.Printf("%s was %.02fx times faster than without AddBatch\n",
  29. descr, float64(time1)/float64(time2))
  30. }
  31. }
  32. func testInit(c *qt.C, n int) (*Tree, *Tree) {
  33. database1, err := db.NewBadgerDB(c.TempDir())
  34. c.Assert(err, qt.IsNil)
  35. tree1, err := NewTree(database1, 100, HashFunctionPoseidon)
  36. c.Assert(err, qt.IsNil)
  37. database2, err := db.NewBadgerDB(c.TempDir())
  38. c.Assert(err, qt.IsNil)
  39. tree2, err := NewTree(database2, 100, HashFunctionPoseidon)
  40. c.Assert(err, qt.IsNil)
  41. bLen := HashFunctionPoseidon.Len()
  42. // add the initial leafs to fill a bit the trees before calling the
  43. // AddBatch method
  44. for i := 0; i < n; i++ {
  45. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  46. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  47. if err := tree1.Add(k, v); err != nil {
  48. c.Fatal(err)
  49. }
  50. if err := tree2.Add(k, v); err != nil {
  51. c.Fatal(err)
  52. }
  53. }
  54. return tree1, tree2
  55. }
  56. func TestAddBatchTreeEmpty(t *testing.T) {
  57. c := qt.New(t)
  58. nLeafs := 1024
  59. database, err := db.NewBadgerDB(c.TempDir())
  60. c.Assert(err, qt.IsNil)
  61. tree, err := NewTree(database, 100, HashFunctionPoseidon)
  62. c.Assert(err, qt.IsNil)
  63. defer tree.db.Close() //nolint:errcheck
  64. bLen := tree.HashFunction().Len()
  65. start := time.Now()
  66. for i := 0; i < nLeafs; i++ {
  67. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  68. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  69. if err := tree.Add(k, v); err != nil {
  70. t.Fatal(err)
  71. }
  72. }
  73. time1 := time.Since(start)
  74. database2, err := db.NewBadgerDB(c.TempDir())
  75. c.Assert(err, qt.IsNil)
  76. tree2, err := NewTree(database2, 100, HashFunctionPoseidon)
  77. c.Assert(err, qt.IsNil)
  78. defer tree2.db.Close() //nolint:errcheck
  79. tree2.dbgInit()
  80. var keys, values [][]byte
  81. for i := 0; i < nLeafs; i++ {
  82. k := BigIntToBytes(bLen, big.NewInt(int64(i)))
  83. v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
  84. keys = append(keys, k)
  85. values = append(values, v)
  86. }
  87. start = time.Now()
  88. indexes, 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(indexes), 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 := db.NewBadgerDB(c.TempDir())
  104. c.Assert(err, qt.IsNil)
  105. tree, err := NewTree(database, 100, HashFunctionPoseidon)
  106. c.Assert(err, qt.IsNil)
  107. defer tree.db.Close() //nolint:errcheck
  108. bLen := tree.HashFunction().Len()
  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 := db.NewBadgerDB(c.TempDir())
  117. c.Assert(err, qt.IsNil)
  118. tree2, err := NewTree(database2, 100, 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. indexes, err := tree2.AddBatch(keys, values)
  129. c.Assert(err, qt.IsNil)
  130. c.Check(len(indexes), 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 := db.NewBadgerDB(c.TempDir())
  145. c.Assert(err, qt.IsNil)
  146. tree1, err := NewTree(database1, 100, HashFunctionBlake2b)
  147. c.Assert(err, qt.IsNil)
  148. defer tree1.db.Close() //nolint:errcheck
  149. database2, err := db.NewBadgerDB(c.TempDir())
  150. c.Assert(err, qt.IsNil)
  151. tree2, err := NewTree(database2, 100, 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. indexes, err := tree2.AddBatch(keys, values)
  174. c.Assert(err, qt.IsNil)
  175. c.Check(len(indexes), qt.Equals, 0)
  176. // check that both trees roots are equal
  177. checkRoots(c, tree1, tree2)
  178. // 2nd test vectors
  179. database1, err = db.NewBadgerDB(c.TempDir())
  180. c.Assert(err, qt.IsNil)
  181. tree1, err = NewTree(database1, 100, HashFunctionBlake2b)
  182. c.Assert(err, qt.IsNil)
  183. defer tree1.db.Close() //nolint:errcheck
  184. database2, err = db.NewBadgerDB(c.TempDir())
  185. c.Assert(err, qt.IsNil)
  186. tree2, err = NewTree(database2, 100, 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. indexes, err = tree2.AddBatch(keys, values)
  213. c.Assert(err, qt.IsNil)
  214. c.Check(len(indexes), 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 := db.NewBadgerDB(c.TempDir())
  222. c.Assert(err, qt.IsNil)
  223. tree1, err := NewTree(database, 100, HashFunctionPoseidon)
  224. c.Assert(err, qt.IsNil)
  225. defer tree1.db.Close() //nolint:errcheck
  226. database2, err := db.NewBadgerDB(c.TempDir())
  227. c.Assert(err, qt.IsNil)
  228. tree2, err := NewTree(database2, 100, 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. indexes, err := tree2.AddBatch(keys, values)
  251. c.Assert(err, qt.IsNil)
  252. c.Check(len(indexes), 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 := db.NewBadgerDB(c.TempDir())
  260. c.Assert(err, qt.IsNil)
  261. tree1, err := NewTree(database, 100, HashFunctionPoseidon)
  262. c.Assert(err, qt.IsNil)
  263. defer tree1.db.Close() //nolint:errcheck
  264. database2, err := db.NewBadgerDB(c.TempDir())
  265. c.Assert(err, qt.IsNil)
  266. tree2, err := NewTree(database2, 100, 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. indexes, err := tree2.AddBatch(keys, values)
  289. c.Assert(err, qt.IsNil)
  290. c.Check(len(indexes), 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 := db.NewBadgerDB(c.TempDir())
  301. c.Assert(err, qt.IsNil)
  302. tree1, err := NewTree(database1, 100, HashFunctionBlake2b)
  303. c.Assert(err, qt.IsNil)
  304. defer tree1.db.Close() //nolint:errcheck
  305. database2, err := db.NewBadgerDB(c.TempDir())
  306. c.Assert(err, qt.IsNil)
  307. tree2, err := NewTree(database2, 100, 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. indexes, err := tree2.AddBatch(keys, values)
  321. c.Assert(err, qt.IsNil)
  322. c.Check(len(indexes), 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. indexes, 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(indexes), 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. indexes, 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(indexes), 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. indexes, err := tree2.AddBatch(keys, values)
  428. c.Assert(err, qt.IsNil)
  429. c.Check(len(indexes), 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. indexes, err := tree2.AddBatch(keys, values)
  454. c.Assert(err, qt.IsNil)
  455. c.Check(len(indexes), 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. indexes, 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(indexes), 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 := db.NewBadgerDB(c.TempDir())
  604. c.Assert(err, qt.IsNil)
  605. tree2, err := NewTree(database2, 100, 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. indexes, 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(indexes), 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 := db.NewBadgerDB(c.TempDir())
  671. c.Assert(err, qt.IsNil)
  672. tree, err := NewTree(database, 140, 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 := db.NewBadgerDB(c.TempDir())
  688. c.Assert(err, qt.IsNil)
  689. tree, err := NewTree(database, 140, 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 := db.NewBadgerDB(c.TempDir())
  715. c.Assert(err, qt.IsNil)
  716. tree1, err := NewTree(database1, 100, 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 := db.NewBadgerDB(c.TempDir())
  726. c.Assert(err, qt.IsNil)
  727. tree2, err := NewTree(database2, 100, 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 := db.NewBadgerDB(c.TempDir())
  736. c.Assert(err, qt.IsNil)
  737. tree3, err := NewTree(database3, 100, 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 := db.NewBadgerDB(c.TempDir())
  763. c.Assert(err, qt.IsNil)
  764. tree, err := NewTree(database, 100, 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. indexes, err := tree.AddBatch(keys, values)
  775. c.Assert(err, qt.IsNil)
  776. c.Check(len(indexes), qt.Equals, 0)
  777. vt, err := tree.loadVT()
  778. c.Assert(err, qt.IsNil)
  779. _, err = vt.computeHashes()
  780. c.Assert(err, qt.IsNil)
  781. // check that tree & vt roots are equal
  782. c.Check(tree.Root(), qt.DeepEquals, vt.root.h)
  783. }
  784. // TODO test adding batch with multiple invalid keys
  785. // TODO for tests of AddBatch, if the root does not match the Add root, bulk
  786. // all the leafs of both trees into a log file to later be able to debug and
  787. // recreate the case