From cde7f96486cc21befc9a05fc3b27a7d6ebb5d5f8 Mon Sep 17 00:00:00 2001 From: Gabriel de Quadros Ligneul Date: Fri, 27 Sep 2024 11:22:41 -0300 Subject: [PATCH] Add contracts for HostIO gas tests These contracts will be used by the nitro tests that check the equivalence between stylus and EVM. Co-authored-by: Aman Sanghi --- hardhat.config.ts | 10 +++ src/mocks/CreateTest.sol | 42 +++++++++ src/mocks/HostioTest.sol | 189 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 src/mocks/CreateTest.sol create mode 100644 src/mocks/HostioTest.sol diff --git a/hardhat.config.ts b/hardhat.config.ts index 3599427d..0176a6da 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -34,6 +34,16 @@ const solidity = { }, }, }, + 'src/mocks/HostioTest.sol': { + version: '0.8.24', + settings: { + optimizer: { + enabled: true, + runs: 100, + }, + evmVersion: 'cancun', + }, + }, }, } diff --git a/src/mocks/CreateTest.sol b/src/mocks/CreateTest.sol new file mode 100644 index 00000000..03ae24c3 --- /dev/null +++ b/src/mocks/CreateTest.sol @@ -0,0 +1,42 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.0; + +/* + * This contract is the solidity equivalent of the stylus create test contract. + */ +contract CreateTest { + // solhint-disable no-complex-fallback + // solhint-disable reason-string + // solhint-disable avoid-low-level-calls + // solhint-disable-next-line prettier/prettier + fallback(bytes calldata input) external returns (bytes memory) { + uint8 kind = uint8(input[0]); + input = input[1:]; + + bytes32 endowment = bytes32(input[:32]); + input = input[32:]; + + address addr; + + if (kind == 2) { + bytes32 salt = bytes32(input[:32]); + input = input[32:]; + bytes memory code = input; + assembly { + addr := create2(endowment, add(code, 32), mload(code), salt) + } + } else { + bytes memory code = input; + assembly { + addr := create(endowment, add(code, 32), mload(code)) + } + } + if (addr == address(0)) { + revert("failed to create"); + } + return addr.code; + } +} diff --git a/src/mocks/HostioTest.sol b/src/mocks/HostioTest.sol new file mode 100644 index 00000000..2256f733 --- /dev/null +++ b/src/mocks/HostioTest.sol @@ -0,0 +1,189 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity ^0.8.24; + +/* + * HostioTest is a test contract used to compare EVM with Stylus. + */ +contract HostioTest { + function exitEarly() external pure { + assembly { + stop() + } + } + + function transientLoadBytes32(bytes32 key) external view returns (bytes32) { + bytes32 data; + assembly { + data := tload(key) + } + return data; + } + + function transientStoreBytes32(bytes32 key, bytes32 value) external { + assembly { + // solc-ignore-next-line transient-storage + tstore(key, value) + } + } + + function returnDataSize() external pure returns (uint256) { + uint256 size; + assembly { + size := returndatasize() + } + return size; + } + + function emitLog( + bytes calldata _data, + int8 n, + bytes32 t1, + bytes32 t2, + bytes32 t3, + bytes32 t4 + ) external { + bytes memory data = _data; + if (n == 0) { + assembly { + log0(add(data, 32), mload(data)) + } + } else if (n == 1) { + assembly { + log1(add(data, 32), mload(data), t1) + } + } else if (n == 2) { + assembly { + log2(add(data, 32), mload(data), t1, t2) + } + } else if (n == 3) { + assembly { + log3(add(data, 32), mload(data), t1, t2, t3) + } + } else if (n == 4) { + assembly { + log4(add(data, 32), mload(data), t1, t2, t3, t4) + } + } else { + revert("invalid n for emit log"); + } + } + + function accountBalance(address account) external view returns (uint256) { + return account.balance; + } + + function accountCode(address account) external view returns (bytes memory) { + return account.code; + } + + function accountCodeSize(address account) external view returns (uint256) { + uint256 size; + assembly { + size := extcodesize(account) + } + return size; + } + + function accountCodehash(address account) external view returns (bytes32) { + bytes32 hash; + assembly { + hash := extcodehash(account) + } + return hash; + } + + function evmGasLeft() external view returns (uint256) { + return gasleft(); + } + + function evmInkLeft() external view returns (uint256) { + return gasleft(); + } + + function blockBasefee() external view returns (uint256) { + return block.basefee; + } + + function chainid() external view returns (uint256) { + return block.chainid; + } + + function blockCoinbase() external view returns (address) { + return block.coinbase; + } + + function blockGasLimit() external view returns (uint256) { + return block.gaslimit; + } + + function blockNumber() external view returns (uint256) { + return block.number; + } + + function blockTimestamp() external view returns (uint256) { + return block.timestamp; + } + + function contractAddress() external view returns (address) { + return address(this); + } + + function mathDiv(uint256 a, uint256 b) external pure returns (uint256) { + return a / b; + } + + function mathMod(uint256 a, uint256 b) external pure returns (uint256) { + return a % b; + } + + function mathPow(uint256 a, uint256 b) external pure returns (uint256) { + uint256 result; + assembly { + result := exp(a, b) + } + return result; + } + + function mathAddMod( + uint256 a, + uint256 b, + uint256 c + ) external pure returns (uint256) { + return addmod(a, b, c); + } + + function mathMulMod( + uint256 a, + uint256 b, + uint256 c + ) external pure returns (uint256) { + return mulmod(a, b, c); + } + + function msgSender() external view returns (address) { + return msg.sender; + } + + function msgValue() external payable returns (uint256) { + return msg.value; + } + + function keccak(bytes calldata preimage) external pure returns (bytes32) { + return keccak256(preimage); + } + + function txGasPrice() external view returns (uint256) { + return tx.gasprice; + } + + function txInkPrice() external view returns (uint256) { + return tx.gasprice; + } + + function txOrigin() external view returns (address) { + return tx.origin; + } +}