From ef8e92cbd65a92b29b8b9d9386e22765ebb3f650 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 30 Jan 2025 16:13:57 +0800 Subject: [PATCH] fix proposer check --- .../layer1/preconf/iface/IPreconfRouter.sol | 1 + .../layer1/preconf/impl/PreconfRouter.sol | 5 ++ .../layer1/preconf/router/RouterTest.t.sol | 58 ++++++++++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/iface/IPreconfRouter.sol b/packages/protocol/contracts/layer1/preconf/iface/IPreconfRouter.sol index c351f2d37b..a174091f8c 100644 --- a/packages/protocol/contracts/layer1/preconf/iface/IPreconfRouter.sol +++ b/packages/protocol/contracts/layer1/preconf/iface/IPreconfRouter.sol @@ -6,6 +6,7 @@ import "src/layer1/based/ITaikoInbox.sol"; /// @title IPreconfRouter /// @custom:security-contact security@taiko.xyz interface IPreconfRouter { + error InvalidParams(); error NotTheOperator(); error ProposerIsNotTheSender(); diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfRouter.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfRouter.sol index bd0f4fb942..551d760140 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfRouter.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfRouter.sol @@ -27,6 +27,11 @@ contract PreconfRouter is EssentialContract, IPreconfRouter { external returns (ITaikoInbox.BatchMetadata memory meta_) { + // Make sure the proposer must be the msg.sender itself. + ITaikoInbox.BatchParams memory batchParams = + abi.decode(_batchParams, (ITaikoInbox.BatchParams)); + require(msg.sender == batchParams.proposer, InvalidParams()); + // Sender must be the selected operator for the epoch address selectedOperator = IPreconfWhitelist(resolve(LibStrings.B_PRECONF_WHITELIST, false)).getOperatorForEpoch(); diff --git a/packages/protocol/test/layer1/preconf/router/RouterTest.t.sol b/packages/protocol/test/layer1/preconf/router/RouterTest.t.sol index 695388aa9f..ff43469269 100644 --- a/packages/protocol/test/layer1/preconf/router/RouterTest.t.sol +++ b/packages/protocol/test/layer1/preconf/router/RouterTest.t.sol @@ -85,13 +85,16 @@ contract RouterTest is RouterTestBase { // Warp to arbitrary slot in epoch 2 vm.warp(epochTwoStart + 2 * LibPreconfConstants.SECONDS_IN_SLOT); + ITaikoInbox.BatchParams memory batchParams; + batchParams.proposer = David; + // Prank as David (not the selected operator) and propose blocks vm.prank(David); vm.expectRevert(IPreconfRouter.NotTheOperator.selector); - router.proposePreconfedBlocks("", "", ""); + router.proposePreconfedBlocks("", abi.encode(batchParams), ""); } - function test_proposePreconfedBlocks_proposerNotSender() external { + function test_proposePreconfedBlocks_InvalidProposerParam() external { address[] memory operators = new address[](3); operators[0] = Bob; operators[1] = Carol; @@ -138,7 +141,56 @@ contract RouterTest is RouterTestBase { // Prank as Carol (selected operator) and propose blocks vm.prank(Carol); - vm.expectRevert(IPreconfRouter.ProposerIsNotTheSender.selector); + vm.expectRevert(IPreconfRouter.InvalidParams.selector); + router.proposePreconfedBlocks("", abi.encode(params), ""); + } + + function test_proposePreconfedBlocks_proposerNotSender() external { + address[] memory operators = new address[](1); + operators[0] = Bob; + addOperators(operators); + + // Setup mock beacon for operator selection + vm.chainId(1); + uint256 epochOneStart = LibPreconfConstants.getGenesisTimestamp(block.chainid); + // Current epoch + uint256 epochTwoStart = epochOneStart + LibPreconfConstants.SECONDS_IN_EPOCH; + + MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); + bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol + + address beaconBlockRootContract = LibPreconfConstants.getBeaconBlockRootContract(); + vm.etch(beaconBlockRootContract, address(mockBeacon).code); + MockBeaconBlockRoot(payable(beaconBlockRootContract)).set( + epochOneStart + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot + ); + + // Setup block params + ITaikoInbox.BlockParams[] memory blockParams = new ITaikoInbox.BlockParams[](1); + blockParams[0] = ITaikoInbox.BlockParams({ numTransactions: 1, timeShift: 1 }); + + ITaikoInbox.BlobParams memory blobParams; + + // Create batch params with DIFFERENT proposer than sender + ITaikoInbox.BatchParams memory params = ITaikoInbox.BatchParams({ + proposer: Carol, // Set different proposer than sender (Carol) + coinbase: address(0), + parentMetaHash: bytes32(0), + anchorBlockId: 0, + anchorInput: bytes32(0), + lastBlockTimestamp: uint64(block.timestamp), + revertIfNotFirstProposal: false, + signalSlots: new bytes32[](0), + blobParams: blobParams, + blocks: blockParams + }); + + // Warp to arbitrary slot in epoch 2 + vm.warp(epochTwoStart + 2 * LibPreconfConstants.SECONDS_IN_SLOT); + + // Prank as Carol (selected operator) and propose blocks + vm.prank(Carol); + vm.expectRevert(IPreconfRouter.NotTheOperator.selector); router.proposePreconfedBlocks("", abi.encode(params), ""); } }