Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Use native blobhash and blobbasefee opcodes #123

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
let solOptions = {
tabWidth: 4,
printWidth: 100,
singleQuote: false,
bracketSpacing: false,
compiler: '0.8.9',
}

module.exports = {
semi: false,
trailingComma: 'es5',
Expand All @@ -7,15 +15,38 @@ module.exports = {
arrowParens: 'avoid',
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: '*.sol',
options: {
tabWidth: 4,
printWidth: 100,
singleQuote: false,
bracketSpacing: false,
compiler: '0.8.9',
},
files: 'src/rollup/ValidatorWalletCreator.sol',
options: { ...solOptions, compiler: '0.8.24' },
},
],
}
12 changes: 1 addition & 11 deletions deploy/SequencerInboxStubCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -17,14 +14,7 @@ module.exports = async hre => {
}
await deploy('SequencerInboxStub', {
from: deployer,
args: [
bridge.address,
deployer,
maxTime,
117964,
reader4844.address,
false,
],
args: [bridge.address, deployer, maxTime, 117964, false],
})
}

Expand Down
9 changes: 2 additions & 7 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,8 @@ cache_path = 'forge-cache/sol'
optimizer = true
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'
solc_version = '0.8.24'
evm_version = 'cancun'

[fmt]
number_underscore = 'thousands'
Expand Down
36 changes: 27 additions & 9 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand All @@ -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']) {
Expand All @@ -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,
},
},
}
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "forge build",
"lint:test": "eslint ./test",
"solhint": "solhint -f table src/**/*.sol",
"prettier:solidity": "prettier --write src/**/*.sol",
Expand Down
27 changes: 8 additions & 19 deletions src/bridge/SequencerInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand All @@ -128,18 +127,8 @@ 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,
IReader4844 reader4844_,
bool _isUsingFeeToken
) {
constructor(uint256 _maxDataSize, 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;
}

Expand Down Expand Up @@ -366,7 +355,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();
Expand Down Expand Up @@ -417,7 +406,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,
Expand Down Expand Up @@ -479,7 +468,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,
Expand Down Expand Up @@ -622,14 +611,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,
Expand Down
41 changes: 41 additions & 0 deletions src/libraries/BlobDataHashReader.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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

pragma solidity ^0.8.0;

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) {
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 { } {
let h := blobhash(i)
// the blob hash opcode returns 0 where no blob hash exists for that index
if iszero(h) {
break
}
// 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)
}
// 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;
}
}
26 changes: 14 additions & 12 deletions src/libraries/GasRefundEnabled.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
// 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.0;

import "./IReader4844.sol";
import "./BlobDataHashReader.sol";
import "./IGasRefunder.sol";

abstract contract GasRefundEnabled {
Expand All @@ -14,7 +13,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)) {
Expand All @@ -32,17 +31,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
if (address(reader4844) != address(0)) {

// 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
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 && block.basefee > 0) {
startGasLeft +=
(dataHashes.length * gasPerBlob * block.blobbasefee) /
block.basefee;
}
}
}

Expand Down
9 changes: 0 additions & 9 deletions src/libraries/IReader4844.sol

This file was deleted.

3 changes: 1 addition & 2 deletions src/mocks/SequencerInboxStub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading