diff --git a/packages/protocol/contracts/L1/ITaikoL1.sol b/packages/protocol/contracts/L1/ITaikoL1.sol index 3a66ba2a4d..c70a9a7cf7 100644 --- a/packages/protocol/contracts/L1/ITaikoL1.sol +++ b/packages/protocol/contracts/L1/ITaikoL1.sol @@ -52,7 +52,13 @@ interface ITaikoL1 { /// @param _blockIds The indices of the blocks to prove. /// @param _inputArr An list of abi-encoded (TaikoData.BlockMetadata, TaikoData.Transition, /// TaikoData.TierProof) tuples. - function proveBlocks(uint64[] calldata _blockIds, bytes[] calldata _inputArr) external; + /// @param _proof The proof. + function proveBlocks( + uint64[] calldata _blockIds, + bytes[] calldata _inputArr, + bytes calldata _proof + ) + external; /// @notice Verifies up to a certain number of blocks. /// @param _maxBlocksToVerify Max number of blocks to verify. diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index 52948f129a..ca20318892 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -148,7 +148,8 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { /// @inheritdoc ITaikoL1 function proveBlocks( uint64[] calldata _blockIds, - bytes[] calldata _inputArr + bytes[] calldata _inputArr, + bytes calldata _proof ) external whenNotPaused @@ -162,8 +163,24 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { TaikoData.Config memory config = getConfig(); + // Run over all blocks and collect all blocks that need to be verified + IVerifier.Context[] memory ctxs = new IVerifier.Context[](_blockIds.length); for (uint256 i; i < _blockIds.length; ++i) { - _proveBlock(_blockIds[i], _inputArr[i], config); + ctxs[i] = _proveBlock(_blockIds[i], _inputArr[i], config); + // We have to make sure that we only batch verify the same type of proof + if ( + ctxs[i].verifier != ctxs[0].verifier || ctxs[i].isContesting != ctxs[0].isContesting + ) { + revert L1_INVALID_PARAMS(); + } + } + + // Batch verify the blocks + // Do not run proof verification to contest an existing proof + if (!ctxs[0].isContesting) { + IVerifier(ctxs[0].verifier).verifyProofs( + ctxs, abi.decode(_proof, (TaikoData.TierProof)) + ); } } @@ -342,8 +359,9 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { TaikoData.Config memory _config ) internal + returns (IVerifier.Context memory ctx_) { - LibProving.proveBlock(state, _config, this, _blockId, _input); + ctx_ = LibProving.proveBlock(state, _config, this, _blockId, _input); if (LibUtils.shouldVerifyBlocks(_config, _blockId, false)) { LibVerifying.verifyBlocks(state, _config, this, _config.maxBlocksToVerify); diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index 7ed20e21cb..ab898733e5 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -136,6 +136,7 @@ library LibProving { bytes calldata _input ) public + returns (IVerifier.Context memory ctx_) { Local memory local; @@ -260,7 +261,7 @@ library LibProving { address verifier = _resolver.resolve(local.tier.verifierName, false); bool isContesting = proof.tier == ts.tier && local.tier.contestBond != 0; - IVerifier.Context memory ctx = IVerifier.Context({ + ctx_ = IVerifier.Context({ metaHash: local.metaHash, blobHash: meta.blobHash, // Separate msgSender to allow the prover to be any address in the future. @@ -268,10 +269,10 @@ library LibProving { msgSender: msg.sender, blockId: local.blockId, isContesting: isContesting, - blobUsed: meta.blobUsed + blobUsed: meta.blobUsed, + tran: tran, + verifier: verifier }); - - IVerifier(verifier).verifyProof(ctx, tran, proof); } local.isTopTier = local.tier.contestBond == 0; diff --git a/packages/protocol/contracts/L1/provers/GuardianProver.sol b/packages/protocol/contracts/L1/provers/GuardianProver.sol index a86f820719..dc24f18c45 100644 --- a/packages/protocol/contracts/L1/provers/GuardianProver.sol +++ b/packages/protocol/contracts/L1/provers/GuardianProver.sol @@ -227,15 +227,10 @@ contract GuardianProver is IVerifier, EssentialContract { } /// @inheritdoc IVerifier - function verifyProof( - Context calldata _ctx, - TaikoData.Transition calldata, - TaikoData.TierProof calldata - ) - external - view - { - if (_ctx.msgSender != address(this)) revert GV_PERMISSION_DENIED(); + function verifyProofs(Context[] calldata _ctx, TaikoData.TierProof calldata) external view { + for (uint256 i = 0; i < _ctx.length; i++) { + if (_ctx[i].msgSender != address(this)) revert GV_PERMISSION_DENIED(); + } } /// @notice Returns the number of guardians diff --git a/packages/protocol/contracts/verifiers/IVerifier.sol b/packages/protocol/contracts/verifiers/IVerifier.sol index a3e0091fcd..dc753d0964 100644 --- a/packages/protocol/contracts/verifiers/IVerifier.sol +++ b/packages/protocol/contracts/verifiers/IVerifier.sol @@ -15,16 +15,12 @@ interface IVerifier { bool isContesting; bool blobUsed; address msgSender; + TaikoData.Transition tran; + address verifier; } /// @notice Verifies a proof. /// @param _ctx The context of the proof verification. - /// @param _tran The transition to verify. /// @param _proof The proof to verify. - function verifyProof( - Context calldata _ctx, - TaikoData.Transition calldata _tran, - TaikoData.TierProof calldata _proof - ) - external; + function verifyProofs(Context[] calldata _ctx, TaikoData.TierProof calldata _proof) external; } diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index def44adfa6..87229c7a6e 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -47,39 +47,48 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { } /// @inheritdoc IVerifier - function verifyProof( - Context calldata _ctx, - TaikoData.Transition calldata _tran, - TaikoData.TierProof calldata _proof - ) - external - { - // Do not run proof verification to contest an existing proof - if (_ctx.isContesting) return; - + function verifyProofs(Context[] calldata _ctx, TaikoData.TierProof calldata _proof) external { // Decode will throw if not proper length/encoding - (bytes memory seal, bytes32 imageId) = abi.decode(_proof.data, (bytes, bytes32)); + (bytes memory seal, bytes32 blockImageId, bytes32 aggregationImageId) = + abi.decode(_proof.data, (bytes, bytes32, bytes32)); - if (!isImageTrusted[imageId]) { + // Check if the aggregation program is trusted + if (!isImageTrusted[aggregationImageId]) { + revert RISC_ZERO_INVALID_IMAGE_ID(); + } + // Check if the block proving program is trusted + if (!isImageTrusted[blockImageId]) { revert RISC_ZERO_INVALID_IMAGE_ID(); } - bytes32 publicInputHash = LibPublicInput.hashPublicInputs( - _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, taikoChainId() - ); + // Collect public inputs + bytes32[] memory public_inputs = new bytes32[](_ctx.length + 1); + // First public input is the block proving program key + public_inputs[0] = blockImageId; + // All other inputs are the block program public inputs (a single 32 byte value) + for (uint256 i = 0; i < _ctx.length; i++) { + public_inputs[i + 1] = LibPublicInput.hashPublicInputs( + _ctx[i].tran, + address(this), + address(0), + _ctx[i].prover, + _ctx[i].metaHash, + taikoChainId() + ); + emit ProofVerified(_ctx[i].metaHash, public_inputs[i + 1]); + } // journalDigest is the sha256 hash of the hashed public input - bytes32 journalDigest = sha256(bytes.concat(FIXED_JOURNAL_HEADER, publicInputHash)); + bytes32 journalDigest = + sha256(bytes.concat(FIXED_JOURNAL_HEADER, abi.encodePacked(public_inputs))); // call risc0 verifier contract (bool success,) = resolve(LibStrings.B_RISCZERO_GROTH16_VERIFIER, false).staticcall( - abi.encodeCall(IRiscZeroVerifier.verify, (seal, imageId, journalDigest)) + abi.encodeCall(IRiscZeroVerifier.verify, (seal, aggregationImageId, journalDigest)) ); if (!success) { revert RISC_ZERO_INVALID_PROOF(); } - - emit ProofVerified(_ctx.metaHash, publicInputHash); } function taikoChainId() internal view virtual returns (uint64) { diff --git a/packages/protocol/contracts/verifiers/SP1Verifier.sol b/packages/protocol/contracts/verifiers/SP1Verifier.sol index 90b627d78c..9c271fb93a 100644 --- a/packages/protocol/contracts/verifiers/SP1Verifier.sol +++ b/packages/protocol/contracts/verifiers/SP1Verifier.sol @@ -41,33 +41,53 @@ contract SP1Verifier is EssentialContract, IVerifier { } /// @inheritdoc IVerifier - function verifyProof( - Context calldata _ctx, - TaikoData.Transition calldata _tran, + function verifyProofs( + Context[] calldata _ctx, TaikoData.TierProof calldata _proof ) external view { - // Do not run proof verification to contest an existing proof - if (_ctx.isContesting) return; + // Extract the necessary data + bytes32 aggregation_program = bytes32(_proof.data[0:32]); + bytes32 block_proving_program = bytes32(_proof.data[32:64]); + bytes memory proof = _proof.data[64:]; - // Avoid in-memory decoding, so in-place decode with slicing. - // e.g.: bytes32 programVKey = bytes32(_proof.data[0:32]); - if (!isProgramTrusted[bytes32(_proof.data[0:32])]) { + // Check if the aggregation program is trusted + if (!isProgramTrusted[aggregation_program]) { + revert SP1_INVALID_PROGRAM_VKEY(); + } + // Check if the block proving program is trusted + if (!isProgramTrusted[block_proving_program]) { revert SP1_INVALID_PROGRAM_VKEY(); } - // Need to be converted from bytes32 to bytes - bytes32 hashedPublicInput = LibPublicInput.hashPublicInputs( - _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, taikoChainId() - ); + // Collect public inputs + bytes32[] memory public_inputs = new bytes32[](_ctx.length + 1); + // First public input is the block proving program key + public_inputs[0] = block_proving_program; + // All other inputs are the block program public inputs (a single 32 byte value) + for (uint256 i = 0; i < _ctx.length; i++) { + // Need to be converted from bytes32 to bytes + public_inputs[i + 1] = sha256( + abi.encodePacked( + LibPublicInput.hashPublicInputs( + _ctx[i].tran, + address(this), + address(0), + _ctx[i].prover, + _ctx[i].metaHash, + taikoChainId() + ) + ) + ); + } // _proof.data[32:] is the succinct's proof position (bool success,) = sp1RemoteVerifier().staticcall( abi.encodeCall( ISP1Verifier.verifyProof, - (bytes32(_proof.data[0:32]), abi.encode(hashedPublicInput), _proof.data[32:]) + (block_proving_program, abi.encodePacked(public_inputs), proof) ) ); diff --git a/packages/protocol/contracts/verifiers/SgxVerifier.sol b/packages/protocol/contracts/verifiers/SgxVerifier.sol index b197118202..f0e4c2e15b 100644 --- a/packages/protocol/contracts/verifiers/SgxVerifier.sol +++ b/packages/protocol/contracts/verifiers/SgxVerifier.sol @@ -143,30 +143,43 @@ contract SgxVerifier is EssentialContract, IVerifier { } /// @inheritdoc IVerifier - function verifyProof( - Context calldata _ctx, - TaikoData.Transition calldata _tran, + function verifyProofs( + Context[] calldata _ctx, TaikoData.TierProof calldata _proof ) external onlyFromNamed(LibStrings.B_TAIKO) { - // Do not run proof verification to contest an existing proof - if (_ctx.isContesting) return; - // Size is: 89 bytes - // 4 bytes + 20 bytes + 65 bytes (signature) = 89 - if (_proof.data.length != 89) revert SGX_INVALID_PROOF(); + // 4 bytes + 20 bytes + 20 bytes + 65 bytes (signature) = 109 + if (_proof.data.length != 109) revert SGX_INVALID_PROOF(); uint32 id = uint32(bytes4(_proof.data[:4])); - address newInstance = address(bytes20(_proof.data[4:24])); - - address oldInstance = ECDSA.recover( - LibPublicInput.hashPublicInputs( - _tran, address(this), newInstance, _ctx.prover, _ctx.metaHash, taikoChainId() - ), - _proof.data[24:] - ); + address oldInstance = address(bytes20(_proof.data[4:24])); + address newInstance = address(bytes20(_proof.data[24:44])); + bytes memory signature = _proof.data[44:]; + + // Collect public inputs + bytes32[] memory public_inputs = new bytes32[](_ctx.length + 1); + // First public input is the current instance public key + public_inputs[0] = bytes32(bytes20(oldInstance)); + // All other inputs are the block program public inputs (a single 32 byte value) + for (uint256 i = 0; i < _ctx.length; i++) { + // TODO: For now this assumes the new instance public key to remain the same + public_inputs[i + 1] = LibPublicInput.hashPublicInputs( + _ctx[i].tran, + address(this), + newInstance, + _ctx[i].prover, + _ctx[i].metaHash, + taikoChainId() + ); + } + + // Verify the blocks + if (oldInstance != ECDSA.recover(keccak256(abi.encodePacked(public_inputs)), signature)) { + revert SGX_INVALID_PROOF(); + } if (!_isInstanceValid(id, oldInstance)) revert SGX_INVALID_INSTANCE(); diff --git a/packages/protocol/test/L1/GuardianProver2.t.sol b/packages/protocol/test/L1/GuardianProver2.t.sol index 3aede68a4e..c148b8609d 100644 --- a/packages/protocol/test/L1/GuardianProver2.t.sol +++ b/packages/protocol/test/L1/GuardianProver2.t.sol @@ -17,6 +17,14 @@ contract TestGuardianProver2 is TaikoL1TestBase { // Tests `verifyProof()` with the correct prover function test_guardian_prover_verifyProof() public view { + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32(0), + blockHash: bytes32(0), + stateRoot: bytes32(0), + graffiti: bytes32(0) + }); + // Context IVerifier.Context memory ctx = IVerifier.Context({ metaHash: bytes32(0), @@ -25,27 +33,31 @@ contract TestGuardianProver2 is TaikoL1TestBase { msgSender: address(gp), blockId: 10, isContesting: false, - blobUsed: false - }); - - // Transition - TaikoData.Transition memory transition = TaikoData.Transition({ - parentHash: bytes32(0), - blockHash: bytes32(0), - stateRoot: bytes32(0), - graffiti: bytes32(0) + blobUsed: false, + tran: transition, + verifier: address(gp) }); // TierProof TaikoData.TierProof memory proof = TaikoData.TierProof({ tier: LibTiers.TIER_GUARDIAN, data: "" }); - // `verifyProof()` - gp.verifyProof(ctx, transition, proof); + // `verifyProofs()` + IVerifier.Context[] memory ctxs = new IVerifier.Context[](1); + ctxs[0] = ctx; + gp.verifyProofs(ctxs, proof); } // Tests `verifyProof()` with the wrong prover function test_guardian_prover_verifyProof_invalidProver() public { + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32(0), + blockHash: bytes32(0), + stateRoot: bytes32(0), + graffiti: bytes32(0) + }); + // Context IVerifier.Context memory ctx = IVerifier.Context({ metaHash: bytes32(0), @@ -54,23 +66,20 @@ contract TestGuardianProver2 is TaikoL1TestBase { msgSender: Alice, blockId: 10, isContesting: false, - blobUsed: false - }); - - // Transition - TaikoData.Transition memory transition = TaikoData.Transition({ - parentHash: bytes32(0), - blockHash: bytes32(0), - stateRoot: bytes32(0), - graffiti: bytes32(0) + blobUsed: false, + tran: transition, + verifier: address(gp) }); // TierProof TaikoData.TierProof memory proof = TaikoData.TierProof({ tier: LibTiers.TIER_GUARDIAN, data: "" }); - // `verifyProof()` with invalid ctx.prover + IVerifier.Context[] memory ctxs = new IVerifier.Context[](1); + ctxs[0] = ctx; + + // `verifyProofs()` with invalid ctx.prover vm.expectRevert(GuardianProver.GV_PERMISSION_DENIED.selector); - gp.verifyProof(ctx, transition, proof); + gp.verifyProofs(ctxs, proof); } } diff --git a/packages/protocol/test/verifiers/RiscZeroGroth16Verifier.t.sol b/packages/protocol/test/verifiers/RiscZeroGroth16Verifier.t.sol index 0ff7677e0f..60f873e0f5 100644 --- a/packages/protocol/test/verifiers/RiscZeroGroth16Verifier.t.sol +++ b/packages/protocol/test/verifiers/RiscZeroGroth16Verifier.t.sol @@ -56,19 +56,18 @@ contract RiscZeroGroth16VerifierTest is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _generateTaikoMainnetContextAndTransition(); + IVerifier.Context[] memory ctx = _generateTaikoMainnetContextAndTransition(); uint64 chainId = L1.getConfig().chainId; bytes32 pi = LibPublicInput.hashPublicInputs( - transition, address(rv), address(0), ctx.prover, ctx.metaHash, chainId + ctx[0].tran, address(rv), address(0), ctx[0].prover, ctx[0].metaHash, chainId ); bytes memory header = hex"20000000"; // [32, 0, 0, 0] -- big-endian uint32(32) for hash // bytes len assert(sha256(bytes.concat(header, pi)) == journalDigest); // `verifyProof()` - rv.verifyProof(ctx, transition, proof); + rv.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -76,25 +75,29 @@ contract RiscZeroGroth16VerifierTest is TaikoL1TestBase { function _generateTaikoMainnetContextAndTransition() internal pure - returns (IVerifier.Context memory ctx, TaikoData.Transition memory transition) + returns (IVerifier.Context[] memory ctxs) { + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: 0x317de24b32f09629524133334ad552a14e3de603d71a9cf9e88d722809f101b3, + blockHash: 0x9966d3cf051d3d1e44e2a740169627506a619257c95374e812ca572de91ed885, + stateRoot: 0x3ae3de1afa16b93a5c7ea20a0b36b43357061f5b8ef857053d68b2735c3df860, + graffiti: 0x8008500000000000000000000000000000000000000000000000000000000000 + }); // Context - ctx = IVerifier.Context({ + IVerifier.Context memory ctx = IVerifier.Context({ metaHash: bytes32(0xd7efb262f6f25cc817452a622009a22e5868e53e1f934d899d3ec68d8c4f2c5b), blobHash: bytes32(0x015cc9688f24b8d2195e46829b3f726ce006884d5fd2760b7cf414bab9a1b231), prover: address(0x70997970C51812dc3A010C7d01b50e0d17dc79C8), msgSender: address(0), blockId: 223_248, //from mainnet isContesting: false, - blobUsed: true + blobUsed: true, + tran: transition, + verifier: address(0) }); - // Transition - transition = TaikoData.Transition({ - parentHash: 0x317de24b32f09629524133334ad552a14e3de603d71a9cf9e88d722809f101b3, - blockHash: 0x9966d3cf051d3d1e44e2a740169627506a619257c95374e812ca572de91ed885, - stateRoot: 0x3ae3de1afa16b93a5c7ea20a0b36b43357061f5b8ef857053d68b2735c3df860, - graffiti: 0x8008500000000000000000000000000000000000000000000000000000000000 - }); + ctxs = new IVerifier.Context[](1); + ctxs[0] = ctx; } } diff --git a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol index d39966fd6d..0632e45c10 100644 --- a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol +++ b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol @@ -76,11 +76,10 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); // `verifyProof()` - rv.verifyProof(ctx, transition, proof); + rv.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -102,11 +101,10 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_IMAGE_ID.selector); - rv.verifyProof(ctx, transition, proof); + rv.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -128,11 +126,10 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_PROOF.selector); - rv.verifyProof(ctx, transition, proof); + rv.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -140,25 +137,30 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { function _getDummyContextAndTransition() internal pure - returns (IVerifier.Context memory ctx, TaikoData.Transition memory transition) + returns (IVerifier.Context[] memory ctxs) { + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32("12"), + blockHash: bytes32("34"), + stateRoot: bytes32("56"), + graffiti: bytes32("78") + }); + // Context - ctx = IVerifier.Context({ + IVerifier.Context memory ctx = IVerifier.Context({ metaHash: bytes32("ab"), blobHash: bytes32("cd"), prover: address(0), msgSender: address(0), blockId: 10, isContesting: false, - blobUsed: false + blobUsed: false, + tran: transition, + verifier: address(0) }); - // Transition - transition = TaikoData.Transition({ - parentHash: bytes32("12"), - blockHash: bytes32("34"), - stateRoot: bytes32("56"), - graffiti: bytes32("78") - }); + ctxs = new IVerifier.Context[](1); + ctxs[0] = ctx; } } diff --git a/packages/protocol/test/verifiers/SP1Verifier.t.sol b/packages/protocol/test/verifiers/SP1Verifier.t.sol index 49b375c3ff..cb6d05d31a 100644 --- a/packages/protocol/test/verifiers/SP1Verifier.t.sol +++ b/packages/protocol/test/verifiers/SP1Verifier.t.sol @@ -72,11 +72,10 @@ contract TestSP1Verifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); // `verifyProof()` - sp1.verifyProof(ctx, transition, proof); + sp1.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -97,12 +96,11 @@ contract TestSP1Verifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); // `verifyProof()` vm.expectRevert(SP1Verifier.SP1_INVALID_PROGRAM_VKEY.selector); - sp1.verifyProof(ctx, transition, proof); + sp1.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -124,11 +122,10 @@ contract TestSP1Verifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); - (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = - _getDummyContextAndTransition(); + IVerifier.Context[] memory ctx = _getDummyContextAndTransition(); vm.expectRevert(SP1Verifier.SP1_INVALID_PROOF.selector); - sp1.verifyProof(ctx, transition, proof); + sp1.verifyProofs(ctx, proof); vm.stopPrank(); } @@ -136,25 +133,30 @@ contract TestSP1Verifier is TaikoL1TestBase { function _getDummyContextAndTransition() internal pure - returns (IVerifier.Context memory ctx, TaikoData.Transition memory transition) + returns (IVerifier.Context[] memory ctxs) { + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32("12"), + blockHash: bytes32("34"), + stateRoot: bytes32("56"), + graffiti: bytes32("78") + }); + // Context - ctx = IVerifier.Context({ + IVerifier.Context memory ctx = IVerifier.Context({ metaHash: bytes32("ab"), blobHash: bytes32("cd"), prover: address(0), msgSender: address(0), blockId: 10, isContesting: false, - blobUsed: false + blobUsed: false, + tran: transition, + verifier: address(0) }); - // Transition - transition = TaikoData.Transition({ - parentHash: bytes32("12"), - blockHash: bytes32("34"), - stateRoot: bytes32("56"), - graffiti: bytes32("78") - }); + ctxs = new IVerifier.Context[](1); + ctxs[0] = ctx; } }