MerkleProof.test.js 6.4 KB

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