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.

1212 lines
33 KiB

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