From e79573959c5e47fa7cedcfab09ce5ec378a22cae Mon Sep 17 00:00:00 2001 From: Zehui Zheng Date: Mon, 9 Oct 2023 23:06:04 +0800 Subject: [PATCH] feat: blockchain agnostic inputs --- .../rollups/contracts/inputs/IInputBox.sol | 4 +-- onchain/rollups/contracts/inputs/InputBox.sol | 6 ++-- .../rollups/contracts/library/LibInput.sol | 35 +++++++++--------- .../test/foundry/inputs/InputBox.t.sol | 36 ++++++++++++++----- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/onchain/rollups/contracts/inputs/IInputBox.sol b/onchain/rollups/contracts/inputs/IInputBox.sol index 521de8e5..c6a38469 100644 --- a/onchain/rollups/contracts/inputs/IInputBox.sol +++ b/onchain/rollups/contracts/inputs/IInputBox.sol @@ -9,7 +9,7 @@ interface IInputBox { /// @param dapp The address of the DApp /// @param inputIndex The index of the input in the input box /// @param sender The address that sent the input - /// @param input The contents of the input + /// @param input The input payload /// @dev MUST be triggered on a successful call to `addInput`. event InputAdded( address indexed dapp, @@ -20,7 +20,7 @@ interface IInputBox { /// @notice Add an input to a DApp's input box. /// @param _dapp The address of the DApp - /// @param _input The contents of the input + /// @param _input The input payload /// @return The hash of the input plus some extra metadata /// @dev MUST fire an `InputAdded` event accordingly. /// Input larger than machine limit will raise `InputSizeExceedsLimit` error. diff --git a/onchain/rollups/contracts/inputs/InputBox.sol b/onchain/rollups/contracts/inputs/InputBox.sol index 6999a195..015bf9f6 100644 --- a/onchain/rollups/contracts/inputs/InputBox.sol +++ b/onchain/rollups/contracts/inputs/InputBox.sol @@ -34,12 +34,12 @@ contract InputBox is IInputBox { bytes32[] storage inputBox = inputBoxes[_dapp]; uint256 inputIndex = inputBox.length; - bytes32 inputHash = LibInput.computeInputHash( + bytes32 inputHash = LibInput.computeEvmInputHash( msg.sender, block.number, block.timestamp, - _input, - inputIndex + inputIndex, + _input ); // add input to the input box diff --git a/onchain/rollups/contracts/library/LibInput.sol b/onchain/rollups/contracts/library/LibInput.sol index 1cae79cb..a8bf4cc7 100644 --- a/onchain/rollups/contracts/library/LibInput.sol +++ b/onchain/rollups/contracts/library/LibInput.sol @@ -16,32 +16,29 @@ library LibInput { /// @param sender `msg.sender` /// @param blockNumber `block.number` /// @param blockTimestamp `block.timestamp` - /// @param input The input blob /// @param inputIndex The index of the input in the input box - /// @return The input hash - function computeInputHash( + /// @param input The input payload + /// @return The EVM input hash + function computeEvmInputHash( address sender, uint256 blockNumber, uint256 blockTimestamp, - bytes calldata input, - uint256 inputIndex + uint256 inputIndex, + bytes calldata input ) internal pure returns (bytes32) { - if (input.length > CanonicalMachine.INPUT_MAX_SIZE) { - revert InputSizeExceedsLimit(); - } - - bytes32 keccakMetadata = keccak256( - abi.encode( - sender, - blockNumber, - blockTimestamp, - 0, //TODO decide how to deal with epoch index - inputIndex // input index in the input box - ) + bytes memory inputBlob = abi.encodeWithSignature( + "EvmInput(address,uint256,uint256,uint256,bytes)", + sender, + blockNumber, + blockTimestamp, + inputIndex, + input ); - bytes32 keccakInput = keccak256(input); + if (inputBlob.length > CanonicalMachine.INPUT_MAX_SIZE) { + revert InputSizeExceedsLimit(); + } - return keccak256(abi.encode(keccakMetadata, keccakInput)); + return keccak256(inputBlob); } } diff --git a/onchain/rollups/test/foundry/inputs/InputBox.t.sol b/onchain/rollups/test/foundry/inputs/InputBox.t.sol index d8902bee..dfdb1744 100644 --- a/onchain/rollups/test/foundry/inputs/InputBox.t.sol +++ b/onchain/rollups/test/foundry/inputs/InputBox.t.sol @@ -98,12 +98,12 @@ contract InputBoxHandler is Test { ); // Compute the input hash from the arguments passed to `addInput` - bytes32 computedInputHash = LibInput.computeInputHash( + bytes32 computedInputHash = LibInput.computeEvmInputHash( msg.sender, block.number, block.timestamp, - _input, - index + index, + _input ); // Check if the input hash matches the computed one @@ -158,13 +158,31 @@ contract InputBoxTest is Test { assertEq(inputBox.getNumberOfInputs(_dapp), 0); } + function getMaxInputPayloadLength() internal pure returns (uint256) { + // an input blob instance + bytes memory blob = abi.encodeWithSignature( + "EvmInput(address,uint256,uint256,uint256,bytes)", + address(0), + 0, + 0, + 0, + new bytes(32) + ); + // number of bytes in input blob excluding input payload + uint256 extraBytes = blob.length - 32; + // because it's abi encoded, input payloads are stored as multiples of 32 bytes + return ((CanonicalMachine.INPUT_MAX_SIZE - extraBytes) / 32) * 32; + } + function testAddLargeInput() public { address dapp = vm.addr(1); - inputBox.addInput(dapp, new bytes(CanonicalMachine.INPUT_MAX_SIZE)); + uint256 maxLength = getMaxInputPayloadLength(); + + inputBox.addInput(dapp, new bytes(maxLength)); vm.expectRevert(LibInput.InputSizeExceedsLimit.selector); - inputBox.addInput(dapp, new bytes(CanonicalMachine.INPUT_MAX_SIZE + 1)); + inputBox.addInput(dapp, new bytes(maxLength + 1)); } // fuzz testing with multiple inputs @@ -175,7 +193,7 @@ contract InputBoxTest is Test { // assume #bytes for each input is within bounds for (uint256 i; i < numInputs; ++i) { - vm.assume(_inputs[i].length <= CanonicalMachine.INPUT_MAX_SIZE); + vm.assume(_inputs[i].length <= getMaxInputPayloadLength()); } // adding inputs @@ -199,12 +217,12 @@ contract InputBoxTest is Test { // testing added inputs for (uint256 i; i < numInputs; ++i) { // compute input hash for each input - bytes32 inputHash = LibInput.computeInputHash( + bytes32 inputHash = LibInput.computeEvmInputHash( address(this), i, // block.number i + year2022, // block.timestamp - _inputs[i], - i // inputBox.length + i, // inputBox.length + _inputs[i] ); // test if input hash is the same as in InputBox assertEq(inputHash, inputBox.getInputHash(_dapp, i));