diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index e0915880bdfe..20d3e22681a4 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -20,6 +20,8 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/state" "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/rollup" + + "github.com/ethereum-optimism/optimism/op-service/feature" ) var ( @@ -430,7 +432,7 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage if block.Number() == nil { return storage, errors.New("block number not set") } - if block.BaseFee() == nil { + if feature.CustomizeL1BaseFeeByTransactions(block.BaseFee(), block.Transactions()) == nil { return storage, errors.New("block base fee not set") } @@ -446,7 +448,7 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage storage["L1Block"] = state.StorageValues{ "number": block.Number(), "timestamp": block.Time(), - "basefee": block.BaseFee(), + "basefee": feature.CustomizeL1BaseFeeByTransactions(block.BaseFee(), block.Transactions()), "hash": block.Hash(), "sequenceNumber": 0, "batcherHash": config.BatchSenderAddress.Hash(), diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index 9383c642c901..52661208a35d 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -11,6 +11,8 @@ import ( "github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/rollup" + + "github.com/ethereum-optimism/optimism/op-service/feature" ) // L1ReceiptsFetcher fetches L1 header info and receipts for the payload attributes derivation (the info tx and deposits) @@ -100,6 +102,14 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex l2Parent, nextL2Time, eth.ToBlockID(l1Info), l1Info.Time())) } + if feature.EnableCustomizeL1BlockBaseFee { + _, receipts, err := ba.l1.FetchReceipts(ctx, epoch.Hash) + if err != nil { + return nil, NewTemporaryError(fmt.Errorf("failed to fetch L1 block receipts: %w", err)) + } + l1Info = feature.CustomizeL1BlockInfoByReceipts(l1Info, receipts) + } + l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info, sysConfig, ba.cfg.IsRegolith(nextL2Time)) if err != nil { return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err)) diff --git a/op-node/rollup/derive/l1_block_info.go b/op-node/rollup/derive/l1_block_info.go index 0e4733d71069..13ae763015d0 100644 --- a/op-node/rollup/derive/l1_block_info.go +++ b/op-node/rollup/derive/l1_block_info.go @@ -54,11 +54,13 @@ func (info *L1BlockInfo) MarshalBinary() ([]byte, error) { offset += 32 binary.BigEndian.PutUint64(data[offset+24:offset+32], info.Time) offset += 32 - // Ensure that the baseFee is not too large. - if info.BaseFee.BitLen() > 256 { - return nil, fmt.Errorf("base fee exceeds 256 bits: %d", info.BaseFee) + if info.BaseFee != nil { + // Ensure that the baseFee is not too large. + if info.BaseFee.BitLen() > 256 { + return nil, fmt.Errorf("base fee exceeds 256 bits: %d", info.BaseFee) + } + info.BaseFee.FillBytes(data[offset : offset+32]) } - info.BaseFee.FillBytes(data[offset : offset+32]) offset += 32 copy(data[offset:offset+32], info.BlockHash.Bytes()) offset += 32 diff --git a/op-node/rollup/driver/sequencer_test.go b/op-node/rollup/driver/sequencer_test.go index 8e7db4269ff2..7ad517b07451 100644 --- a/op-node/rollup/driver/sequencer_test.go +++ b/op-node/rollup/driver/sequencer_test.go @@ -302,7 +302,7 @@ func TestSequencerChaosMonkey(t *testing.T) { } }) - seq := NewSequencer(log, cfg, engControl, attrBuilder, originSelector, metrics.NoopMetrics) + seq := NewSequencer(log, cfg, engControl, nil, attrBuilder, originSelector, metrics.NoopMetrics) seq.timeNow = clockFn // try to build 1000 blocks, with 5x as many planning attempts, to handle errors and clock problems diff --git a/op-node/sources/l1_client.go b/op-node/sources/l1_client.go index d3d1d7438291..eec0a3ecfa28 100644 --- a/op-node/sources/l1_client.go +++ b/op-node/sources/l1_client.go @@ -14,6 +14,8 @@ import ( "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/sources/caching" + + "github.com/ethereum-optimism/optimism/op-service/feature" ) type L1ClientConfig struct { @@ -75,7 +77,7 @@ func NewL1Client(client client.RPC, log log.Logger, metrics caching.Metrics, con // L1BlockRefByLabel returns the [eth.L1BlockRef] for the given block label. // Notice, we cannot cache a block reference by label because labels are not guaranteed to be unique. func (s *L1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L1BlockRef, error) { - info, err := s.InfoByLabel(ctx, label) + info, err := feature.CustomizeL1Label(ctx, s.EthClient, label) if err != nil { // Both geth and erigon like to serve non-standard errors for the safe and finalized heads, correct that. // This happens when the chain just started and nothing is marked as safe/finalized yet. diff --git a/op-proposer/proposer/l2_output_submitter.go b/op-proposer/proposer/l2_output_submitter.go index bcf34e5a0969..d48d756d5cb9 100644 --- a/op-proposer/proposer/l2_output_submitter.go +++ b/op-proposer/proposer/l2_output_submitter.go @@ -26,6 +26,8 @@ import ( oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" "github.com/ethereum-optimism/optimism/op-service/txmgr" + + "github.com/ethereum-optimism/optimism/op-service/feature" ) var supportedL2OutputVersion = eth.Bytes32{} @@ -316,7 +318,7 @@ func proposeL2OutputTxData(abi *abi.ABI, output *eth.OutputResponse) ([]byte, er "proposeL2Output", output.OutputRoot, new(big.Int).SetUint64(output.BlockRef.Number), - output.Status.CurrentL1.Hash, + feature.CustomizeProposeL1BlockHash(output.Status.CurrentL1.Hash), new(big.Int).SetUint64(output.Status.CurrentL1.Number)) } diff --git a/op-service/txmgr/txmgr.go b/op-service/txmgr/txmgr.go index 37711506cbbf..8f8242f9288d 100644 --- a/op-service/txmgr/txmgr.go +++ b/op-service/txmgr/txmgr.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-service/feature" "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) @@ -179,13 +180,13 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (* rawTx.Gas = candidate.GasLimit } else { // Calculate the intrinsic gas for the transaction - gas, err := m.backend.EstimateGas(ctx, ethereum.CallMsg{ + gas, err := m.backend.EstimateGas(ctx, feature.CustomizeCraftL1CallMsg(ethereum.CallMsg{ From: m.cfg.From, To: candidate.To, GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, Data: rawTx.Data, - }) + })) if err != nil { return nil, fmt.Errorf("failed to estimate gas: %w", err) } @@ -194,7 +195,7 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (* ctx, cancel = context.WithTimeout(ctx, m.cfg.NetworkTimeout) defer cancel() - return m.cfg.Signer(ctx, m.cfg.From, types.NewTx(rawTx)) + return m.cfg.Signer(ctx, m.cfg.From, types.NewTx(feature.CustomizeCraftL1Transaction(rawTx))) } // send submits the same transaction several times with increasing gas prices as necessary. @@ -392,7 +393,7 @@ func (m *SimpleTxManager) increaseGasPrice(ctx context.Context, tx *types.Transa return tx } - rawTx := &types.DynamicFeeTx{ + rawTx := feature.CustomizeCraftL1Transaction(&types.DynamicFeeTx{ ChainID: tx.ChainId(), Nonce: tx.Nonce(), GasTipCap: gasTipCap, @@ -402,7 +403,7 @@ func (m *SimpleTxManager) increaseGasPrice(ctx context.Context, tx *types.Transa Value: tx.Value(), Data: tx.Data(), AccessList: tx.AccessList(), - } + }) ctx, cancel := context.WithTimeout(ctx, m.cfg.NetworkTimeout) defer cancel() newTx, err := m.cfg.Signer(ctx, m.cfg.From, types.NewTx(rawTx)) @@ -430,10 +431,10 @@ func (m *SimpleTxManager) suggestGasPriceCaps(ctx context.Context) (*big.Int, *b if err != nil { m.metr.RPCError() return nil, nil, fmt.Errorf("failed to fetch the suggested basefee: %w", err) - } else if head.BaseFee == nil { + } else if feature.CustomizeSuggestedL1BaseFee(head.BaseFee) == nil { return nil, nil, errors.New("txmgr does not support pre-london blocks that do not have a basefee") } - return tip, head.BaseFee, nil + return tip, feature.CustomizeSuggestedL1BaseFee(head.BaseFee), nil } // calcThresholdValue returns x * priceBumpPercent / 100 diff --git a/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol b/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol index 8a50079a662c..d5a5420a7bd2 100644 --- a/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol +++ b/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol @@ -152,7 +152,7 @@ abstract contract ResourceMetering is Initializable { // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei // during any 1 day period in the last 5 years, so should be fine. - uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei); + uint256 gasCost = resourceCost / 5 gwei; // Give the user a refund based on the amount of gas they used to do all of the work up to // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts