Skip to content

Commit a4ba7e9

Browse files
committed
Make InputBox require application contract deployment
1 parent 2d47ce6 commit a4ba7e9

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

.changeset/angry-worms-dig.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cartesi/rollups": major
3+
---
4+
5+
Make `InputBox` require application contract deployment

src/inputs/IInputBox.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ interface IInputBox {
2222
/// @param input The input
2323
event InputAdded(address indexed appContract, uint256 indexed index, bytes input);
2424

25+
/// @notice The application contract was not deployed yet.
26+
/// @param appContract The application contract address
27+
error ApplicationContractNotDeployed(address appContract);
28+
2529
/// @notice Input is too large.
2630
/// @param appContract The application contract address
2731
/// @param inputLength The input length

src/inputs/InputBox.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
// (c) Cartesi and individual authors (see AUTHORS)
22
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
33

4-
pragma solidity ^0.8.18;
4+
pragma solidity ^0.8.27;
55

66
import {IInputBox} from "./IInputBox.sol";
77
import {CanonicalMachine} from "../common/CanonicalMachine.sol";
88
import {Inputs} from "../common/Inputs.sol";
99
import {LibBinaryMerkleTree} from "../library/LibBinaryMerkleTree.sol";
1010
import {LibKeccak256} from "../library/LibKeccak256.sol";
1111
import {LibMath} from "../library/LibMath.sol";
12+
import {LibAddress} from "../library/LibAddress.sol";
1213

1314
contract InputBox is IInputBox {
1415
using LibMath for uint256;
16+
using LibAddress for address;
1517
using LibBinaryMerkleTree for bytes;
1618

1719
/// @notice Deployment block number
@@ -26,6 +28,8 @@ contract InputBox is IInputBox {
2628
override
2729
returns (bytes32)
2830
{
31+
require(appContract.hasCode(), ApplicationContractNotDeployed(appContract));
32+
2933
bytes32[] storage inputBox = _inputBoxes[appContract];
3034

3135
uint256 index = inputBox.length;

src/library/LibAddress.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,11 @@ library LibAddress {
5252
returndata.raise();
5353
}
5454
}
55+
56+
/// @notice Check whether an account has any code.
57+
/// @param account The account address
58+
/// @return Whether the account has any code.
59+
function hasCode(address account) internal view returns (bool) {
60+
return account.code.length > 0;
61+
}
5562
}

test/inputs/InputBox.t.sol

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
pragma solidity ^0.8.22;
55

66
import {Test} from "forge-std-1.9.6/src/Test.sol";
7+
8+
import {Create2} from "@openzeppelin-contracts-5.2.0/utils/Create2.sol";
9+
710
import {InputBox} from "src/inputs/InputBox.sol";
811
import {IInputBox} from "src/inputs/IInputBox.sol";
912
import {CanonicalMachine} from "src/common/CanonicalMachine.sol";
@@ -14,6 +17,8 @@ import {LibMath} from "src/library/LibMath.sol";
1417

1518
import {EvmAdvanceEncoder} from "../util/EvmAdvanceEncoder.sol";
1619

20+
contract MockApplication {}
21+
1722
contract InputBoxTest is Test {
1823
using LibMath for uint256;
1924
using LibBinaryMerkleTree for bytes;
@@ -34,8 +39,27 @@ contract InputBoxTest is Test {
3439
assertEq(_inputBox.getNumberOfInputs(appContract), 0);
3540
}
3641

42+
function testAddInputNoContract(
43+
uint256 privateKey,
44+
bytes32 salt,
45+
bytes calldata payload
46+
) external {
47+
privateKey = boundPrivateKey(privateKey);
48+
49+
_testAddInputNoContract(address(0), payload);
50+
_testAddInputNoContract(vm.addr(privateKey), payload);
51+
52+
bytes32 bytecodeHash = keccak256(type(MockApplication).creationCode);
53+
address appContract = Create2.computeAddress(salt, bytecodeHash);
54+
_testAddInputNoContract(appContract, payload);
55+
56+
assertEq(appContract, address(new MockApplication{salt: salt}()));
57+
assertGt(appContract.code.length, 0);
58+
_inputBox.addInput(appContract, payload);
59+
}
60+
3761
function testAddLargeInput() public {
38-
address appContract = vm.addr(1);
62+
address appContract = address(new MockApplication());
3963
uint256 max = _getMaxInputPayloadLength();
4064

4165
_inputBox.addInput(appContract, new bytes(max));
@@ -55,9 +79,9 @@ contract InputBoxTest is Test {
5579
_inputBox.addInput(appContract, largePayload);
5680
}
5781

58-
function testAddInput(uint64 chainId, address appContract, bytes[] calldata payloads)
59-
public
60-
{
82+
function testAddInput(uint64 chainId, bytes[] calldata payloads) public {
83+
address appContract = address(new MockApplication());
84+
6185
vm.chainId(chainId); // foundry limits chain id to be less than 2^64 - 1
6286

6387
uint256 numPayloads = payloads.length;
@@ -120,6 +144,18 @@ contract InputBoxTest is Test {
120144
}
121145
}
122146

147+
function _testAddInputNoContract(address appContract, bytes calldata payload)
148+
internal
149+
{
150+
assertEq(appContract.code.length, 0, "expected account with no code");
151+
vm.expectRevert(
152+
abi.encodeWithSelector(
153+
IInputBox.ApplicationContractNotDeployed.selector, appContract
154+
)
155+
);
156+
_inputBox.addInput(appContract, payload);
157+
}
158+
123159
function _prevrandao(uint256 blockNumber) internal pure returns (uint256) {
124160
return uint256(keccak256(abi.encode("prevrandao", blockNumber)));
125161
}

0 commit comments

Comments
 (0)