From 941c8ce936be21428496f96fedb667ad00b0c9db Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 15:22:58 +0000 Subject: [PATCH 01/11] Use native blobhash and blobbasefee opcodes --- deploy/SequencerInboxStubCreator.js | 4 -- hardhat.config.ts | 36 ++++++++++++----- src/bridge/SequencerInbox.sol | 23 ++++------- src/libraries/BlobDataHashReader.sol | 33 ++++++++++++++++ src/libraries/GasRefundEnabled.sol | 26 +++++++------ src/libraries/IReader4844.sol | 9 ----- src/mocks/SequencerInboxStub.sol | 3 +- src/rollup/ValidatorWallet.sol | 6 +-- test/contract/sequencerInbox.spec.4844.ts | 4 +- .../sequencerInboxForceInclude.spec.ts | 2 - test/contract/toolkit4844.ts | 16 +------- test/foundry/BridgeCreator.t.sol | 3 -- test/foundry/RollupCreator.t.sol | 3 -- test/foundry/SequencerInbox.t.sol | 17 ++++---- yul/Reader4844.yul | 39 ------------------- 15 files changed, 95 insertions(+), 129 deletions(-) create mode 100644 src/libraries/BlobDataHashReader.sol delete mode 100644 src/libraries/IReader4844.sol delete mode 100644 yul/Reader4844.yul diff --git a/deploy/SequencerInboxStubCreator.js b/deploy/SequencerInboxStubCreator.js index e61a227c..defc1bf3 100644 --- a/deploy/SequencerInboxStubCreator.js +++ b/deploy/SequencerInboxStubCreator.js @@ -6,9 +6,6 @@ module.exports = async hre => { const { deployer } = await getNamedAccounts() const bridge = await ethers.getContract('BridgeStub') - const reader4844 = await Toolkit4844.deployReader4844( - await ethers.getSigner(deployer) - ) const maxTime = { delayBlocks: 10000, futureBlocks: 10000, @@ -22,7 +19,6 @@ module.exports = async hre => { deployer, maxTime, 117964, - reader4844.address, false, ], }) diff --git a/hardhat.config.ts b/hardhat.config.ts index 401a29b3..bd81a4f5 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -11,6 +11,17 @@ import dotenv from 'dotenv' dotenv.config() +const cancunSolSettings = { + version: '0.8.24', + settings: { + evmVersion: 'cancun', + optimizer: { + enabled: true, + runs: 500, + }, + }, +} + const solidity = { compilers: [ { @@ -23,7 +34,16 @@ const solidity = { }, }, ], - overrides: {}, + overrides: { + 'src/bridge/SequencerInbox.sol': cancunSolSettings, + 'src/rollup/BridgeCreator.sol': cancunSolSettings, + 'src/rollup/RollupCreator.sol': cancunSolSettings, + 'src/mocks/SequencerInboxStub.sol': cancunSolSettings, + 'src/libraries/GasRefundEnabled.sol': cancunSolSettings, + 'src/libraries/BlobDataHashReader.sol': cancunSolSettings, + 'src/rollup/ValidatorWallet.sol': cancunSolSettings, + 'src/rollup/ValidatorWalletCreator.sol': cancunSolSettings, + }, } if (process.env['INTERFACE_TESTER_SOLC_VERSION']) { @@ -36,14 +56,12 @@ if (process.env['INTERFACE_TESTER_SOLC_VERSION']) { }, }, }) - solidity.overrides = { - 'src/test-helpers/InterfaceCompatibilityTester.sol': { - version: process.env['INTERFACE_TESTER_SOLC_VERSION'], - settings: { - optimizer: { - enabled: true, - runs: 100, - }, + solidity.overrides['src/test-helpers/InterfaceCompatibilityTester.sol'] = { + version: process.env['INTERFACE_TESTER_SOLC_VERSION'], + settings: { + optimizer: { + enabled: true, + runs: 100, }, }, } diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index f69b8f0b..be77c469 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -2,7 +2,7 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; +pragma solidity 0.8.24; import { AlreadyInit, @@ -42,12 +42,12 @@ import "../rollup/IRollupLogic.sol"; import "./Messages.sol"; import "../precompiles/ArbGasInfo.sol"; import "../precompiles/ArbSys.sol"; -import "../libraries/IReader4844.sol"; import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol"; import "../libraries/DelegateCallAware.sol"; import {IGasRefunder} from "../libraries/IGasRefunder.sol"; import {GasRefundEnabled} from "../libraries/GasRefundEnabled.sol"; +import {BlobDataHashReader} from "../libraries/BlobDataHashReader.sol"; import "../libraries/ArbitrumChecker.sol"; import {IERC20Bridge} from "./IERC20Bridge.sol"; @@ -109,7 +109,6 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox } mapping(address => bool) public isSequencer; - IReader4844 public immutable reader4844; // see ISequencerInbox.MaxTimeVariation uint64 internal delayBlocks; @@ -130,16 +129,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox constructor( uint256 _maxDataSize, - IReader4844 reader4844_, bool _isUsingFeeToken ) { maxDataSize = _maxDataSize; - if (hostChainIsArbitrum) { - if (reader4844_ != IReader4844(address(0))) revert DataBlobsNotSupported(); - } else { - if (reader4844_ == IReader4844(address(0))) revert InitParamZero("Reader4844"); - } - reader4844 = reader4844_; isUsingFeeToken = _isUsingFeeToken; } @@ -366,7 +358,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox IGasRefunder gasRefunder, uint256 prevMessageCount, uint256 newMessageCount - ) external refundsGas(gasRefunder, IReader4844(address(0))) { + ) external refundsGas(gasRefunder, false) { // solhint-disable-next-line avoid-tx-origin if (msg.sender != tx.origin) revert NotOrigin(); if (!isBatchPoster[msg.sender]) revert NotBatchPoster(); @@ -417,7 +409,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox IGasRefunder gasRefunder, uint256 prevMessageCount, uint256 newMessageCount - ) external refundsGas(gasRefunder, reader4844) { + ) external refundsGas(gasRefunder, true) { if (!isBatchPoster[msg.sender]) revert NotBatchPoster(); ( bytes32 dataHash, @@ -479,7 +471,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox IGasRefunder gasRefunder, uint256 prevMessageCount, uint256 newMessageCount - ) external override refundsGas(gasRefunder, IReader4844(address(0))) { + ) external override refundsGas(gasRefunder, false) { if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster(); (bytes32 dataHash, IBridge.TimeBounds memory timeBounds) = formCallDataHash( data, @@ -608,6 +600,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox return (keccak256(bytes.concat(header, data)), timeBounds); } + /// @dev Form a hash of the data being provided in 4844 data blobs /// @param afterDelayedMessagesRead The delayed messages count read up to /// @return The data hash @@ -622,14 +615,14 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox uint256 ) { - bytes32[] memory dataHashes = reader4844.getDataHashes(); + bytes32[] memory dataHashes = BlobDataHashReader.getDataHashes(); if (dataHashes.length == 0) revert MissingDataHashes(); (bytes memory header, IBridge.TimeBounds memory timeBounds) = packHeader( afterDelayedMessagesRead ); - uint256 blobCost = reader4844.getBlobBaseFee() * GAS_PER_BLOB * dataHashes.length; + uint256 blobCost = block.blobbasefee * GAS_PER_BLOB * dataHashes.length; return ( keccak256(bytes.concat(header, DATA_BLOB_HEADER_FLAG, abi.encodePacked(dataHashes))), timeBounds, diff --git a/src/libraries/BlobDataHashReader.sol b/src/libraries/BlobDataHashReader.sol new file mode 100644 index 00000000..11f11bf2 --- /dev/null +++ b/src/libraries/BlobDataHashReader.sol @@ -0,0 +1,33 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE +// SPDX-License-Identifier: BUSL-1.1 + +// solhint-disable-next-line compiler-version +pragma solidity ^0.8.24; + +library BlobDataHashReader { + /// @notice Gets all the data blob hashes on this transaction + /// @dev Will revert if called on chains that do not support the 4844 blobhash opcode + function getDataHashes() internal view returns(bytes32[] memory) { + // we use assembly so that we can efficiently push into a memory arracy + assembly { + let i := 0 + for { } true { } + { + let h := blobhash(i) + // the blob hash opcode returns 0 where no blob hash exists for that index + if iszero(h) { break } + + // store the blob hash + mstore(add(mul(i, 32), 64), h) + + // set the number of hashes + i := add(i, 1) + } + // format an return an array of the data blob hashes + mstore(0, 32) + mstore(32, i) + return(0, add(mul(i, 32), 64)) + } + } +} \ No newline at end of file diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index 60287ee0..60be806b 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -3,9 +3,9 @@ // SPDX-License-Identifier: BUSL-1.1 // solhint-disable-next-line compiler-version -pragma solidity ^0.8.0; +pragma solidity ^0.8.24; -import "./IReader4844.sol"; +import "./BlobDataHashReader.sol"; import "./IGasRefunder.sol"; abstract contract GasRefundEnabled { @@ -14,7 +14,7 @@ abstract contract GasRefundEnabled { /// @dev this refunds the sender for execution costs of the tx /// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging /// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded - modifier refundsGas(IGasRefunder gasRefunder, IReader4844 reader4844) { + modifier refundsGas(IGasRefunder gasRefunder, bool includeBlobCosts) { uint256 startGasLeft = gasleft(); _; if (address(gasRefunder) != address(0)) { @@ -32,17 +32,19 @@ abstract contract GasRefundEnabled { } else { // for similar reasons to above we only refund blob gas when the tx.origin is the msg.sender // this avoids the caller being able to send blobs to other contracts and still get refunded here - if (address(reader4844) != address(0)) { + + // since 4844 may not be enable yet, or may never be enabled on this chain we do not want to always call the + // blobhash or blobbasefee opcodes. We can only detect the presence of these opcodes without reverting + // by either doing a call and checking success or providing a bool for specific code paths. We go for + // the bool approach as it's cheaper + if(includeBlobCosts) { // add any cost for 4844 data, the data hash reader throws an error prior to 4844 being activated // we do this addition here rather in the GasRefunder so that we can check the msg.sender is the tx.origin - try reader4844.getDataHashes() returns (bytes32[] memory dataHashes) { - if (dataHashes.length != 0) { - uint256 blobBasefee = reader4844.getBlobBaseFee(); - startGasLeft += - (dataHashes.length * gasPerBlob * blobBasefee) / - block.basefee; - } - } catch {} + bytes32[] memory dataHashes = BlobDataHashReader.getDataHashes(); + if (dataHashes.length != 0) { + // CHRIS: TODO: should we check basefee == 0? we often have that for estimation + startGasLeft += (dataHashes.length * gasPerBlob * block.blobbasefee) / block.basefee; + } } } diff --git a/src/libraries/IReader4844.sol b/src/libraries/IReader4844.sol deleted file mode 100644 index a66ebae5..00000000 --- a/src/libraries/IReader4844.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity >=0.6.9 <0.9.0; - -interface IReader4844 { - /// @notice Returns the current BLOBBASEFEE - function getBlobBaseFee() external view returns (uint256); - - /// @notice Returns all the data hashes of all the blobs on the current transaction - function getDataHashes() external view returns (bytes32[] memory); -} diff --git a/src/mocks/SequencerInboxStub.sol b/src/mocks/SequencerInboxStub.sol index e78d9479..88db5f00 100644 --- a/src/mocks/SequencerInboxStub.sol +++ b/src/mocks/SequencerInboxStub.sol @@ -14,9 +14,8 @@ contract SequencerInboxStub is SequencerInbox { address sequencer_, ISequencerInbox.MaxTimeVariation memory maxTimeVariation_, uint256 maxDataSize_, - IReader4844 reader4844_, bool isUsingFeeToken_ - ) SequencerInbox(maxDataSize_, reader4844_, isUsingFeeToken_) { + ) SequencerInbox(maxDataSize_, isUsingFeeToken_) { bridge = bridge_; rollup = IOwnable(msg.sender); delayBlocks = maxTimeVariation_.delayBlocks; diff --git a/src/rollup/ValidatorWallet.sol b/src/rollup/ValidatorWallet.sol index 0d7cbace..21d90c34 100644 --- a/src/rollup/ValidatorWallet.sol +++ b/src/rollup/ValidatorWallet.sol @@ -110,7 +110,7 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware, GasRefundEnab bytes[] calldata data, address[] calldata destination, uint256[] calldata amount - ) public payable onlyExecutorOrOwner refundsGas(gasRefunder, IReader4844(address(0))) { + ) public payable onlyExecutorOrOwner refundsGas(gasRefunder, false) { uint256 numTxes = data.length; if (numTxes != destination.length) revert BadArrayLength(numTxes, destination.length); if (numTxes != amount.length) revert BadArrayLength(numTxes, amount.length); @@ -145,7 +145,7 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware, GasRefundEnab bytes calldata data, address destination, uint256 amount - ) public payable onlyExecutorOrOwner refundsGas(gasRefunder, IReader4844(address(0))) { + ) public payable onlyExecutorOrOwner refundsGas(gasRefunder, false) { if (data.length > 0) require(destination.isContract(), "NO_CODE_AT_ADDR"); validateExecuteTransaction(destination); // We use a low level call here to allow for contract and non-contract calls @@ -169,7 +169,7 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware, GasRefundEnab IGasRefunder gasRefunder, IChallengeManager manager, uint64[] calldata challenges - ) public onlyExecutorOrOwner refundsGas(gasRefunder, IReader4844(address(0))) { + ) public onlyExecutorOrOwner refundsGas(gasRefunder, false) { uint256 challengesCount = challenges.length; for (uint256 i = 0; i < challengesCount; i++) { try manager.timeout(challenges[i]) {} catch (bytes memory error) { diff --git a/test/contract/sequencerInbox.spec.4844.ts b/test/contract/sequencerInbox.spec.4844.ts index e40804cb..3f64c51f 100644 --- a/test/contract/sequencerInbox.spec.4844.ts +++ b/test/contract/sequencerInbox.spec.4844.ts @@ -282,12 +282,10 @@ describe('SequencerInbox', async () => { await rollupOwner.getAddress() ) - const reader4844 = await Toolkit4844.deployReader4844(fundingWallet) - const sequencerInboxFac = new SequencerInbox__factory(deployer) const seqInboxTemplate = await sequencerInboxFac.deploy( 117964, - reader4844.address + false ) const inboxFac = new Inbox__factory(deployer) const inboxTemplate = await inboxFac.deploy(117964) diff --git a/test/contract/sequencerInboxForceInclude.spec.ts b/test/contract/sequencerInboxForceInclude.spec.ts index 92b1df6f..e438ad2a 100644 --- a/test/contract/sequencerInboxForceInclude.spec.ts +++ b/test/contract/sequencerInboxForceInclude.spec.ts @@ -232,13 +232,11 @@ describe('SequencerInboxForceInclude', async () => { )) as RollupMock__factory const rollup = await rollupMockFac.deploy(await rollupOwner.getAddress()) - const reader4844 = await Toolkit4844.deployReader4844(admin) const sequencerInboxFac = (await ethers.getContractFactory( 'SequencerInbox' )) as SequencerInbox__factory const seqInboxTemplate = await sequencerInboxFac.deploy( 117964, - reader4844.address, false ) const inboxFac = (await ethers.getContractFactory( diff --git a/test/contract/toolkit4844.ts b/test/contract/toolkit4844.ts index b0271641..3f35b859 100644 --- a/test/contract/toolkit4844.ts +++ b/test/contract/toolkit4844.ts @@ -1,9 +1,7 @@ import { execSync } from 'child_process' -import { ContractFactory, Signer, Wallet, ethers } from 'ethers' +import { ContractFactory, Signer, ethers } from 'ethers' import * as http from 'http' -import { IReader4844, IReader4844__factory } from '../../build/types' import { JsonRpcProvider } from '@ethersproject/providers' -import { bytecode as Reader4844Bytecode } from '../../out/yul/Reader4844.yul/Reader4844.json' const wait = async (ms: number) => new Promise((res, rej) => { @@ -121,16 +119,4 @@ export class Toolkit4844 { throw new Error('Error sending blob tx:\n' + res) } } - - public static async deployReader4844(wallet: Signer): Promise { - const contractFactory = new ContractFactory( - IReader4844__factory.abi, - Reader4844Bytecode, - wallet - ) - const reader4844 = await contractFactory.deploy() - await reader4844.deployed() - - return IReader4844__factory.connect(reader4844.address, wallet) - } } diff --git a/test/foundry/BridgeCreator.t.sol b/test/foundry/BridgeCreator.t.sol index 58e4928d..7f55a261 100644 --- a/test/foundry/BridgeCreator.t.sol +++ b/test/foundry/BridgeCreator.t.sol @@ -13,14 +13,12 @@ contract BridgeCreatorTest is Test { BridgeCreator public creator; address public owner = address(100); uint256 public constant MAX_DATA_SIZE = 117_964; - IReader4844 dummyReader4844 = IReader4844(address(137)); BridgeCreator.BridgeContracts ethBasedTemplates = BridgeCreator.BridgeContracts({ bridge: new Bridge(), sequencerInbox: new SequencerInbox( MAX_DATA_SIZE, - dummyReader4844, false ), inbox: new Inbox(MAX_DATA_SIZE), @@ -32,7 +30,6 @@ contract BridgeCreatorTest is Test { bridge: new ERC20Bridge(), sequencerInbox: new SequencerInbox( MAX_DATA_SIZE, - dummyReader4844, true ), inbox: new ERC20Inbox(MAX_DATA_SIZE), diff --git a/test/foundry/RollupCreator.t.sol b/test/foundry/RollupCreator.t.sol index 591f04aa..959e9ebe 100644 --- a/test/foundry/RollupCreator.t.sol +++ b/test/foundry/RollupCreator.t.sol @@ -27,7 +27,6 @@ contract RollupCreatorTest is Test { IRollupAdmin public rollupAdmin; IRollupUser public rollupUser; DeployHelper public deployHelper; - IReader4844 dummyReader4844 = IReader4844(address(137)); // 1 gwei uint256 public constant MAX_FEE_PER_GAS = 1_000_000_000; @@ -37,7 +36,6 @@ contract RollupCreatorTest is Test { bridge: new Bridge(), sequencerInbox: new SequencerInbox( MAX_DATA_SIZE, - dummyReader4844, false ), inbox: new Inbox(MAX_DATA_SIZE), @@ -48,7 +46,6 @@ contract RollupCreatorTest is Test { bridge: new ERC20Bridge(), sequencerInbox: new SequencerInbox( MAX_DATA_SIZE, - dummyReader4844, true ), inbox: new ERC20Inbox(MAX_DATA_SIZE), diff --git a/test/foundry/SequencerInbox.t.sol b/test/foundry/SequencerInbox.t.sol index c6889820..ae46399e 100644 --- a/test/foundry/SequencerInbox.t.sol +++ b/test/foundry/SequencerInbox.t.sol @@ -51,7 +51,6 @@ contract SequencerInboxTest is Test { }); address dummyInbox = address(139); address proxyAdmin = address(140); - IReader4844 dummyReader4844 = IReader4844(address(137)); uint256 constant public MAX_DATA_SIZE = 117964; @@ -66,7 +65,6 @@ contract SequencerInboxTest is Test { SequencerInbox seqInboxImpl = new SequencerInbox( maxDataSize, - isArbHosted ? IReader4844(address(0)) : dummyReader4844, false ); SequencerInbox seqInbox = SequencerInbox(address(new TransparentUpgradeableProxy(address(seqInboxImpl), proxyAdmin, ""))); @@ -100,7 +98,7 @@ contract SequencerInboxTest is Test { abi.encodeWithSelector(ArbSys.arbOSVersion.selector), abi.encode(uint256(11)) ); - SequencerInbox seqInboxImpl = new SequencerInbox(maxDataSize, IReader4844(address(0)), true); + SequencerInbox seqInboxImpl = new SequencerInbox(maxDataSize, true); SequencerInbox seqInbox = SequencerInbox(address(new TransparentUpgradeableProxy(address(seqInboxImpl), proxyAdmin, ""))); seqInbox.initialize( bridge, @@ -237,7 +235,7 @@ contract SequencerInboxTest is Test { /* solhint-disable func-name-mixedcase */ function testConstructor() public { - SequencerInbox seqInboxLogic = new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, false); + SequencerInbox seqInboxLogic = new SequencerInbox(MAX_DATA_SIZE, false); assertEq(seqInboxLogic.maxDataSize(), MAX_DATA_SIZE, "Invalid MAX_DATA_SIZE"); assertEq(seqInboxLogic.isUsingFeeToken(), false, "Invalid isUsingFeeToken"); @@ -245,7 +243,7 @@ contract SequencerInboxTest is Test { assertEq(seqInboxProxy.maxDataSize(), MAX_DATA_SIZE, "Invalid MAX_DATA_SIZE"); assertEq(seqInboxProxy.isUsingFeeToken(), false, "Invalid isUsingFeeToken"); - SequencerInbox seqInboxLogicFeeToken = new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, true); + SequencerInbox seqInboxLogicFeeToken = new SequencerInbox(MAX_DATA_SIZE, true); assertEq(seqInboxLogicFeeToken.maxDataSize(), MAX_DATA_SIZE, "Invalid MAX_DATA_SIZE"); assertEq(seqInboxLogicFeeToken.isUsingFeeToken(), true, "Invalid isUsingFeeToken"); @@ -258,7 +256,7 @@ contract SequencerInboxTest is Test { Bridge _bridge = Bridge(address(new TransparentUpgradeableProxy(address(new Bridge()), proxyAdmin, ""))); _bridge.initialize(IOwnable(address(new RollupMock(rollupOwner)))); - address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, false)); + address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, false)); SequencerInbox seqInboxProxy = SequencerInbox(TestUtil.deployProxy(seqInboxLogic)); seqInboxProxy.initialize( IBridge(_bridge), @@ -275,7 +273,7 @@ contract SequencerInboxTest is Test { address nativeToken = address(new ERC20PresetMinterPauser("Appchain Token", "App")); _bridge.initialize(IOwnable(address(new RollupMock(rollupOwner))), nativeToken); - address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, true)); + address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, true)); SequencerInbox seqInboxProxy = SequencerInbox(TestUtil.deployProxy(seqInboxLogic)); seqInboxProxy.initialize( IBridge(_bridge), @@ -291,7 +289,7 @@ contract SequencerInboxTest is Test { Bridge _bridge = Bridge(address(new TransparentUpgradeableProxy(address(new Bridge()), proxyAdmin, ""))); _bridge.initialize(IOwnable(address(new RollupMock(rollupOwner)))); - address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, true)); + address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, true)); SequencerInbox seqInboxProxy = SequencerInbox(TestUtil.deployProxy(seqInboxLogic)); vm.expectRevert(abi.encodeWithSelector(NativeTokenMismatch.selector)); @@ -306,7 +304,7 @@ contract SequencerInboxTest is Test { address nativeToken = address(new ERC20PresetMinterPauser("Appchain Token", "App")); _bridge.initialize(IOwnable(address(new RollupMock(rollupOwner))), nativeToken); - address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, dummyReader4844, false)); + address seqInboxLogic = address(new SequencerInbox(MAX_DATA_SIZE, false)); SequencerInbox seqInboxProxy = SequencerInbox(TestUtil.deployProxy(seqInboxLogic)); vm.expectRevert(abi.encodeWithSelector(NativeTokenMismatch.selector)); @@ -476,7 +474,6 @@ contract SequencerInboxTest is Test { (SequencerInbox seqInbox, ) = deployRollup(false); SequencerInbox seqInboxImpl = new SequencerInbox( maxDataSize, - dummyReader4844, false ); diff --git a/yul/Reader4844.yul b/yul/Reader4844.yul deleted file mode 100644 index ef183d79..00000000 --- a/yul/Reader4844.yul +++ /dev/null @@ -1,39 +0,0 @@ -object "Reader4844" { - code { - datacopy(0, dataoffset("runtime"), datasize("runtime")) - return(0, datasize("runtime")) - } - object "runtime" { - code { - // This contract does not accept callvalue - if callvalue() { revert(0, 0) } - - // Match against the keccak of the ABI function signature needed. - switch shr(0xe0, calldataload(0)) - // bytes4(keccak("getDataHashes()")) - case 0xe83a2d82 { - let i := 0 - for { } true { } - { - // DATAHASH opcode has hex value 0x49 - let hash := verbatim_1i_1o(hex"49", i) - if iszero(hash) { break } - mstore(add(mul(i, 32), 64), hash) - i := add(i, 1) - } - mstore(0, 32) - mstore(32, i) - return(0, add(mul(i, 32), 64)) - } - // bytes4(keccak("getBlobBaseFee()")) - case 0x1f6d6ef7 { - // BLOBBASEFEE opcode has hex value 0x4a - let blobBasefee := verbatim_0i_1o(hex"4a") - mstore(0, blobBasefee) - return(0, 32) - } - // Unknown selector (revert) - default { revert(0, 0) } - } - } -} From 96c7253c07683e74364d639bd4b5ae96de1f1c3e Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 15:25:54 +0000 Subject: [PATCH 02/11] Comment updates --- src/libraries/GasRefundEnabled.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index 60be806b..9871ac51 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -33,7 +33,7 @@ abstract contract GasRefundEnabled { // for similar reasons to above we only refund blob gas when the tx.origin is the msg.sender // this avoids the caller being able to send blobs to other contracts and still get refunded here - // since 4844 may not be enable yet, or may never be enabled on this chain we do not want to always call the + // since 4844 may not be enabled on this chain we do not want to always call the // blobhash or blobbasefee opcodes. We can only detect the presence of these opcodes without reverting // by either doing a call and checking success or providing a bool for specific code paths. We go for // the bool approach as it's cheaper From c443d0c5f0a76b939fbb44d26013edfcec775d2c Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 15:30:17 +0000 Subject: [PATCH 03/11] Formatting and comment out forge build for now --- .github/workflows/contract-tests.yml | 4 ++-- foundry.toml | 6 ------ package.json | 4 +--- src/bridge/SequencerInbox.sol | 6 +----- src/libraries/GasRefundEnabled.sol | 10 ++++++---- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/.github/workflows/contract-tests.yml b/.github/workflows/contract-tests.yml index 2835c5d2..22c3e520 100644 --- a/.github/workflows/contract-tests.yml +++ b/.github/workflows/contract-tests.yml @@ -127,8 +127,8 @@ jobs: - name: Install dependencies run: yarn install - - name: Build - run: yarn build:all + # - name: Build + # run: yarn build:all - name: Test 4844 run: yarn test:4844 diff --git a/foundry.toml b/foundry.toml index 774b6a24..82a96065 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,12 +9,6 @@ optimizer_runs = 20000 via_ir = false solc_version = '0.8.9' -[profile.yul] -src = 'yul' -out = 'out/yul' -libs = ['node_modules', 'lib'] -cache_path = 'forge-cache/yul' - [fmt] number_underscore = 'thousands' line_length = 100 diff --git a/package.json b/package.json index 6f649956..1dcb2f5e 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,7 @@ "prepublishOnly": "hardhat clean && hardhat compile", "build:all": "yarn build && yarn build:forge", "build": "hardhat compile", - "build:forge:sol": "forge build --skip *.yul", - "build:forge:yul": "FOUNDRY_PROFILE=yul forge build --skip *.sol", - "build:forge": "yarn build:forge:sol && yarn build:forge:yul", + "build:forge": "yarn build:forge:sol", "lint:test": "eslint ./test", "solhint": "solhint -f table src/**/*.sol", "prettier:solidity": "prettier --write src/**/*.sol", diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index be77c469..7ccb08a8 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -127,10 +127,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox // True if the chain this SequencerInbox is deployed on uses custom fee token bool public immutable isUsingFeeToken; - constructor( - uint256 _maxDataSize, - bool _isUsingFeeToken - ) { + constructor(uint256 _maxDataSize, bool _isUsingFeeToken) { maxDataSize = _maxDataSize; isUsingFeeToken = _isUsingFeeToken; } @@ -600,7 +597,6 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox return (keccak256(bytes.concat(header, data)), timeBounds); } - /// @dev Form a hash of the data being provided in 4844 data blobs /// @param afterDelayedMessagesRead The delayed messages count read up to /// @return The data hash diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index 9871ac51..5cfd27d8 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -32,18 +32,20 @@ abstract contract GasRefundEnabled { } else { // for similar reasons to above we only refund blob gas when the tx.origin is the msg.sender // this avoids the caller being able to send blobs to other contracts and still get refunded here - + // since 4844 may not be enabled on this chain we do not want to always call the // blobhash or blobbasefee opcodes. We can only detect the presence of these opcodes without reverting - // by either doing a call and checking success or providing a bool for specific code paths. We go for + // by either doing a call and checking success or providing a bool for specific code paths. We go for // the bool approach as it's cheaper - if(includeBlobCosts) { + if (includeBlobCosts) { // add any cost for 4844 data, the data hash reader throws an error prior to 4844 being activated // we do this addition here rather in the GasRefunder so that we can check the msg.sender is the tx.origin bytes32[] memory dataHashes = BlobDataHashReader.getDataHashes(); if (dataHashes.length != 0) { // CHRIS: TODO: should we check basefee == 0? we often have that for estimation - startGasLeft += (dataHashes.length * gasPerBlob * block.blobbasefee) / block.basefee; + startGasLeft += + (dataHashes.length * gasPerBlob * block.blobbasefee) / + block.basefee; } } } From a66ea256097d7286d4d3caa70174a670bf59996d Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 16:22:12 +0000 Subject: [PATCH 04/11] Formatting and linting --- .prettierrc.js | 27 +++++++++++++++++---------- src/bridge/SequencerInbox.sol | 3 ++- src/libraries/BlobDataHashReader.sol | 15 +++++++-------- src/libraries/GasRefundEnabled.sol | 1 - 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 5392936b..140bf28a 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,3 +1,11 @@ +let solOptions = { + tabWidth: 4, + printWidth: 100, + singleQuote: false, + bracketSpacing: false, + compiler: '0.8.9', +} + module.exports = { semi: false, trailingComma: 'es5', @@ -7,15 +15,14 @@ module.exports = { arrowParens: 'avoid', bracketSpacing: true, overrides: [ - { - files: '*.sol', - options: { - tabWidth: 4, - printWidth: 100, - singleQuote: false, - bracketSpacing: false, - compiler: '0.8.9', - }, - }, + { files: '*.sol', options: solOptions }, + { files: 'src/bridge/SequencerInbox.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/rollup/BridgeCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/rollup/RollupCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/mocks/SequencerInboxStub.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/libraries/GasRefundEnabled.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/libraries/BlobDataHashReader.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/rollup/ValidatorWallet.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { files: 'src/rollup/ValidatorWalletCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, ], } diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index 7ccb08a8..f232df48 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -2,7 +2,8 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.24; +// CHRIS: TODO: use ^ on all the new version like we used to +pragma solidity ^0.8.24; import { AlreadyInit, diff --git a/src/libraries/BlobDataHashReader.sol b/src/libraries/BlobDataHashReader.sol index 11f11bf2..25920c5a 100644 --- a/src/libraries/BlobDataHashReader.sol +++ b/src/libraries/BlobDataHashReader.sol @@ -2,25 +2,24 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -// solhint-disable-next-line compiler-version pragma solidity ^0.8.24; library BlobDataHashReader { /// @notice Gets all the data blob hashes on this transaction /// @dev Will revert if called on chains that do not support the 4844 blobhash opcode - function getDataHashes() internal view returns(bytes32[] memory) { + function getDataHashes() internal view returns (bytes32[] memory) { // we use assembly so that we can efficiently push into a memory arracy assembly { let i := 0 - for { } true { } - { + // prettier-ignore + for { } 1 { } { let h := blobhash(i) // the blob hash opcode returns 0 where no blob hash exists for that index - if iszero(h) { break } - + if iszero(h) { + break + } // store the blob hash mstore(add(mul(i, 32), 64), h) - // set the number of hashes i := add(i, 1) } @@ -30,4 +29,4 @@ library BlobDataHashReader { return(0, add(mul(i, 32), 64)) } } -} \ No newline at end of file +} diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index 5cfd27d8..ff788924 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -2,7 +2,6 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -// solhint-disable-next-line compiler-version pragma solidity ^0.8.24; import "./BlobDataHashReader.sol"; From ff544046845bdd41aba6bb591ac96be071b65050 Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 16:26:15 +0000 Subject: [PATCH 05/11] Check that block.basefee gt 0 --- src/libraries/GasRefundEnabled.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index ff788924..db8445f1 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -40,8 +40,7 @@ abstract contract GasRefundEnabled { // add any cost for 4844 data, the data hash reader throws an error prior to 4844 being activated // we do this addition here rather in the GasRefunder so that we can check the msg.sender is the tx.origin bytes32[] memory dataHashes = BlobDataHashReader.getDataHashes(); - if (dataHashes.length != 0) { - // CHRIS: TODO: should we check basefee == 0? we often have that for estimation + if (dataHashes.length != 0 && block.basefee > 0) { startGasLeft += (dataHashes.length * gasPerBlob * block.blobbasefee) / block.basefee; From 36ded16a5d52396f46f830642422a3c0efbf5e52 Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 16:31:00 +0000 Subject: [PATCH 06/11] Ts formatting --- .prettierrc.js | 50 ++++++++++++++----- deploy/SequencerInboxStubCreator.js | 8 +-- hardhat.config.ts | 2 +- test/contract/sequencerInbox.spec.4844.ts | 5 +- .../sequencerInboxForceInclude.spec.ts | 5 +- 5 files changed, 41 insertions(+), 29 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 140bf28a..917ddb37 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,9 +1,9 @@ let solOptions = { - tabWidth: 4, - printWidth: 100, - singleQuote: false, - bracketSpacing: false, - compiler: '0.8.9', + tabWidth: 4, + printWidth: 100, + singleQuote: false, + bracketSpacing: false, + compiler: '0.8.9', } module.exports = { @@ -16,13 +16,37 @@ module.exports = { bracketSpacing: true, overrides: [ { files: '*.sol', options: solOptions }, - { files: 'src/bridge/SequencerInbox.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/rollup/BridgeCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/rollup/RollupCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/mocks/SequencerInboxStub.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/libraries/GasRefundEnabled.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/libraries/BlobDataHashReader.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/rollup/ValidatorWallet.sol', options: { ...solOptions, compiler: '0.8.24' }}, - { files: 'src/rollup/ValidatorWalletCreator.sol', options: { ...solOptions, compiler: '0.8.24' }}, + { + files: 'src/bridge/SequencerInbox.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/rollup/BridgeCreator.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/rollup/RollupCreator.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/mocks/SequencerInboxStub.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/libraries/GasRefundEnabled.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/libraries/BlobDataHashReader.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/rollup/ValidatorWallet.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, + { + files: 'src/rollup/ValidatorWalletCreator.sol', + options: { ...solOptions, compiler: '0.8.24' }, + }, ], } diff --git a/deploy/SequencerInboxStubCreator.js b/deploy/SequencerInboxStubCreator.js index defc1bf3..014d8efb 100644 --- a/deploy/SequencerInboxStubCreator.js +++ b/deploy/SequencerInboxStubCreator.js @@ -14,13 +14,7 @@ module.exports = async hre => { } await deploy('SequencerInboxStub', { from: deployer, - args: [ - bridge.address, - deployer, - maxTime, - 117964, - false, - ], + args: [bridge.address, deployer, maxTime, 117964, false], }) } diff --git a/hardhat.config.ts b/hardhat.config.ts index bd81a4f5..6d458782 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -40,7 +40,7 @@ const solidity = { 'src/rollup/RollupCreator.sol': cancunSolSettings, 'src/mocks/SequencerInboxStub.sol': cancunSolSettings, 'src/libraries/GasRefundEnabled.sol': cancunSolSettings, - 'src/libraries/BlobDataHashReader.sol': cancunSolSettings, + 'src/libraries/BlobDataHashReader.sol': cancunSolSettings, 'src/rollup/ValidatorWallet.sol': cancunSolSettings, 'src/rollup/ValidatorWalletCreator.sol': cancunSolSettings, }, diff --git a/test/contract/sequencerInbox.spec.4844.ts b/test/contract/sequencerInbox.spec.4844.ts index 3f64c51f..88cac452 100644 --- a/test/contract/sequencerInbox.spec.4844.ts +++ b/test/contract/sequencerInbox.spec.4844.ts @@ -283,10 +283,7 @@ describe('SequencerInbox', async () => { ) const sequencerInboxFac = new SequencerInbox__factory(deployer) - const seqInboxTemplate = await sequencerInboxFac.deploy( - 117964, - false - ) + const seqInboxTemplate = await sequencerInboxFac.deploy(117964, false) const inboxFac = new Inbox__factory(deployer) const inboxTemplate = await inboxFac.deploy(117964) diff --git a/test/contract/sequencerInboxForceInclude.spec.ts b/test/contract/sequencerInboxForceInclude.spec.ts index e438ad2a..db729f61 100644 --- a/test/contract/sequencerInboxForceInclude.spec.ts +++ b/test/contract/sequencerInboxForceInclude.spec.ts @@ -235,10 +235,7 @@ describe('SequencerInboxForceInclude', async () => { const sequencerInboxFac = (await ethers.getContractFactory( 'SequencerInbox' )) as SequencerInbox__factory - const seqInboxTemplate = await sequencerInboxFac.deploy( - 117964, - false - ) + const seqInboxTemplate = await sequencerInboxFac.deploy(117964, false) const inboxFac = (await ethers.getContractFactory( 'Inbox' )) as Inbox__factory From fb54b92246cf3ccba98c70de6f06bd0a60924dec Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 16:31:57 +0000 Subject: [PATCH 07/11] Added todo --- .github/workflows/contract-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/contract-tests.yml b/.github/workflows/contract-tests.yml index 22c3e520..ed2335eb 100644 --- a/.github/workflows/contract-tests.yml +++ b/.github/workflows/contract-tests.yml @@ -127,6 +127,7 @@ jobs: - name: Install dependencies run: yarn install + # CHRIS: TODO: comment back in when foundry builds cancun # - name: Build # run: yarn build:all From fbe831cf2a9333d75fa10174449b670c343f100b Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 16:35:13 +0000 Subject: [PATCH 08/11] Reset sol versions --- src/bridge/SequencerInbox.sol | 1 - src/libraries/BlobDataHashReader.sol | 2 +- src/libraries/GasRefundEnabled.sol | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bridge/SequencerInbox.sol b/src/bridge/SequencerInbox.sol index f232df48..22f456d3 100644 --- a/src/bridge/SequencerInbox.sol +++ b/src/bridge/SequencerInbox.sol @@ -2,7 +2,6 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -// CHRIS: TODO: use ^ on all the new version like we used to pragma solidity ^0.8.24; import { diff --git a/src/libraries/BlobDataHashReader.sol b/src/libraries/BlobDataHashReader.sol index 25920c5a..cd0afcdf 100644 --- a/src/libraries/BlobDataHashReader.sol +++ b/src/libraries/BlobDataHashReader.sol @@ -2,7 +2,7 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.24; +pragma solidity ^0.8.0; library BlobDataHashReader { /// @notice Gets all the data blob hashes on this transaction diff --git a/src/libraries/GasRefundEnabled.sol b/src/libraries/GasRefundEnabled.sol index db8445f1..303e7d24 100644 --- a/src/libraries/GasRefundEnabled.sol +++ b/src/libraries/GasRefundEnabled.sol @@ -2,7 +2,7 @@ // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.24; +pragma solidity ^0.8.0; import "./BlobDataHashReader.sol"; import "./IGasRefunder.sol"; From ecf423837414afdc07662af1baf7c19fbc874cbf Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Fri, 26 Jan 2024 18:12:47 +0000 Subject: [PATCH 09/11] Updated the blobhash reader --- src/libraries/BlobDataHashReader.sol | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/libraries/BlobDataHashReader.sol b/src/libraries/BlobDataHashReader.sol index cd0afcdf..c908de35 100644 --- a/src/libraries/BlobDataHashReader.sol +++ b/src/libraries/BlobDataHashReader.sol @@ -8,8 +8,12 @@ library BlobDataHashReader { /// @notice Gets all the data blob hashes on this transaction /// @dev Will revert if called on chains that do not support the 4844 blobhash opcode function getDataHashes() internal view returns (bytes32[] memory) { - // we use assembly so that we can efficiently push into a memory arracy + bytes32[] memory dataHashes; + // we use assembly so that we can push into a memory array without resizing assembly { + // get the free mem pointer + let dataHashesPtr := mload(0x40) + // and keep track of the number of hashes let i := 0 // prettier-ignore for { } 1 { } { @@ -18,15 +22,20 @@ library BlobDataHashReader { if iszero(h) { break } - // store the blob hash - mstore(add(mul(i, 32), 64), h) - // set the number of hashes + // we will fill the first slot with the array size + // so we store the hashes after that + mstore(add(dataHashesPtr, add(mul(i, 32), 32)), h) i := add(i, 1) } - // format an return an array of the data blob hashes - mstore(0, 32) - mstore(32, i) - return(0, add(mul(i, 32), 64)) + // store the hash count + mstore(dataHashesPtr, i) + + // update the free mem pointer + let size := add(mul(i, 32), 32) + mstore(0x40, add(dataHashesPtr, size)) + + dataHashes := dataHashesPtr } + return dataHashes; } } From bf7e86d601b03788bd621353aeef072a85985cb8 Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Mon, 29 Jan 2024 16:48:51 +0000 Subject: [PATCH 10/11] Use 0.8.24 foundry for compilation and evm-version cancun --- foundry.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/foundry.toml b/foundry.toml index 82a96065..f20e5385 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,7 +7,8 @@ cache_path = 'forge-cache/sol' optimizer = true optimizer_runs = 20000 via_ir = false -solc_version = '0.8.9' +solc_version = '0.8.24' +evm_version = 'cancun' [fmt] number_underscore = 'thousands' From eb390acdf28ee970363cc06dcd93c85dbc70f4d1 Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Mon, 29 Jan 2024 17:00:48 +0000 Subject: [PATCH 11/11] Updated forge build --- .github/workflows/contract-tests.yml | 5 ++--- package.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/contract-tests.yml b/.github/workflows/contract-tests.yml index ed2335eb..2835c5d2 100644 --- a/.github/workflows/contract-tests.yml +++ b/.github/workflows/contract-tests.yml @@ -127,9 +127,8 @@ jobs: - name: Install dependencies run: yarn install - # CHRIS: TODO: comment back in when foundry builds cancun - # - name: Build - # run: yarn build:all + - name: Build + run: yarn build:all - name: Test 4844 run: yarn test:4844 diff --git a/package.json b/package.json index 1dcb2f5e..bc59a3e7 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "prepublishOnly": "hardhat clean && hardhat compile", "build:all": "yarn build && yarn build:forge", "build": "hardhat compile", - "build:forge": "yarn build:forge:sol", + "build:forge": "forge build", "lint:test": "eslint ./test", "solhint": "solhint -f table src/**/*.sol", "prettier:solidity": "prettier --write src/**/*.sol",