blobstream-contracts 0.0.1-security → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of blobstream-contracts might be problematic. Click here for more details.
- package/.codecov.yml +51 -0
- package/.github/CODEOWNERS +7 -0
- package/.github/dependabot.yml +18 -0
- package/.github/workflows/code-analysis.yml +41 -0
- package/.github/workflows/contract-inheritance-check.yml +28 -0
- package/.github/workflows/go-check.yml +25 -0
- package/.github/workflows/labels.yml +19 -0
- package/.github/workflows/lint.yml +37 -0
- package/.github/workflows/tests.yml +72 -0
- package/.gitmodules +12 -0
- package/.golangci.yml +64 -0
- package/.markdownlint.yaml +5 -0
- package/.markdownlint.yml +4 -0
- package/.markdownlintignore +1 -0
- package/.prettierrc.json +11 -0
- package/LICENSE +201 -0
- package/Makefile +18 -0
- package/README.md +102 -5
- package/docs/inclusion-proofs.md +69 -0
- package/foundry.toml +4 -0
- package/go.mod +34 -0
- package/go.sum +212 -0
- package/hardhat.config.ts +46 -0
- package/index.js +40 -0
- package/package.json +29 -3
- package/remappings.txt +6 -0
- package/scripts/Dockerfile_Environment +39 -0
- package/scripts/deploy.ts +12 -0
- package/scripts/gen.sh +34 -0
- package/scripts/upgradability_check.sh +22 -0
- package/slither.config.json +3 -0
- package/src/Blobstream.sol +366 -0
- package/src/Constants.sol +10 -0
- package/src/DataRootTuple.sol +15 -0
- package/src/IDAOracle.sol +18 -0
- package/src/lib/tree/Constants.sol +23 -0
- package/src/lib/tree/Types.sol +37 -0
- package/src/lib/tree/Utils.sol +106 -0
- package/src/lib/tree/binary/BinaryMerkleMultiproof.sol +12 -0
- package/src/lib/tree/binary/BinaryMerkleProof.sol +12 -0
- package/src/lib/tree/binary/BinaryMerkleTree.sol +256 -0
- package/src/lib/tree/binary/TreeHasher.sol +23 -0
- package/src/lib/tree/binary/test/BinaryMerkleTree.t.sol +365 -0
- package/src/lib/tree/binary/test/TreeHasher.t.sol +40 -0
- package/src/lib/tree/namespace/NamespaceMerkleMultiproof.sol +14 -0
- package/src/lib/tree/namespace/NamespaceMerkleProof.sol +14 -0
- package/src/lib/tree/namespace/NamespaceMerkleTree.sol +306 -0
- package/src/lib/tree/namespace/NamespaceNode.sol +23 -0
- package/src/lib/tree/namespace/TreeHasher.sol +69 -0
- package/src/lib/tree/namespace/test/NamespaceMerkleMultiproof.t.sol +108 -0
- package/src/lib/tree/namespace/test/NamespaceMerkleTree.t.sol +644 -0
- package/src/lib/tree/namespace/test/TreeHasher.t.sol +66 -0
- package/src/lib/tree/test/Utils.t.sol +48 -0
- package/src/lib/tree/test/blob.dat +0 -0
- package/src/lib/tree/test/header.dat +0 -0
- package/src/lib/tree/test/proofs.json +1 -0
- package/src/lib/verifier/DAVerifier.sol +328 -0
- package/src/lib/verifier/test/DAVerifier.t.sol +396 -0
- package/src/lib/verifier/test/RollupInclusionProofs.t.sol +589 -0
- package/src/test/Blobstream.t.sol +200 -0
- package/src/test/BlobstreamBenchmark.t.sol +137 -0
- package/tsconfig.json +11 -0
- package/wrappers/Blobstream.sol/wrapper.go +1325 -0
- package/wrappers/ERC1967Proxy.sol/wrapper.go +668 -0
@@ -0,0 +1,256 @@
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
2
|
+
pragma solidity ^0.8.22;
|
3
|
+
|
4
|
+
import "../Constants.sol";
|
5
|
+
import "../Utils.sol";
|
6
|
+
import "./TreeHasher.sol";
|
7
|
+
import "./BinaryMerkleProof.sol";
|
8
|
+
import "./BinaryMerkleMultiproof.sol";
|
9
|
+
|
10
|
+
/// @title Binary Merkle Tree.
|
11
|
+
library BinaryMerkleTree {
|
12
|
+
/////////////////
|
13
|
+
// Error codes //
|
14
|
+
/////////////////
|
15
|
+
|
16
|
+
enum ErrorCodes {
|
17
|
+
NoError,
|
18
|
+
/// @notice The provided side nodes count is invalid for the proof.
|
19
|
+
InvalidNumberOfSideNodes,
|
20
|
+
/// @notice The provided proof key is not part of the tree.
|
21
|
+
KeyNotInTree,
|
22
|
+
/// @notice Invalid number of leaves in proof.
|
23
|
+
InvalidNumberOfLeavesInProof,
|
24
|
+
/// @notice The proof contains unexpected side nodes.
|
25
|
+
UnexpectedInnerHashes,
|
26
|
+
/// @notice The proof verification expected at least one inner hash.
|
27
|
+
ExpectedAtLeastOneInnerHash
|
28
|
+
}
|
29
|
+
|
30
|
+
///////////////
|
31
|
+
// Functions //
|
32
|
+
///////////////
|
33
|
+
|
34
|
+
/// @notice Verify if element exists in Merkle tree, given data, proof, and root.
|
35
|
+
/// @param root The root of the tree in which verify the given leaf.
|
36
|
+
/// @param proof Binary Merkle proof for the leaf.
|
37
|
+
/// @param data The data of the leaf to verify.
|
38
|
+
/// @return `true` is proof is valid, `false` otherwise.
|
39
|
+
/// @dev proof.numLeaves is necessary to determine height of subtree containing the data to prove.
|
40
|
+
function verify(bytes32 root, BinaryMerkleProof memory proof, bytes memory data)
|
41
|
+
internal
|
42
|
+
pure
|
43
|
+
returns (bool, ErrorCodes)
|
44
|
+
{
|
45
|
+
// Check proof is correct length for the key it is proving
|
46
|
+
if (proof.numLeaves <= 1) {
|
47
|
+
if (proof.sideNodes.length != 0) {
|
48
|
+
return (false, ErrorCodes.InvalidNumberOfSideNodes);
|
49
|
+
}
|
50
|
+
} else if (proof.sideNodes.length != pathLengthFromKey(proof.key, proof.numLeaves)) {
|
51
|
+
return (false, ErrorCodes.InvalidNumberOfSideNodes);
|
52
|
+
}
|
53
|
+
|
54
|
+
// Check key is in tree
|
55
|
+
if (proof.key >= proof.numLeaves) {
|
56
|
+
return (false, ErrorCodes.KeyNotInTree);
|
57
|
+
}
|
58
|
+
|
59
|
+
// A sibling at height 1 is created by getting the hash of the data to prove.
|
60
|
+
bytes32 digest = leafDigest(data);
|
61
|
+
|
62
|
+
// Null proof is only valid if numLeaves = 1
|
63
|
+
// If so, just verify hash(data) is root
|
64
|
+
if (proof.sideNodes.length == 0) {
|
65
|
+
if (proof.numLeaves == 1) {
|
66
|
+
return (root == digest, ErrorCodes.NoError);
|
67
|
+
} else {
|
68
|
+
return (false, ErrorCodes.NoError);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
(bytes32 computedHash, ErrorCodes error) = computeRootHash(proof.key, proof.numLeaves, digest, proof.sideNodes);
|
73
|
+
|
74
|
+
if (error != ErrorCodes.NoError) {
|
75
|
+
return (false, error);
|
76
|
+
}
|
77
|
+
|
78
|
+
return (computedHash == root, ErrorCodes.NoError);
|
79
|
+
}
|
80
|
+
|
81
|
+
function verifyMulti(bytes32 root, BinaryMerkleMultiproof memory proof, bytes[] memory data)
|
82
|
+
internal
|
83
|
+
pure
|
84
|
+
returns (bool)
|
85
|
+
{
|
86
|
+
bytes32[] memory nodes = new bytes32[](data.length);
|
87
|
+
for (uint256 i = 0; i < data.length; i++) {
|
88
|
+
nodes[i] = leafDigest(data[i]);
|
89
|
+
}
|
90
|
+
|
91
|
+
return verifyMultiHashes(root, proof, nodes);
|
92
|
+
}
|
93
|
+
|
94
|
+
function verifyMultiHashes(bytes32 root, BinaryMerkleMultiproof memory proof, bytes32[] memory leafNodes)
|
95
|
+
internal
|
96
|
+
pure
|
97
|
+
returns (bool)
|
98
|
+
{
|
99
|
+
uint256 leafIndex = 0;
|
100
|
+
bytes32[] memory leftSubtrees = new bytes32[](proof.sideNodes.length);
|
101
|
+
|
102
|
+
for (uint256 i = 0; leafIndex != proof.beginKey && i < proof.sideNodes.length; ++i) {
|
103
|
+
uint256 subtreeSize = _nextSubtreeSize(leafIndex, proof.beginKey);
|
104
|
+
leftSubtrees[i] = proof.sideNodes[i];
|
105
|
+
leafIndex += subtreeSize;
|
106
|
+
}
|
107
|
+
|
108
|
+
uint256 proofRangeSubtreeEstimate = _getSplitPoint(proof.endKey) * 2;
|
109
|
+
if (proofRangeSubtreeEstimate < 1) {
|
110
|
+
proofRangeSubtreeEstimate = 1;
|
111
|
+
}
|
112
|
+
|
113
|
+
(bytes32 rootHash, uint256 proofHead,,) =
|
114
|
+
_computeRootMulti(proof, leafNodes, 0, proofRangeSubtreeEstimate, 0, 0);
|
115
|
+
for (uint256 i = proofHead; i < proof.sideNodes.length; ++i) {
|
116
|
+
rootHash = nodeDigest(rootHash, proof.sideNodes[i]);
|
117
|
+
}
|
118
|
+
|
119
|
+
return (rootHash == root);
|
120
|
+
}
|
121
|
+
|
122
|
+
function _computeRootMulti(
|
123
|
+
BinaryMerkleMultiproof memory proof,
|
124
|
+
bytes32[] memory leafNodes,
|
125
|
+
uint256 begin,
|
126
|
+
uint256 end,
|
127
|
+
uint256 headProof,
|
128
|
+
uint256 headLeaves
|
129
|
+
) private pure returns (bytes32, uint256, uint256, bool) {
|
130
|
+
// reached a leaf
|
131
|
+
if (end - begin == 1) {
|
132
|
+
// if current range overlaps with proof range, pop and return a leaf
|
133
|
+
if (proof.beginKey <= begin && begin < proof.endKey) {
|
134
|
+
// Note: second return value is guaranteed to be `false` by
|
135
|
+
// construction.
|
136
|
+
return _popLeavesIfNonEmpty(leafNodes, headLeaves, leafNodes.length, headProof);
|
137
|
+
}
|
138
|
+
|
139
|
+
// if current range does not overlap with proof range,
|
140
|
+
// pop and return a proof node (leaf) if present,
|
141
|
+
// else return nil because leaf doesn't exist
|
142
|
+
return _popProofIfNonEmpty(proof.sideNodes, headProof, end, headLeaves);
|
143
|
+
}
|
144
|
+
|
145
|
+
// if current range does not overlap with proof range,
|
146
|
+
// pop and return a proof node if present,
|
147
|
+
// else return nil because subtree doesn't exist
|
148
|
+
if (end <= proof.beginKey || begin >= proof.endKey) {
|
149
|
+
return _popProofIfNonEmpty(proof.sideNodes, headProof, end, headLeaves);
|
150
|
+
}
|
151
|
+
|
152
|
+
// Recursively get left and right subtree
|
153
|
+
uint256 k = _getSplitPoint(end - begin);
|
154
|
+
(bytes32 left, uint256 newHeadProofLeft, uint256 newHeadLeavesLeft,) =
|
155
|
+
_computeRootMulti(proof, leafNodes, begin, begin + k, headProof, headLeaves);
|
156
|
+
(bytes32 right, uint256 newHeadProof, uint256 newHeadLeaves, bool rightIsNil) =
|
157
|
+
_computeRootMulti(proof, leafNodes, begin + k, end, newHeadProofLeft, newHeadLeavesLeft);
|
158
|
+
|
159
|
+
// only right leaf/subtree can be non-existent
|
160
|
+
if (rightIsNil == true) {
|
161
|
+
return (left, newHeadProof, newHeadLeaves, false);
|
162
|
+
}
|
163
|
+
bytes32 hash = nodeDigest(left, right);
|
164
|
+
return (hash, newHeadProof, newHeadLeaves, false);
|
165
|
+
}
|
166
|
+
|
167
|
+
function _popProofIfNonEmpty(bytes32[] memory nodes, uint256 headProof, uint256 end, uint256 headLeaves)
|
168
|
+
private
|
169
|
+
pure
|
170
|
+
returns (bytes32, uint256, uint256, bool)
|
171
|
+
{
|
172
|
+
(bytes32 node, uint256 newHead, bool isNil) = _popIfNonEmpty(nodes, headProof, end);
|
173
|
+
return (node, newHead, headLeaves, isNil);
|
174
|
+
}
|
175
|
+
|
176
|
+
function _popLeavesIfNonEmpty(bytes32[] memory nodes, uint256 headLeaves, uint256 end, uint256 headProof)
|
177
|
+
private
|
178
|
+
pure
|
179
|
+
returns (bytes32, uint256, uint256, bool)
|
180
|
+
{
|
181
|
+
(bytes32 node, uint256 newHead, bool isNil) = _popIfNonEmpty(nodes, headLeaves, end);
|
182
|
+
return (node, headProof, newHead, isNil);
|
183
|
+
}
|
184
|
+
|
185
|
+
function _popIfNonEmpty(bytes32[] memory nodes, uint256 head, uint256 end)
|
186
|
+
private
|
187
|
+
pure
|
188
|
+
returns (bytes32, uint256, bool)
|
189
|
+
{
|
190
|
+
if (nodes.length == 0 || head >= nodes.length || head >= end) {
|
191
|
+
bytes32 node;
|
192
|
+
return (node, head, true);
|
193
|
+
}
|
194
|
+
return (nodes[head], head + 1, false);
|
195
|
+
}
|
196
|
+
|
197
|
+
/// @notice Use the leafHash and innerHashes to get the root merkle hash.
|
198
|
+
/// If the length of the innerHashes slice isn't exactly correct, the result is nil.
|
199
|
+
/// Recursive impl.
|
200
|
+
function computeRootHash(uint256 key, uint256 numLeaves, bytes32 leafHash, bytes32[] memory sideNodes)
|
201
|
+
private
|
202
|
+
pure
|
203
|
+
returns (bytes32, ErrorCodes)
|
204
|
+
{
|
205
|
+
if (numLeaves == 0) {
|
206
|
+
return (leafHash, ErrorCodes.InvalidNumberOfLeavesInProof);
|
207
|
+
}
|
208
|
+
if (numLeaves == 1) {
|
209
|
+
if (sideNodes.length != 0) {
|
210
|
+
return (leafHash, ErrorCodes.UnexpectedInnerHashes);
|
211
|
+
}
|
212
|
+
return (leafHash, ErrorCodes.NoError);
|
213
|
+
}
|
214
|
+
if (sideNodes.length == 0) {
|
215
|
+
return (leafHash, ErrorCodes.ExpectedAtLeastOneInnerHash);
|
216
|
+
}
|
217
|
+
uint256 numLeft = _getSplitPoint(numLeaves);
|
218
|
+
bytes32[] memory sideNodesLeft = slice(sideNodes, 0, sideNodes.length - 1);
|
219
|
+
ErrorCodes error;
|
220
|
+
if (key < numLeft) {
|
221
|
+
bytes32 leftHash;
|
222
|
+
(leftHash, error) = computeRootHash(key, numLeft, leafHash, sideNodesLeft);
|
223
|
+
if (error != ErrorCodes.NoError) {
|
224
|
+
return (leafHash, error);
|
225
|
+
}
|
226
|
+
return (nodeDigest(leftHash, sideNodes[sideNodes.length - 1]), ErrorCodes.NoError);
|
227
|
+
}
|
228
|
+
bytes32 rightHash;
|
229
|
+
(rightHash, error) = computeRootHash(key - numLeft, numLeaves - numLeft, leafHash, sideNodesLeft);
|
230
|
+
if (error != ErrorCodes.NoError) {
|
231
|
+
return (leafHash, error);
|
232
|
+
}
|
233
|
+
return (nodeDigest(sideNodes[sideNodes.length - 1], rightHash), ErrorCodes.NoError);
|
234
|
+
}
|
235
|
+
|
236
|
+
/// @notice creates a slice of bytes32 from the data slice of bytes32 containing the elements
|
237
|
+
/// that correspond to the provided range.
|
238
|
+
/// It selects a half-open range which includes the begin element, but excludes the end one.
|
239
|
+
/// @param _data The slice that we want to select data from.
|
240
|
+
/// @param _begin The beginning of the range (inclusive).
|
241
|
+
/// @param _end The ending of the range (exclusive).
|
242
|
+
/// @return _ the sliced data.
|
243
|
+
function slice(bytes32[] memory _data, uint256 _begin, uint256 _end) internal pure returns (bytes32[] memory) {
|
244
|
+
if (_begin > _end) {
|
245
|
+
revert("Invalid range: _begin is greater than _end");
|
246
|
+
}
|
247
|
+
if (_begin > _data.length || _end > _data.length) {
|
248
|
+
revert("Invalid range: _begin or _end are out of bounds");
|
249
|
+
}
|
250
|
+
bytes32[] memory out = new bytes32[](_end - _begin);
|
251
|
+
for (uint256 i = _begin; i < _end; i++) {
|
252
|
+
out[i - _begin] = _data[i];
|
253
|
+
}
|
254
|
+
return out;
|
255
|
+
}
|
256
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
2
|
+
pragma solidity ^0.8.22;
|
3
|
+
|
4
|
+
import "../Constants.sol";
|
5
|
+
|
6
|
+
/// @notice Calculate the digest of a node.
|
7
|
+
/// @param left The left child.
|
8
|
+
/// @param right The right child.
|
9
|
+
/// @return digest The node digest.
|
10
|
+
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#binary-merkle-tree
|
11
|
+
// solhint-disable-next-line func-visibility
|
12
|
+
function nodeDigest(bytes32 left, bytes32 right) pure returns (bytes32 digest) {
|
13
|
+
digest = sha256(abi.encodePacked(Constants.NODE_PREFIX, left, right));
|
14
|
+
}
|
15
|
+
|
16
|
+
/// @notice Calculate the digest of a leaf.
|
17
|
+
/// @param data The data of the leaf.
|
18
|
+
/// @return digest The leaf digest.
|
19
|
+
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#binary-merkle-tree
|
20
|
+
// solhint-disable-next-line func-visibility
|
21
|
+
function leafDigest(bytes memory data) pure returns (bytes32 digest) {
|
22
|
+
digest = sha256(abi.encodePacked(Constants.LEAF_PREFIX, data));
|
23
|
+
}
|
@@ -0,0 +1,365 @@
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
2
|
+
pragma solidity ^0.8.22;
|
3
|
+
|
4
|
+
import "ds-test/test.sol";
|
5
|
+
import "forge-std/Vm.sol";
|
6
|
+
|
7
|
+
import "../BinaryMerkleProof.sol";
|
8
|
+
import "../BinaryMerkleTree.sol";
|
9
|
+
import "../BinaryMerkleMultiproof.sol";
|
10
|
+
|
11
|
+
/**
|
12
|
+
* TEST VECTORS
|
13
|
+
*
|
14
|
+
* 0x01
|
15
|
+
* 0x02
|
16
|
+
* 0x03
|
17
|
+
* 0x04
|
18
|
+
* 0x05
|
19
|
+
* 0x06
|
20
|
+
* 0x07
|
21
|
+
* 0x08
|
22
|
+
*
|
23
|
+
* 0xb413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2
|
24
|
+
* 0xfcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f
|
25
|
+
* 0x583c7dfb7b3055d99465544032a571e10a134b1b6f769422bbb71fd7fa167a5d
|
26
|
+
* 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4
|
27
|
+
* 0x9f1afa4dc124cba73134e82ff50f17c8f7164257c79fed9a13f5943a6acb8e3d
|
28
|
+
* 0x40d88127d4d31a3891f41598eeed41174e5bc89b1eb9bbd66a8cbfc09956a3fd
|
29
|
+
* 0x2ecd8a6b7d2845546659ad4cf443533cf921b19dc81fa83934e83821b4dfdcb7
|
30
|
+
* 0xb4c43b50bf245bd727623e3c775a8fcfb8d823d00b57dd65f7f79dd33f126315
|
31
|
+
*
|
32
|
+
* 0x6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965
|
33
|
+
* 0x78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d
|
34
|
+
* 0x90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0
|
35
|
+
* 0x28c01722dd8dd05b63bcdeb6878bc2c083118cc2b170646d6b842d0bdbdc9d29
|
36
|
+
*
|
37
|
+
* 0xfa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f
|
38
|
+
* 0x4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09
|
39
|
+
*
|
40
|
+
* 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071
|
41
|
+
*
|
42
|
+
*/
|
43
|
+
|
44
|
+
// Intermediate mock contract that calls the library function
|
45
|
+
// and returns the result.
|
46
|
+
// This is done because of the expectRevert v1 behaviour change:
|
47
|
+
// https://github.com/foundry-rs/book/pull/922
|
48
|
+
contract BinaryMerkleTreeLibMock {
|
49
|
+
function slice(bytes32[] memory _data, uint256 _begin, uint256 _end) external returns (bytes32[] memory) {
|
50
|
+
return BinaryMerkleTree.slice(_data, _begin, _end);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
contract BinaryMerkleProofTest is DSTest {
|
55
|
+
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
|
56
|
+
BinaryMerkleTreeLibMock public binaryMerkleTreeMock;
|
57
|
+
|
58
|
+
function setUp() external {
|
59
|
+
binaryMerkleTreeMock = new BinaryMerkleTreeLibMock();
|
60
|
+
}
|
61
|
+
|
62
|
+
function testVerifyNone() external {
|
63
|
+
bytes32 root = sha256("");
|
64
|
+
bytes32[] memory sideNodes;
|
65
|
+
uint256 key = 0;
|
66
|
+
uint256 numLeaves = 0;
|
67
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
68
|
+
bytes memory data;
|
69
|
+
(bool isValid,) = BinaryMerkleTree.verify(root, proof, data);
|
70
|
+
assertTrue(!isValid);
|
71
|
+
}
|
72
|
+
|
73
|
+
function testVerifyOneLeafEmpty() external {
|
74
|
+
bytes32 root = 0x6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d;
|
75
|
+
bytes32[] memory sideNodes;
|
76
|
+
uint256 key = 0;
|
77
|
+
uint256 numLeaves = 1;
|
78
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
79
|
+
bytes memory data;
|
80
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
81
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
82
|
+
assertTrue(isValid);
|
83
|
+
}
|
84
|
+
|
85
|
+
function testVerifyOneLeafSome() external {
|
86
|
+
bytes32 root = 0x48c90c8ae24688d6bef5d48a30c2cc8b6754335a8db21793cc0a8e3bed321729;
|
87
|
+
bytes32[] memory sideNodes;
|
88
|
+
uint256 key = 0;
|
89
|
+
uint256 numLeaves = 1;
|
90
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
91
|
+
bytes memory data = hex"deadbeef";
|
92
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
93
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
94
|
+
assertTrue(isValid);
|
95
|
+
}
|
96
|
+
|
97
|
+
function testVerifyOneLeaf01() external {
|
98
|
+
bytes32 root = 0xb413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2;
|
99
|
+
bytes32[] memory sideNodes;
|
100
|
+
uint256 key = 0;
|
101
|
+
uint256 numLeaves = 1;
|
102
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
103
|
+
bytes memory data = hex"01";
|
104
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
105
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
106
|
+
assertTrue(isValid);
|
107
|
+
}
|
108
|
+
|
109
|
+
function testVerifyLeafOneOfEight() external {
|
110
|
+
bytes32 root = 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071;
|
111
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
112
|
+
sideNodes[0] = 0xfcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f;
|
113
|
+
sideNodes[1] = 0x78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d;
|
114
|
+
sideNodes[2] = 0x4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09;
|
115
|
+
|
116
|
+
uint256 key = 0;
|
117
|
+
uint256 numLeaves = 8;
|
118
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
119
|
+
bytes memory data = hex"01";
|
120
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
121
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
122
|
+
assertTrue(isValid);
|
123
|
+
}
|
124
|
+
|
125
|
+
function testVerifyLeafTwoOfEight() external {
|
126
|
+
bytes32 root = 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071;
|
127
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
128
|
+
sideNodes[0] = 0xb413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2;
|
129
|
+
sideNodes[1] = 0x78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d;
|
130
|
+
sideNodes[2] = 0x4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09;
|
131
|
+
|
132
|
+
uint256 key = 1;
|
133
|
+
uint256 numLeaves = 8;
|
134
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
135
|
+
bytes memory data = hex"02";
|
136
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
137
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
138
|
+
assertTrue(isValid);
|
139
|
+
}
|
140
|
+
|
141
|
+
function testVerifyLeafThreeOfEight() external {
|
142
|
+
bytes32 root = 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071;
|
143
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
144
|
+
sideNodes[0] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
145
|
+
sideNodes[1] = 0x6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965;
|
146
|
+
sideNodes[2] = 0x4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09;
|
147
|
+
|
148
|
+
uint256 key = 2;
|
149
|
+
uint256 numLeaves = 8;
|
150
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
151
|
+
bytes memory data = hex"03";
|
152
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
153
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
154
|
+
assertTrue(isValid);
|
155
|
+
}
|
156
|
+
|
157
|
+
function testVerifyLeafSevenOfEight() external {
|
158
|
+
bytes32 root = 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071;
|
159
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
160
|
+
sideNodes[0] = 0xb4c43b50bf245bd727623e3c775a8fcfb8d823d00b57dd65f7f79dd33f126315;
|
161
|
+
sideNodes[1] = 0x90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0;
|
162
|
+
sideNodes[2] = 0xfa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f;
|
163
|
+
|
164
|
+
uint256 key = 6;
|
165
|
+
uint256 numLeaves = 8;
|
166
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
167
|
+
bytes memory data = hex"07";
|
168
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
169
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
170
|
+
assertTrue(isValid);
|
171
|
+
}
|
172
|
+
|
173
|
+
function testVerifyLeafEightOfEight() external {
|
174
|
+
bytes32 root = 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071;
|
175
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
176
|
+
sideNodes[0] = 0x2ecd8a6b7d2845546659ad4cf443533cf921b19dc81fa83934e83821b4dfdcb7;
|
177
|
+
sideNodes[1] = 0x90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0;
|
178
|
+
sideNodes[2] = 0xfa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f;
|
179
|
+
|
180
|
+
uint256 key = 7;
|
181
|
+
uint256 numLeaves = 8;
|
182
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
183
|
+
bytes memory data = hex"08";
|
184
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
185
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
186
|
+
assertTrue(isValid);
|
187
|
+
}
|
188
|
+
|
189
|
+
// Test vectors:
|
190
|
+
// 0x00
|
191
|
+
// 0x01
|
192
|
+
// 0x02
|
193
|
+
// 0x03
|
194
|
+
// 0x04
|
195
|
+
function testVerifyProofOfFiveLeaves() external {
|
196
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
197
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
198
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
199
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
200
|
+
sideNodes[2] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
201
|
+
|
202
|
+
uint256 key = 1;
|
203
|
+
uint256 numLeaves = 5;
|
204
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
205
|
+
bytes memory data = bytes(hex"01");
|
206
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
207
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
208
|
+
assertTrue(isValid);
|
209
|
+
}
|
210
|
+
|
211
|
+
function testVerifyInvalidProofRoot() external {
|
212
|
+
// correct root: 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
213
|
+
bytes32 root = 0xc855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
214
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
215
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
216
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
217
|
+
sideNodes[2] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
218
|
+
|
219
|
+
uint256 key = 1;
|
220
|
+
uint256 numLeaves = 5;
|
221
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
222
|
+
bytes memory data = bytes(hex"01");
|
223
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
224
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
225
|
+
assertTrue(!isValid);
|
226
|
+
}
|
227
|
+
|
228
|
+
function testVerifyInvalidProofKey() external {
|
229
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
230
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
231
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
232
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
233
|
+
sideNodes[2] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
234
|
+
|
235
|
+
// correct key: 1
|
236
|
+
uint256 key = 2;
|
237
|
+
uint256 numLeaves = 5;
|
238
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
239
|
+
bytes memory data = bytes(hex"01");
|
240
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
241
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
242
|
+
assertTrue(!isValid);
|
243
|
+
}
|
244
|
+
|
245
|
+
function testVerifyInvalidProofNumberOfLeaves() external {
|
246
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
247
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
248
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
249
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
250
|
+
sideNodes[2] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
251
|
+
|
252
|
+
uint256 key = 1;
|
253
|
+
// correct numLeaves: 5
|
254
|
+
uint256 numLeaves = 200;
|
255
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
256
|
+
bytes memory data = bytes(hex"01");
|
257
|
+
(bool isValid,) = BinaryMerkleTree.verify(root, proof, data);
|
258
|
+
assertTrue(!isValid);
|
259
|
+
}
|
260
|
+
|
261
|
+
function testVerifyInvalidProofSideNodes() external {
|
262
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
263
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
264
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
265
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
266
|
+
// correct side node: 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
267
|
+
sideNodes[2] = 0x5f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
268
|
+
|
269
|
+
uint256 key = 1;
|
270
|
+
uint256 numLeaves = 5;
|
271
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
272
|
+
bytes memory data = bytes(hex"01");
|
273
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
274
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
275
|
+
assertTrue(!isValid);
|
276
|
+
}
|
277
|
+
|
278
|
+
function testVerifyInvalidProofData() external {
|
279
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
280
|
+
bytes32[] memory sideNodes = new bytes32[](3);
|
281
|
+
sideNodes[0] = 0x96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7;
|
282
|
+
sideNodes[1] = 0x52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825;
|
283
|
+
sideNodes[2] = 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4;
|
284
|
+
|
285
|
+
uint256 key = 1;
|
286
|
+
uint256 numLeaves = 5;
|
287
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
288
|
+
// correct data: 01
|
289
|
+
bytes memory data = bytes(hex"012345");
|
290
|
+
(bool isValid, BinaryMerkleTree.ErrorCodes error) = BinaryMerkleTree.verify(root, proof, data);
|
291
|
+
assertEq(uint256(BinaryMerkleTree.ErrorCodes.NoError), uint256(error));
|
292
|
+
assertTrue(!isValid);
|
293
|
+
}
|
294
|
+
|
295
|
+
function testValidSlice() public {
|
296
|
+
bytes32[] memory data = new bytes32[](4);
|
297
|
+
data[0] = "a";
|
298
|
+
data[1] = "b";
|
299
|
+
data[2] = "c";
|
300
|
+
data[3] = "d";
|
301
|
+
|
302
|
+
bytes32[] memory result = BinaryMerkleTree.slice(data, 1, 3);
|
303
|
+
|
304
|
+
assertEq(result[0], data[1]);
|
305
|
+
assertEq(result[1], data[2]);
|
306
|
+
}
|
307
|
+
|
308
|
+
function testSameKeyAndLeavesNumber() external {
|
309
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
310
|
+
bytes32[] memory sideNodes = new bytes32[](0);
|
311
|
+
uint256 key = 3;
|
312
|
+
uint256 numLeaves = 3;
|
313
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
314
|
+
bytes memory data = bytes(hex"01");
|
315
|
+
(bool isValid,) = BinaryMerkleTree.verify(root, proof, data);
|
316
|
+
assertTrue(!isValid);
|
317
|
+
}
|
318
|
+
|
319
|
+
function testConsecutiveKeyAndNumberOfLeaves() external {
|
320
|
+
bytes32 root = 0xb855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f;
|
321
|
+
bytes32[] memory sideNodes = new bytes32[](0);
|
322
|
+
uint256 key = 6;
|
323
|
+
uint256 numLeaves = 7;
|
324
|
+
BinaryMerkleProof memory proof = BinaryMerkleProof(sideNodes, key, numLeaves);
|
325
|
+
bytes memory data = bytes(hex"01");
|
326
|
+
(bool isValid,) = BinaryMerkleTree.verify(root, proof, data);
|
327
|
+
assertTrue(!isValid);
|
328
|
+
}
|
329
|
+
|
330
|
+
function testInvalidSliceBeginEnd() public {
|
331
|
+
bytes32[] memory data = new bytes32[](4);
|
332
|
+
data[0] = "a";
|
333
|
+
data[1] = "b";
|
334
|
+
data[2] = "c";
|
335
|
+
data[3] = "d";
|
336
|
+
|
337
|
+
vm.expectRevert("Invalid range: _begin is greater than _end");
|
338
|
+
binaryMerkleTreeMock.slice(data, 2, 1);
|
339
|
+
}
|
340
|
+
|
341
|
+
function testOutOfBoundsSlice() public {
|
342
|
+
bytes32[] memory data = new bytes32[](4);
|
343
|
+
data[0] = "a";
|
344
|
+
data[1] = "b";
|
345
|
+
data[2] = "c";
|
346
|
+
data[3] = "d";
|
347
|
+
|
348
|
+
vm.expectRevert("Invalid range: _begin or _end are out of bounds");
|
349
|
+
binaryMerkleTreeMock.slice(data, 2, 5);
|
350
|
+
}
|
351
|
+
|
352
|
+
// header.dat, blob.dat, and proofs.json test vectors included in ../../test/ and serialized to hex bytes using Rust
|
353
|
+
// The hard-coded serialized proofs and data were generated in Rust, with this code
|
354
|
+
// https://github.com/S1nus/hyperchain-da/blob/main/src/clients/celestia/evm_types.rs#L132
|
355
|
+
function testMultiproof() public {
|
356
|
+
bytes memory proofData =
|
357
|
+
hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000006ce29bcde696f84e35c5626904542a549b080e92603243b34794242473940706917519bf954f5b30495af5c8cdb9983e6319104badc1ea811ed2c421018a3ad7821ea268d3540deab8f9b2024464618610c9a7083620badcf505bda647cc8e9f82bfc87d990d8344f6efd44fcb09b46b87f9a92230d41329452efee8656c6760a9ad9f3a95af971e89e2a80b255bb56d5aae15de69803b52aa5079b33374b16e16178fc62a2f2ce6bf21909c0a0edea9525486e0ece65bff23499342cca38dd62";
|
358
|
+
BinaryMerkleMultiproof memory multiproof = abi.decode(proofData, (BinaryMerkleMultiproof));
|
359
|
+
bytes32 dataroot = hex"ef8920d86519bd5f8ce3c802b84fc9b9512483e4d4a5c9608b44af4d6639f7d1";
|
360
|
+
bytes memory leafData =
|
361
|
+
hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000102030405746e218305fe3dbbef65feceed939fe8dd93c88b06c95473fbe344fb864060f3000000000000000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000102030405000000000000000000000000000000000000000000000000010203040555cd7fb524ae792c9d4bc8946d07209728c533a3e14d4e7c0c95c0b150d0c284000000000000000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000001020304050000000000000000000000000000000000000000000000000102030405505c1e7c897461a152e152f1ff3ecc358fefdf1f69448ab1165b6ca76836933b000000000000000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000001020304050000000000000000000000000000000000000000000000000102030405100a0548893d8eab0322f34f45ac84785cdf50dfab5102a12d958e6031bacebe000000000000000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000102030405000000000000000000000000000000000000000000000000010203040566e5eb1da67430f204a3c5615591f71316695c7ec1f1f713cde7e936d4a43ec1000000000000000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000001020304050000000000000000000000000000000000000000000000000102030405d2a5de6299e28c2fec359a2718599f5ac22c2948a71d26a438295e531b6f4cb5000000000000000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000001020304050000000000000000000000000000000000000000000000000102030405688c5238e50c0a8a556bfabff31bef1fa9cdd812c9fd4dcee5c2a0836f687fbf000000000000000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000001020304050000000000000000000000000000000000000000000000000102030405b55a5b1efc2a22cdbfa21d050bd67147ff2b936c68354eb1a83bcdf14eb57e38000000000000000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000010203040500000000000000000000000000000000000000000067480c4a88c4d129947e11c33fa811daa791771e591dd933498d1212d46b8cde9c34c28831b0b532000000000000";
|
362
|
+
bytes[] memory leaves = abi.decode(leafData, (bytes[]));
|
363
|
+
assertTrue(BinaryMerkleTree.verifyMulti(dataroot, multiproof, leaves));
|
364
|
+
}
|
365
|
+
}
|