@@ -3,13 +3,16 @@ pragma solidity ^0.8;
33
44import "rainbow-bridge-sol/nearbridge/contracts/AdminControlled.sol " ;
55import "rainbow-bridge-sol/nearbridge/contracts/INearBridge.sol " ;
6- import "rainbow-bridge-sol/nearbridge/contracts/NearDecoder.sol " ;
76import "./ProofDecoder.sol " ;
87import "./INearProver.sol " ;
98
9+ error InvalidOutcomeRoot ();
10+ error InvalidBlockRoot ();
11+ error InvalidOutcomeRootRoot ();
12+ error InvalidBlockHash ();
13+
1014contract NearProver is INearProver , AdminControlled {
1115 using Borsh for Borsh.Data;
12- using NearDecoder for Borsh.Data;
1316 using ProofDecoder for Borsh.Data;
1417
1518 INearBridge public bridge;
@@ -25,6 +28,27 @@ contract NearProver is INearProver, AdminControlled {
2528 uint constant UNPAUSE_ALL = 0 ;
2629 uint constant PAUSED_VERIFY = 1 ;
2730
31+ function lookupItems (ProofDecoder.LookupMerklePath memory proof , ProofDecoder.MerklePath memory cache )
32+ internal
33+ pure
34+ returns (ProofDecoder.MerklePath memory path )
35+ {
36+ for (uint256 i = 0 ; i < proof.items.length ; i++ ) {
37+ if (proof.items.length == 0 ) {
38+ return path;
39+ }
40+ path.items = new ProofDecoder.MerklePathItem [](proof.items.length );
41+ ProofDecoder.LookupMerklePathItem memory lookup = proof.items[i];
42+
43+ if (lookup.either == 0 ) {
44+ path.items[i] = cache.items[lookup.index];
45+ } else if (lookup.either == 1 ) {
46+ path.items[i] = lookup.item;
47+ }
48+ }
49+ return path;
50+ }
51+
2852 function proveOutcome (bytes memory proofData , uint64 blockHeight )
2953 public
3054 view
@@ -33,30 +57,57 @@ contract NearProver is INearProver, AdminControlled {
3357 returns (bool )
3458 {
3559 Borsh.Data memory borsh = Borsh.from (proofData);
36- ProofDecoder.FullOutcomeProof memory fullOutcomeProof = borsh.decodeFullOutcomeProof ();
60+ ProofDecoder.Proof memory proof = borsh.decodeProof ();
3761 borsh.done ();
3862
39- bytes32 hash = _computeRoot (
40- fullOutcomeProof.outcome_proof.outcome_with_id.hash,
41- fullOutcomeProof.outcome_proof.proof
42- );
63+ bytes32 hash;
64+ ProofDecoder.BlindedProof memory blindedProof;
65+ ProofDecoder.MerklePath memory path;
66+ ProofDecoder.LookupMerklePathItem memory lookup;
67+
68+ for (uint256 index = 0 ; index < proof.batch.length ; index++ ) {
69+ blindedProof = proof.batch[index];
70+
71+ // Outcome proof
72+ hash = _computeLookupRoot (blindedProof.outcome_hash, blindedProof.outcome_proof, proof.cache);
73+
74+ //Outcome root proof
75+ hash = _computeLookupRoot (sha256 (abi.encodePacked (hash)), blindedProof.outcome_root_proof, proof.cache);
4376
44- hash = sha256 (abi.encodePacked (hash));
77+ if (hash != blindedProof.transaction_header.outcome_root) {
78+ revert InvalidOutcomeRoot ();
79+ }
4580
46- hash = _computeRoot (hash, fullOutcomeProof.outcome_root_proof);
81+ // Block hash from header
82+ hash = blindedProof.transaction_header.hash;
83+ if (hash != blindedProof.outcome_proof_block_hash) {
84+ revert InvalidBlockHash ();
85+ }
4786
48- require (
49- hash == fullOutcomeProof.block_header_lite.inner_lite.outcome_root,
50- "NearProver: outcome merkle proof is not valid "
51- );
87+ // Block proof
88+ path.items = new ProofDecoder.MerklePathItem [](
89+ blindedProof.block_proof.items.length + proof.ancestry.items.length
90+ );
91+ for (uint256 i = 0 ; i < blindedProof.block_proof.items.length ; i++ ) {
92+ lookup = blindedProof.block_proof.items[i];
93+ if (lookup.either == 0 ) {
94+ path.items[i] = proof.cache.items[lookup.index];
95+ } else if (lookup.either == 1 ) {
96+ path.items[i] = lookup.item;
97+ }
98+ }
99+ for (uint256 i = 0 ; i < proof.ancestry.items.length ; i++ ) {
100+ path.items[blindedProof.block_proof.items.length + i] = proof.ancestry.items[i];
101+ }
52102
53- bytes32 expectedBlockMerkleRoot = bridge.blockMerkleRoots (blockHeight);
103+ hash = _computeRoot (hash, path);
104+ if (hash != proof.client_block_merkle_root) {
105+ revert InvalidBlockRoot ();
106+ }
54107
55- require (
56- _computeRoot (fullOutcomeProof.block_header_lite.hash, fullOutcomeProof.block_proof) ==
57- expectedBlockMerkleRoot,
58- "NearProver: block proof is not valid "
59- );
108+ bytes32 expectedBlockMerkleRoot = bridge.blockMerkleRoots (blockHeight);
109+ require (hash == expectedBlockMerkleRoot, "NearProver: block merkle proof is not expected merkle root " );
110+ }
60111
61112 return true ;
62113 }
@@ -72,4 +123,22 @@ contract NearProver is INearProver, AdminControlled {
72123 }
73124 }
74125 }
126+
127+ function _computeLookupRoot (
128+ bytes32 node ,
129+ ProofDecoder.LookupMerklePath memory proof ,
130+ ProofDecoder.MerklePath memory cache
131+ ) internal pure returns (bytes32 hash ) {
132+ ProofDecoder.MerklePath memory path;
133+ path.items = new ProofDecoder.MerklePathItem [](proof.items.length );
134+ for (uint i = 0 ; i < proof.items.length ; i++ ) {
135+ ProofDecoder.LookupMerklePathItem memory item = proof.items[i];
136+ if (item.either == 0 ) {
137+ path.items[i] = cache.items[item.index];
138+ } else if (item.either == 1 ) {
139+ path.items[i] = item.item;
140+ }
141+ }
142+ return _computeRoot (node, path);
143+ }
75144}
0 commit comments