MerkleProof.test.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. require('@openzeppelin/test-helpers');
  2. const { expectRevert } = require('@openzeppelin/test-helpers');
  3. const { MerkleTree } = require('merkletreejs');
  4. const keccak256 = require('keccak256');
  5. const { expect } = require('chai');
  6. const MerkleProofWrapper = artifacts.require('MerkleProofWrapper');
  7. contract('MerkleProof', function (accounts) {
  8. beforeEach(async function () {
  9. this.merkleProof = await MerkleProofWrapper.new();
  10. });
  11. describe('verify', function () {
  12. it('returns true for a valid Merkle proof', async function () {
  13. const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('');
  14. const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true });
  15. const root = merkleTree.getHexRoot();
  16. const leaf = keccak256(elements[0]);
  17. const proof = merkleTree.getHexProof(leaf);
  18. expect(await this.merkleProof.verify(proof, root, leaf)).to.equal(true);
  19. // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements:
  20. const noSuchLeaf = keccak256(
  21. Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)),
  22. );
  23. expect(await this.merkleProof.verify(proof.slice(1), root, noSuchLeaf)).to.equal(true);
  24. });
  25. it('returns false for an invalid Merkle proof', async function () {
  26. const correctElements = ['a', 'b', 'c'];
  27. const correctMerkleTree = new MerkleTree(correctElements, keccak256, { hashLeaves: true, sortPairs: true });
  28. const correctRoot = correctMerkleTree.getHexRoot();
  29. const correctLeaf = keccak256(correctElements[0]);
  30. const badElements = ['d', 'e', 'f'];
  31. const badMerkleTree = new MerkleTree(badElements);
  32. const badProof = badMerkleTree.getHexProof(badElements[0]);
  33. expect(await this.merkleProof.verify(badProof, correctRoot, correctLeaf)).to.equal(false);
  34. });
  35. it('returns false for a Merkle proof of invalid length', async function () {
  36. const elements = ['a', 'b', 'c'];
  37. const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true });
  38. const root = merkleTree.getHexRoot();
  39. const leaf = keccak256(elements[0]);
  40. const proof = merkleTree.getHexProof(leaf);
  41. const badProof = proof.slice(0, proof.length - 5);
  42. expect(await this.merkleProof.verify(badProof, root, leaf)).to.equal(false);
  43. });
  44. });
  45. describe('multiProofVerify', function () {
  46. it('returns true for a valid Merkle multi proof', async function () {
  47. const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare);
  48. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  49. const root = merkleTree.getRoot();
  50. const proofLeaves = ['b', 'f', 'd'].map(keccak256).sort(Buffer.compare);
  51. const proof = merkleTree.getMultiProof(proofLeaves);
  52. const proofFlags = merkleTree.getProofFlags(proofLeaves, proof);
  53. expect(await this.merkleProof.multiProofVerify(root, proofLeaves, proof, proofFlags)).to.equal(true);
  54. });
  55. it('returns false for an invalid Merkle multi proof', async function () {
  56. const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare);
  57. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  58. const root = merkleTree.getRoot();
  59. const badProofLeaves = ['g', 'h', 'i'].map(keccak256).sort(Buffer.compare);
  60. const badMerkleTree = new MerkleTree(badProofLeaves);
  61. const badProof = badMerkleTree.getMultiProof(badProofLeaves);
  62. const badProofFlags = badMerkleTree.getProofFlags(badProofLeaves, badProof);
  63. expect(await this.merkleProof.multiProofVerify(root, badProofLeaves, badProof, badProofFlags)).to.equal(false);
  64. });
  65. it('revert with invalid multi proof #1', async function () {
  66. const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch
  67. const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare);
  68. const badLeave = keccak256('e');
  69. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  70. const root = merkleTree.getRoot();
  71. await expectRevert(
  72. this.merkleProof.multiProofVerify(
  73. root,
  74. [ leaves[0], badLeave ], // A, E
  75. [ leaves[1], fill, merkleTree.layers[1][1] ],
  76. [ false, false, false ],
  77. ),
  78. 'MerkleProof: invalid multiproof',
  79. );
  80. });
  81. it('revert with invalid multi proof #2', async function () {
  82. const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch
  83. const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare);
  84. const badLeave = keccak256('e');
  85. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  86. const root = merkleTree.getRoot();
  87. await expectRevert(
  88. this.merkleProof.multiProofVerify(
  89. root,
  90. [ badLeave, leaves[0] ], // A, E
  91. [ leaves[1], fill, merkleTree.layers[1][1] ],
  92. [ false, false, false, false ],
  93. ),
  94. 'reverted with panic code 0x32',
  95. );
  96. });
  97. it('limit case: works for tree containing a single leaf', async function () {
  98. const leaves = ['a'].map(keccak256).sort(Buffer.compare);
  99. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  100. const root = merkleTree.getRoot();
  101. const proofLeaves = ['a'].map(keccak256).sort(Buffer.compare);
  102. const proof = merkleTree.getMultiProof(proofLeaves);
  103. const proofFlags = merkleTree.getProofFlags(proofLeaves, proof);
  104. expect(await this.merkleProof.multiProofVerify(root, proofLeaves, proof, proofFlags)).to.equal(true);
  105. });
  106. it('limit case: can prove empty leaves', async function () {
  107. const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare);
  108. const merkleTree = new MerkleTree(leaves, keccak256, { sort: true });
  109. const root = merkleTree.getRoot();
  110. expect(await this.merkleProof.multiProofVerify(root, [], [ root ], [])).to.equal(true);
  111. });
  112. });
  113. });