MerkleTreeWithHistory.test.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* global artifacts, web3, contract, assert */
  2. require('chai')
  3. .use(require('bn-chai')(web3.utils.BN))
  4. .use(require('chai-as-promised'))
  5. .should()
  6. const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
  7. const MerkleTreeWithHistory = artifacts.require('./MerkleTreeWithHistoryMock.sol')
  8. const hasherContract = artifacts.require('./Hasher.sol')
  9. const MerkleTree = require('../lib/MerkleTree')
  10. const hasherImpl = require('../lib/MiMC')
  11. const snarkjs = require('snarkjs')
  12. const bigInt = snarkjs.bigInt
  13. const { ETH_AMOUNT, MERKLE_TREE_HEIGHT } = process.env
  14. // eslint-disable-next-line no-unused-vars
  15. function BNArrayToStringArray(array) {
  16. const arrayToPrint = []
  17. array.forEach(item => {
  18. arrayToPrint.push(item.toString())
  19. })
  20. return arrayToPrint
  21. }
  22. function toFixedHex(number, length = 32) {
  23. let str = bigInt(number).toString(16)
  24. while (str.length < length * 2) str = '0' + str
  25. str = '0x' + str
  26. return str
  27. }
  28. contract('MerkleTreeWithHistory', accounts => {
  29. let merkleTreeWithHistory
  30. let hasherInstance
  31. let levels = MERKLE_TREE_HEIGHT || 16
  32. const sender = accounts[0]
  33. // eslint-disable-next-line no-unused-vars
  34. const value = ETH_AMOUNT || '1000000000000000000'
  35. let snapshotId
  36. let prefix = 'test'
  37. let tree
  38. let hasher
  39. before(async () => {
  40. tree = new MerkleTree(
  41. levels,
  42. null,
  43. prefix,
  44. )
  45. hasherInstance = await hasherContract.deployed()
  46. await MerkleTreeWithHistory.link(hasherContract, hasherInstance.address)
  47. merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
  48. snapshotId = await takeSnapshot()
  49. })
  50. describe('#constructor', () => {
  51. it('should initialize', async () => {
  52. const zeroValue = await merkleTreeWithHistory.ZERO_VALUE()
  53. const firstSubtree = await merkleTreeWithHistory.filledSubtrees(0)
  54. firstSubtree.should.be.equal(toFixedHex(zeroValue))
  55. const firstZero = await merkleTreeWithHistory.zeros(0)
  56. firstZero.should.be.equal(toFixedHex(zeroValue))
  57. })
  58. })
  59. describe('merkleTreeLib', () => {
  60. it('index_to_key', () => {
  61. assert.equal(
  62. MerkleTree.index_to_key('test', 5, 20),
  63. 'test_tree_5_20',
  64. )
  65. })
  66. it('tests insert', async () => {
  67. hasher = new hasherImpl()
  68. tree = new MerkleTree(
  69. 2,
  70. null,
  71. prefix,
  72. )
  73. await tree.insert(toFixedHex('5'))
  74. let { root, path_elements } = await tree.path(0)
  75. const calculated_root = hasher.hash(null,
  76. hasher.hash(null, '5', path_elements[0]),
  77. path_elements[1]
  78. )
  79. // console.log(root)
  80. assert.equal(root, calculated_root)
  81. })
  82. it('creation odd elements count', async () => {
  83. const elements = [12, 13, 14, 15, 16, 17, 18, 19, 20]
  84. for(const [, el] of Object.entries(elements)) {
  85. await tree.insert(el)
  86. }
  87. const batchTree = new MerkleTree(
  88. levels,
  89. elements,
  90. prefix,
  91. )
  92. for(const [i] of Object.entries(elements)) {
  93. const pathViaConstructor = await batchTree.path(i)
  94. const pathViaUpdate = await tree.path(i)
  95. pathViaConstructor.should.be.deep.equal(pathViaUpdate)
  96. }
  97. })
  98. it('should find an element', async () => {
  99. const elements = [12, 13, 14, 15, 16, 17, 18, 19, 20]
  100. for(const [, el] of Object.entries(elements)) {
  101. await tree.insert(el)
  102. }
  103. let index = tree.getIndexByElement(13)
  104. index.should.be.equal(1)
  105. index = tree.getIndexByElement(19)
  106. index.should.be.equal(7)
  107. index = tree.getIndexByElement(12)
  108. index.should.be.equal(0)
  109. index = tree.getIndexByElement(20)
  110. index.should.be.equal(8)
  111. index = tree.getIndexByElement(42)
  112. index.should.be.equal(false)
  113. })
  114. it('creation even elements count', async () => {
  115. const elements = [12, 13, 14, 15, 16, 17]
  116. for(const [, el] of Object.entries(elements)) {
  117. await tree.insert(el)
  118. }
  119. const batchTree = new MerkleTree(
  120. levels,
  121. elements,
  122. prefix,
  123. )
  124. for(const [i] of Object.entries(elements)) {
  125. const pathViaConstructor = await batchTree.path(i)
  126. const pathViaUpdate = await tree.path(i)
  127. pathViaConstructor.should.be.deep.equal(pathViaUpdate)
  128. }
  129. })
  130. it.skip('creation using 30000 elements', () => {
  131. const elements = []
  132. for(let i = 1000; i < 31001; i++) {
  133. elements.push(i)
  134. }
  135. console.time('MerkleTree')
  136. tree = new MerkleTree(
  137. levels,
  138. elements,
  139. prefix,
  140. )
  141. console.timeEnd('MerkleTree')
  142. // 2,7 GHz Intel Core i7
  143. // 1000 : 1949.084ms
  144. // 10000: 19456.220ms
  145. // 30000: 63406.679ms
  146. })
  147. })
  148. describe('#insert', () => {
  149. it('should insert', async () => {
  150. let rootFromContract
  151. for (let i = 1; i < 11; i++) {
  152. await merkleTreeWithHistory.insert(toFixedHex(i), { from: sender })
  153. await tree.insert(i)
  154. let { root } = await tree.path(i - 1)
  155. rootFromContract = await merkleTreeWithHistory.getLastRoot()
  156. toFixedHex(root).should.be.equal(rootFromContract.toString())
  157. }
  158. })
  159. it('should reject if tree is full', async () => {
  160. const levels = 6
  161. const merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
  162. for (let i = 0; i < 2**levels; i++) {
  163. await merkleTreeWithHistory.insert(toFixedHex(i+42)).should.be.fulfilled
  164. }
  165. let error = await merkleTreeWithHistory.insert(toFixedHex(1337)).should.be.rejected
  166. error.reason.should.be.equal('Merkle tree is full. No more leafs can be added')
  167. error = await merkleTreeWithHistory.insert(toFixedHex(1)).should.be.rejected
  168. error.reason.should.be.equal('Merkle tree is full. No more leafs can be added')
  169. })
  170. it.skip('hasher gas', async () => {
  171. const levels = 6
  172. const merkleTreeWithHistory = await MerkleTreeWithHistory.new(levels)
  173. const zeroValue = await merkleTreeWithHistory.zeroValue()
  174. const gas = await merkleTreeWithHistory.hashLeftRight.estimateGas(zeroValue, zeroValue)
  175. console.log('gas', gas - 21000)
  176. })
  177. })
  178. describe('#isKnownRoot', () => {
  179. it('should work', async () => {
  180. let path
  181. for (let i = 1; i < 5; i++) {
  182. await merkleTreeWithHistory.insert(toFixedHex(i), { from: sender }).should.be.fulfilled
  183. await tree.insert(i)
  184. path = await tree.path(i - 1)
  185. let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(path.root))
  186. isKnown.should.be.equal(true)
  187. }
  188. await merkleTreeWithHistory.insert(toFixedHex(42), { from: sender }).should.be.fulfilled
  189. // check outdated root
  190. let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(path.root))
  191. isKnown.should.be.equal(true)
  192. })
  193. it('should not return uninitialized roots', async () => {
  194. await merkleTreeWithHistory.insert(toFixedHex(42), { from: sender }).should.be.fulfilled
  195. let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(0))
  196. isKnown.should.be.equal(false)
  197. })
  198. })
  199. afterEach(async () => {
  200. await revertSnapshot(snapshotId.result)
  201. // eslint-disable-next-line require-atomic-updates
  202. snapshotId = await takeSnapshot()
  203. hasher = new hasherImpl()
  204. tree = new MerkleTree(
  205. levels,
  206. null,
  207. prefix,
  208. null,
  209. hasher,
  210. )
  211. })
  212. })