diff --git a/cannon/mipsevm/testutil/evm.go b/cannon/mipsevm/testutil/evm.go index 745f7c662b2df..b986711c2fc84 100644 --- a/cannon/mipsevm/testutil/evm.go +++ b/cannon/mipsevm/testutil/evm.go @@ -98,7 +98,10 @@ func NewEVMEnv(contracts *ContractMetadata) (*vm.EVM, *state.StateDB) { cancunActivation := *chainCfg.ShanghaiTime + 10 chainCfg.CancunTime = &cancunActivation offsetBlocks := uint64(1000) // blocks after cancun fork - bc := &testChain{startTime: *chainCfg.CancunTime + offsetBlocks*12} + bc := &testChain{ + config: chainCfg, + startTime: *chainCfg.CancunTime + offsetBlocks*12, + } header := bc.GetHeader(common.Hash{}, 17034870+offsetBlocks) db := rawdb.NewMemoryDatabase() statedb := state.NewDatabase(triedb.NewDatabase(db, nil), nil) @@ -129,6 +132,7 @@ func NewEVMEnv(contracts *ContractMetadata) (*vm.EVM, *state.StateDB) { } type testChain struct { + config *params.ChainConfig startTime uint64 } @@ -136,6 +140,10 @@ func (d *testChain) Engine() consensus.Engine { return ethash.NewFullFaker() } +func (d *testChain) Config() *params.ChainConfig { + return d.config +} + func (d *testChain) GetHeader(h common.Hash, n uint64) *types.Header { parentHash := common.Hash{0: 0xff} binary.BigEndian.PutUint64(parentHash[1:], n-1) diff --git a/go.mod b/go.mod index dd274fdf4e164..4d839b84604e0 100644 --- a/go.mod +++ b/go.mod @@ -256,7 +256,7 @@ require ( rsc.io/tmplfunc v0.0.3 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101500.1-rc.1 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101500.2-rc.1 //replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index c9d862d33094c..a6dd712478e2e 100644 --- a/go.sum +++ b/go.sum @@ -192,8 +192,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= -github.com/ethereum-optimism/op-geth v1.101500.1-rc.1 h1:nvfeMbZdXgrNI5EZtIUVZqql9Jms3F2Q5CWHz3Catr4= -github.com/ethereum-optimism/op-geth v1.101500.1-rc.1/go.mod h1:OMpyVMMy5zpAAHlR5s/aGbXRk+7cIKczUEIJj54APbY= +github.com/ethereum-optimism/op-geth v1.101500.2-rc.1 h1:CCQtyKKobjMbK9jYd676YbH6Xcvntdn6jIOxFTCb5B8= +github.com/ethereum-optimism/op-geth v1.101500.2-rc.1/go.mod h1:OMpyVMMy5zpAAHlR5s/aGbXRk+7cIKczUEIJj54APbY= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250205201532-8ff62ada16e1 h1:OqRYDcjiOx5QCLn5krpd3BK1CW+VfSZx7YIa6zY9ePE= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250205201532-8ff62ada16e1/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= diff --git a/op-batcher/batcher/channel_test.go b/op-batcher/batcher/channel_test.go index b36ce9311bcea..0e1365eceec9c 100644 --- a/op-batcher/batcher/channel_test.go +++ b/op-batcher/batcher/channel_test.go @@ -169,7 +169,7 @@ func TestChannel_NextTxData_singleFrameTx(t *testing.T) { func TestChannel_NextTxData_multiFrameTx(t *testing.T) { require := require.New(t) - const n = eth.MaxBlobsPerBlobTx + const n = 6 lgr := testlog.Logger(t, log.LevelWarn) ch, err := newChannelWithChannelOut(lgr, metrics.NoopMetrics, ChannelConfig{ UseBlobs: true, diff --git a/op-batcher/batcher/config.go b/op-batcher/batcher/config.go index 048e879eb0c15..c712b74bc8e5c 100644 --- a/op-batcher/batcher/config.go +++ b/op-batcher/batcher/config.go @@ -6,13 +6,13 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" altda "github.com/ethereum-optimism/optimism/op-alt-da" "github.com/ethereum-optimism/optimism/op-batcher/compressor" "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/eth" oplog "github.com/ethereum-optimism/optimism/op-service/log" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/oppprof" @@ -20,6 +20,10 @@ import ( "github.com/ethereum-optimism/optimism/op-service/txmgr" ) +// Current max blobs const, irrespective of active fork, is that of the Prague +// blob config. +var maxBlobsPerBlock = params.DefaultPragueBlobConfig.Max + type CLIConfig struct { // L1EthRpc is the HTTP provider URL for L1. L1EthRpc string @@ -155,9 +159,11 @@ func (c *CLIConfig) Check() error { if !flags.ValidDataAvailabilityType(c.DataAvailabilityType) { return fmt.Errorf("unknown data availability type: %q", c.DataAvailabilityType) } - // we want to enforce it for both blobs and auto - if c.DataAvailabilityType != flags.CalldataType && c.TargetNumFrames > eth.MaxBlobsPerBlobTx { - return fmt.Errorf("too many frames for blob transactions, max %d", eth.MaxBlobsPerBlobTx) + // Most chains' L1s still have only Cancun active, but we don't want to + // overcomplicate this check with a dynamic L1 query, so we just use maxBlobsPerBlock. + // We want to check for both, blobs and auto da-type. + if c.DataAvailabilityType != flags.CalldataType && c.TargetNumFrames > maxBlobsPerBlock { + return fmt.Errorf("too many frames for blob transactions, max %d", maxBlobsPerBlock) } if err := c.MetricsConfig.Check(); err != nil { return err diff --git a/op-batcher/batcher/config_test.go b/op-batcher/batcher/config_test.go index 19d4a5c9ec0ab..96f5fdaf4196e 100644 --- a/op-batcher/batcher/config_test.go +++ b/op-batcher/batcher/config_test.go @@ -9,12 +9,12 @@ import ( "github.com/ethereum-optimism/optimism/op-batcher/compressor" "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/log" "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/oppprof" "github.com/ethereum-optimism/optimism/op-service/rpc" "github.com/ethereum-optimism/optimism/op-service/txmgr" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) @@ -50,6 +50,9 @@ func TestValidBatcherConfig(t *testing.T) { require.NoError(t, cfg.Check(), "valid config should pass the check function") } +// Set current +var maxBlobsPerBlock = params.DefaultPragueBlobConfig.Max + func TestBatcherConfig(t *testing.T) { tests := []struct { name string @@ -102,12 +105,12 @@ func TestBatcherConfig(t *testing.T) { errString: "TargetNumFrames must be at least 1", }, { - name: fmt.Sprintf("larger %d TargetNumFrames for blobs", eth.MaxBlobsPerBlobTx), + name: fmt.Sprintf("larger %d TargetNumFrames for blobs", maxBlobsPerBlock), override: func(c *batcher.CLIConfig) { - c.TargetNumFrames = eth.MaxBlobsPerBlobTx + 1 + c.TargetNumFrames = maxBlobsPerBlock + 1 c.DataAvailabilityType = flags.BlobsType }, - errString: fmt.Sprintf("too many frames for blob transactions, max %d", eth.MaxBlobsPerBlobTx), + errString: fmt.Sprintf("too many frames for blob transactions, max %d", maxBlobsPerBlock), }, { name: "invalid compr ratio for ratio compressor", diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index de935cce74c7b..3bbeb5f170632 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -1,12 +1,10 @@ package batcher import ( - "bytes" "context" "errors" "fmt" "io" - "math" "math/big" _ "net/http/pprof" "sync" @@ -892,45 +890,17 @@ type TxSender[T any] interface { // sendTx uses the txmgr queue to send the given transaction candidate after setting its // gaslimit. It will block if the txmgr queue has reached its MaxPendingTransactions limit. func (l *BatchSubmitter) sendTx(txdata txData, isCancel bool, candidate *txmgr.TxCandidate, queue TxSender[txRef], receiptsCh chan txmgr.TxReceipt[txRef]) { - intrinsicGas, err := core.IntrinsicGas(candidate.TxData, nil, nil, false, true, true, false) + floorDataGas, err := core.FloorDataGas(candidate.TxData) if err != nil { - // we log instead of return an error here because txmgr can do its own gas estimation - l.Log.Error("Failed to calculate intrinsic gas", "err", err) + // We log instead of return an error here because the txmgr will do its own gas estimation. + l.Log.Warn("Failed to calculate floor data gas", "err", err) } else { - candidate.GasLimit = intrinsicGas - } - - floorDataGas, err := floorDataGas(candidate.TxData) - if err != nil { - l.Log.Warn("Failed to compute FloorDataGas: %v, continuing with intrinsic gas.") - } else if floorDataGas > candidate.GasLimit { - l.Log.Debug("Bumping gas limit to floor data gas", "intrinsic_gas", intrinsicGas, "floor_data_gas", floorDataGas) candidate.GasLimit = floorDataGas } queue.Send(txRef{id: txdata.ID(), isCancel: isCancel, isBlob: txdata.asBlob}, *candidate, receiptsCh) } -// Copypaste from upstream geth -// TODO remove in #14500 -func floorDataGas(data []byte) (uint64, error) { - TxTokenPerNonZeroByte := uint64(4) - TxGas := uint64(21000) - TxCostFloorPerToken := uint64(10) - - var ( - z = uint64(bytes.Count(data, []byte{0})) - nz = uint64(len(data)) - z - tokens = nz*TxTokenPerNonZeroByte + z - ) - // Check for overflow - if (math.MaxUint64-TxGas)/TxCostFloorPerToken < tokens { - return 0, core.ErrGasUintOverflow - } - // Minimum gas required for a transaction based on its data tokens (EIP-7623). - return TxGas + tokens*TxCostFloorPerToken, nil -} - func (l *BatchSubmitter) blobTxCandidate(data txData) (*txmgr.TxCandidate, error) { blobs, err := data.Blobs() if err != nil { diff --git a/op-batcher/batcher/test_batch_submitter.go b/op-batcher/batcher/test_batch_submitter.go index 93083aa0dc6d7..e3e17f1542eb3 100644 --- a/op-batcher/batcher/test_batch_submitter.go +++ b/op-batcher/batcher/test_batch_submitter.go @@ -33,7 +33,7 @@ func (l *TestBatchSubmitter) JamTxPool(ctx context.Context) error { } else if candidate, err = l.blobTxCandidate(emptyTxData); err != nil { return err } - if candidate.GasLimit, err = core.IntrinsicGas(candidate.TxData, nil, nil, false, true, true, false); err != nil { + if candidate.GasLimit, err = core.FloorDataGas(candidate.TxData); err != nil { return err } diff --git a/op-chain-ops/cmd/check-derivation/main.go b/op-chain-ops/cmd/check-derivation/main.go index 08d52cca6a2cf..71c0fec1b9a18 100644 --- a/op-chain-ops/cmd/check-derivation/main.go +++ b/op-chain-ops/cmd/check-derivation/main.go @@ -225,7 +225,7 @@ func getRandomSignedTransaction(ctx context.Context, ethClient *ethclient.Client var txData types.TxData switch txType { case types.LegacyTxType: - gasLimit, err := core.IntrinsicGas(data, nil, nil, false, true, true, false) + gasLimit, err := core.FloorDataGas(data) if err != nil { return nil, fmt.Errorf("failed to get intrinsicGas: %w", err) } @@ -242,7 +242,7 @@ func getRandomSignedTransaction(ctx context.Context, ethClient *ethclient.Client Address: randomAddress, StorageKeys: []common.Hash{common.HexToHash("0x1234")}, }} - gasLimit, err := core.IntrinsicGas(data, accessList, nil, false, true, true, false) + gasLimit, err := core.FloorDataGas(data) if err != nil { return nil, fmt.Errorf("failed to get intrinsicGas: %w", err) } @@ -257,7 +257,7 @@ func getRandomSignedTransaction(ctx context.Context, ethClient *ethclient.Client Data: data, } case types.DynamicFeeTxType: - gasLimit, err := core.IntrinsicGas(data, nil, nil, false, true, true, false) + gasLimit, err := core.FloorDataGas(data) if err != nil { return nil, fmt.Errorf("failed to get intrinsicGas: %w", err) } diff --git a/op-chain-ops/cmd/check-ecotone/main.go b/op-chain-ops/cmd/check-ecotone/main.go index 58a11e9ce1ad0..b49bb0de33160 100644 --- a/op-chain-ops/cmd/check-ecotone/main.go +++ b/op-chain-ops/cmd/check-ecotone/main.go @@ -17,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -512,7 +511,8 @@ func checkBlobTxDenial(ctx context.Context, env *actionEnv) error { if latestHeader.ExcessBlobGas == nil { return fmt.Errorf("the L1 block %s (time %d) is not ecotone yet", latestHeader.Hash(), latestHeader.Time) } - blobBaseFee := eip4844.CalcBlobFee(*latestHeader.ExcessBlobGas) + + blobBaseFee := eth.CalcBlobFeeDefault(latestHeader) blobFeeCap := new(uint256.Int).Mul(uint256.NewInt(2), uint256.MustFromBig(blobBaseFee)) if blobFeeCap.Lt(uint256.NewInt(params.GWei)) { // ensure we meet 1 gwei geth tx-pool minimum blobFeeCap = uint256.NewInt(params.GWei) diff --git a/op-chain-ops/cmd/op-simulate/main.go b/op-chain-ops/cmd/op-simulate/main.go index 9c67c9529f130..5c7d95feb2dc3 100644 --- a/op-chain-ops/cmd/op-simulate/main.go +++ b/op-chain-ops/cmd/op-simulate/main.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" gstate "github.com/ethereum/go-ethereum/core/state" @@ -190,7 +191,7 @@ func fetchChainConfig(ctx context.Context, cl *rpc.Client) (*params.ChainConfig, } // if not already recognized, then fetch the chain config manually var config params.ChainConfig - if err := cl.CallContext(ctx, &config, "eth_chainConfig"); err != nil { + if err := cl.CallContext(ctx, &config, "debug_chainConfig"); err != nil { return nil, fmt.Errorf("failed to retrieve chain config: %w", err) } return &config, nil @@ -234,6 +235,7 @@ func readDump(prestatePath string) (map[common.Address]DumpAccount, error) { type simChainContext struct { eng consensus.Engine head *types.Header + cfg *params.ChainConfig } func (d *simChainContext) Engine() consensus.Engine { @@ -247,6 +249,10 @@ func (d *simChainContext) GetHeader(h common.Hash, n uint64) *types.Header { panic(fmt.Errorf("header retrieval not supported, cannot fetch %s %d", h, n)) } +func (d *simChainContext) Config() *params.ChainConfig { + return d.cfg +} + func simulate(ctx context.Context, logger log.Logger, conf *params.ChainConfig, prestatePath string, tx *types.Transaction, header *types.Header, doProfile bool) error { memDB := rawdb.NewMemoryDatabase() @@ -262,7 +268,7 @@ func simulate(ctx context.Context, logger log.Logger, conf *params.ChainConfig, for addr, acc := range dump { state.CreateAccount(addr) state.SetBalance(addr, uint256.MustFromBig((*big.Int)(&acc.Balance)), tracing.BalanceChangeUnspecified) - state.SetNonce(addr, acc.Nonce) + state.SetNonce(addr, acc.Nonce, tracing.NonceChangeUnspecified) state.SetCode(addr, acc.Code) state.SetStorage(addr, acc.Storage) } @@ -284,7 +290,7 @@ func simulate(ctx context.Context, logger log.Logger, conf *params.ChainConfig, state.Prepare(rules, sender, header.Coinbase, tx.To(), precompiles, tx.AccessList()) state.SetTxContext(tx.Hash(), 0) - cCtx := &simChainContext{eng: beacon.NewFaker(), head: header} + cCtx := &simChainContext{eng: beacon.New(ethash.NewFaker()), head: header, cfg: conf} gp := core.GasPool(tx.Gas()) usedGas := uint64(0) vmConfig := vm.Config{} diff --git a/op-chain-ops/foundry/allocs_test.go b/op-chain-ops/foundry/allocs_test.go index 4bb9ed4d4b5c3..8fdeee6da0d7e 100644 --- a/op-chain-ops/foundry/allocs_test.go +++ b/op-chain-ops/foundry/allocs_test.go @@ -40,19 +40,19 @@ func TestForgeAllocs_FromState(t *testing.T) { alice := common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") st.CreateAccount(alice) st.SetBalance(alice, uint256.NewInt(123), tracing.BalanceChangeUnspecified) - st.SetNonce(alice, 42) + st.SetNonce(alice, 42, tracing.NonceChangeUnspecified) bob := common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8") st.CreateAccount(bob) st.CreateContract(bob) st.SetBalance(bob, uint256.NewInt(100), tracing.BalanceChangeUnspecified) - st.SetNonce(bob, 1) + st.SetNonce(bob, 1, tracing.NonceChangeUnspecified) st.SetState(bob, common.Hash{0: 0x42}, common.Hash{0: 7}) contract := common.HexToAddress("0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC") st.CreateAccount(contract) st.CreateContract(contract) - st.SetNonce(contract, 30) + st.SetNonce(contract, 30, tracing.NonceChangeUnspecified) st.SetBalance(contract, uint256.NewInt(0), tracing.BalanceChangeUnspecified) st.SetCode(contract, []byte{10, 11, 12, 13, 14}) diff --git a/op-chain-ops/genesis/genesis.go b/op-chain-ops/genesis/genesis.go index 5607dd182ab51..091adf15c58dc 100644 --- a/op-chain-ops/genesis/genesis.go +++ b/op-chain-ops/genesis/genesis.go @@ -149,6 +149,8 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) { // To enable post-Merge consensus at genesis MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), + // use default Ethereum prod blob schedules + BlobScheduleConfig: params.DefaultBlobSchedule, } gasLimit := config.L1GenesisBlockGasLimit diff --git a/op-chain-ops/script/cheatcodes_environment.go b/op-chain-ops/script/cheatcodes_environment.go index 55584c835db05..9d48e4fb5a00b 100644 --- a/op-chain-ops/script/cheatcodes_environment.go +++ b/op-chain-ops/script/cheatcodes_environment.go @@ -136,7 +136,7 @@ type Log struct { // SetNonce implements https://book.getfoundry.sh/cheatcodes/set-nonce func (c *CheatCodesPrecompile) SetNonce(account common.Address, nonce uint64) { - c.h.state.SetNonce(account, nonce) + c.h.state.SetNonce(account, nonce, tracing.NonceChangeUnspecified) } // GetNonce implements https://book.getfoundry.sh/cheatcodes/get-nonce @@ -149,9 +149,9 @@ func (c *CheatCodesPrecompile) ResetNonce(addr common.Address) { // Resets nonce to 0 if EOA, or 1 if contract. // In scripts often set code to empty first when using it, it then becomes 0. if c.h.state.GetCodeHash(addr) == types.EmptyCodeHash { - c.h.state.SetNonce(addr, 0) + c.h.state.SetNonce(addr, 0, tracing.NonceChangeUnspecified) } else { - c.h.state.SetNonce(addr, 1) + c.h.state.SetNonce(addr, 1, tracing.NonceChangeUnspecified) } } diff --git a/op-chain-ops/script/forking/forking_test.go b/op-chain-ops/script/forking/forking_test.go index e6e62c19fc19c..dd5f1f8518e86 100644 --- a/op-chain-ops/script/forking/forking_test.go +++ b/op-chain-ops/script/forking/forking_test.go @@ -90,7 +90,7 @@ func TestForking(t *testing.T) { bob := common.Address(bytes.Repeat([]byte{0xbb}, 20)) forkState.CreateAccount(alice) - forkState.SetNonce(alice, 3) + forkState.SetNonce(alice, 3, tracing.NonceChangeUnspecified) forkState.AddBalance(alice, uint256.NewInt(123), tracing.BalanceChangeUnspecified) // Check if writes worked require.Equal(t, uint64(123), forkState.GetBalance(alice).Uint64()) @@ -126,7 +126,7 @@ func TestForking(t *testing.T) { require.Equal(t, uint64(1000), forkState.GetNonce(bob)) // Apply a diff change on top of the fork - forkState.SetNonce(bob, 99999) + forkState.SetNonce(bob, 99999, tracing.NonceChangeUnspecified) // Now unselect the fork, going back to the default again. require.NoError(t, forkState.SelectFork(ForkID{})) @@ -140,7 +140,7 @@ func TestForking(t *testing.T) { require.Equal(t, uint64(0), forkState.GetNonce(bob)) // Make a change to the base-state, to see if it survives going back to the fork. - forkState.SetNonce(bob, 5) + forkState.SetNonce(bob, 5, tracing.NonceChangeUnspecified) // Re-select the fork, see if the changes come back, including the diff we made require.NoError(t, forkState.SelectFork(forkA)) @@ -149,7 +149,7 @@ func TestForking(t *testing.T) { // This change will continue to be visible across forks, // alice is going to be persistent. - forkState.SetNonce(alice, 777) + forkState.SetNonce(alice, 777, tracing.NonceChangeUnspecified) // Now make Alice persistent, see if we can get the original value forkState.MakePersistent(alice) @@ -173,8 +173,8 @@ func TestForking(t *testing.T) { require.Equal(t, uint64(222), forkState.GetNonce(bob), "bob is forked") // Mutate both, and undo the fork, to test if the persistent change is still there in non-fork mode - forkState.SetNonce(alice, 1001) // this mutates forkA, because alice was made persistent there - forkState.SetNonce(bob, 1002) + forkState.SetNonce(alice, 1001, tracing.NonceChangeUnspecified) // this mutates forkA, because alice was made persistent there + forkState.SetNonce(bob, 1002, tracing.NonceChangeUnspecified) require.NoError(t, forkState.SelectFork(ForkID{})) require.Equal(t, uint64(1001), forkState.GetNonce(alice), "alice is persistent") require.Equal(t, uint64(5), forkState.GetNonce(bob), "bob is not persistent") @@ -255,7 +255,7 @@ func TestForking(t *testing.T) { require.Equal(t, uint64(9000), forkState.GetNonce(bob)) // Put in some mutations, for the fork-diff testing - forkState.SetNonce(alice, 1234) + forkState.SetNonce(alice, 1234, tracing.NonceChangeUnspecified) forkState.SetBalance(alice, uint256.NewInt(100_000), tracing.BalanceChangeUnspecified) forkState.SetState(alice, common.Hash{4}, common.Hash{42}) forkState.SetState(alice, common.Hash{5}, common.Hash{100}) diff --git a/op-chain-ops/script/forking/state.go b/op-chain-ops/script/forking/state.go index de628712f5c3a..e200e8903ef6d 100644 --- a/op-chain-ops/script/forking/state.go +++ b/op-chain-ops/script/forking/state.go @@ -266,8 +266,8 @@ func (fst *ForkableState) GetNonce(address common.Address) uint64 { return fst.stateFor(address).GetNonce(address) } -func (fst *ForkableState) SetNonce(address common.Address, u uint64) { - fst.stateFor(address).SetNonce(address, u) +func (fst *ForkableState) SetNonce(address common.Address, u uint64, reason tracing.NonceChangeReason) { + fst.stateFor(address).SetNonce(address, u, reason) } func (fst *ForkableState) GetCodeHash(address common.Address) common.Hash { @@ -386,6 +386,10 @@ func (fst *ForkableState) Witness() *stateless.Witness { return fst.selected.Witness() } +func (fst *ForkableState) AccessEvents() *state.AccessEvents { + return fst.selected.AccessEvents() +} + func (fst *ForkableState) SetBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) { fst.stateFor(addr).SetBalance(addr, amount, reason) } diff --git a/op-chain-ops/script/script.go b/op-chain-ops/script/script.go index d95ab96bc6347..65523ccbd27f2 100644 --- a/op-chain-ops/script/script.go +++ b/op-chain-ops/script/script.go @@ -214,6 +214,8 @@ func NewHost( CancunTime: new(uint64), PragueTime: nil, VerkleTime: nil, + // Select default Ethereum prod blob schedules + BlobScheduleConfig: params.DefaultBlobSchedule, // OP-Stack forks are disabled, since we use this for L1. BedrockBlock: nil, RegolithTime: nil, @@ -402,13 +404,13 @@ func (h *Host) Wipe(addr common.Address) { if h.state.GetCodeSize(addr) > 0 { h.state.SetCode(addr, nil) } - h.state.SetNonce(addr, 0) + h.state.SetNonce(addr, 0, tracing.NonceChangeUnspecified) h.state.SetBalance(addr, uint256.NewInt(0), tracing.BalanceChangeUnspecified) } // SetNonce sets an account's nonce in state. func (h *Host) SetNonce(addr common.Address, nonce uint64) { - h.state.SetNonce(addr, nonce) + h.state.SetNonce(addr, nonce, tracing.NonceChangeUnspecified) } // GetNonce returs an account's nonce from state. @@ -433,7 +435,7 @@ func (h *Host) ImportAccount(addr common.Address, account types.Account) { balance = uint256.MustFromBig(account.Balance) } h.state.SetBalance(addr, balance, tracing.BalanceChangeUnspecified) - h.state.SetNonce(addr, account.Nonce) + h.state.SetNonce(addr, account.Nonce, tracing.NonceChangeUnspecified) h.state.SetCode(addr, account.Code) for key, value := range account.Storage { h.state.SetState(addr, key, value) @@ -505,7 +507,7 @@ func (h *Host) onEnter(depth int, typ byte, from common.Address, to common.Addre if parentCallFrame.Prank.Sender != nil { sender = *parentCallFrame.Prank.Sender } - h.state.SetNonce(sender, h.state.GetNonce(sender)+1) + h.state.SetNonce(sender, h.state.GetNonce(sender)+1, tracing.NonceChangeUnspecified) } if h.isolateBroadcasts { @@ -829,7 +831,7 @@ func (h *Host) NewScriptAddress() common.Address { deployNonce := h.state.GetNonce(deployer) // compute address of script contract to be deployed addr := crypto.CreateAddress(deployer, deployNonce) - h.state.SetNonce(deployer, deployNonce+1) + h.state.SetNonce(deployer, deployNonce+1, tracing.NonceChangeUnspecified) return addr } diff --git a/op-deployer/pkg/deployer/broadcaster/keyed.go b/op-deployer/pkg/deployer/broadcaster/keyed.go index 2031ebe296e7a..fe3a4b18d7fb8 100644 --- a/op-deployer/pkg/deployer/broadcaster/keyed.go +++ b/op-deployer/pkg/deployer/broadcaster/keyed.go @@ -78,7 +78,6 @@ func NewKeyedBroadcaster(cfg KeyedBroadcasterOpts) (*KeyedBroadcaster, error) { &metrics.NoopTxMetrics{}, mgrCfg, ) - if err != nil { return nil, fmt.Errorf("failed to create tx manager: %w", err) } @@ -236,7 +235,18 @@ func padGasLimit(data []byte, gasUsed uint64, creation bool, blockGasLimit uint6 panic(err) } - limit := uint64(float64(intrinsicGas+gasUsed) * GasPadFactor) + floorDataGas, err := core.FloorDataGas(data) + // We should never cause an overflow here. + if err != nil { + panic(err) + } + + gas := intrinsicGas + gasUsed + if floorDataGas > gas { + gas = floorDataGas + } + + limit := uint64(float64(gas) * GasPadFactor) if limit > blockGasLimit { return blockGasLimit } diff --git a/op-e2e/actions/batcher/eip4844_test.go b/op-e2e/actions/batcher/eip4844_test.go index 06f2a86f60c42..04f52eeff9c69 100644 --- a/op-e2e/actions/batcher/eip4844_test.go +++ b/op-e2e/actions/batcher/eip4844_test.go @@ -10,11 +10,11 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" ) @@ -85,9 +85,14 @@ func TestEIP4844DataAvailability(gt *testing.T) { func TestEIP4844MultiBlobs(gt *testing.T) { t := helpers.NewDefaultTesting(gt) + // Feel free to bump to Prague when updating this test's L1 config to activate Prague log := testlog.Logger(t, log.LevelDebug) sd, dp, miner, sequencer, seqEngine, verifier, _ := setupEIP4844Test(t, log) + // We could use eip4844.MaxBlobsPerBlock(sd.L1Cfg.Config, sd.L1Cfg.Timestamp) here, but + // we don't have the L1 chain config available in the action test batcher. So we just + // stick to Cancun max blobs for now, which is sufficient for this test. + maxBlobsPerBlock := params.DefaultCancunBlobConfig.Max batcher := setupBatcher(t, log, sd, dp, miner, sequencer, seqEngine, batcherFlags.BlobsType) @@ -105,10 +110,10 @@ func TestEIP4844MultiBlobs(gt *testing.T) { sequencer.ActBuildToL1Head(t) // submit all new L2 blocks - batcher.ActSubmitAllMultiBlobs(t, eth.MaxBlobsPerBlobTx) + batcher.ActSubmitAllMultiBlobs(t, maxBlobsPerBlock) batchTx := batcher.LastSubmitted require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx") - require.Len(t, batchTx.BlobTxSidecar().Blobs, eth.MaxBlobsPerBlobTx) + require.Len(t, batchTx.BlobTxSidecar().Blobs, maxBlobsPerBlock) // new L1 block with L2 batch miner.ActL1StartBlock(12)(t) diff --git a/op-e2e/actions/derivation/reorg_test.go b/op-e2e/actions/derivation/reorg_test.go index 4ccbec6839af7..2f26a8862403a 100644 --- a/op-e2e/actions/derivation/reorg_test.go +++ b/op-e2e/actions/derivation/reorg_test.go @@ -105,7 +105,7 @@ func ReorgOrphanBlock(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { miner.ActL1SetFeeRecipient(common.Address{'C'}) // note: the geth tx pool reorgLoop is too slow (responds to chain head events, but async), // and there's no way to manually trigger runReorg, so we re-insert it ourselves. - require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTx}, true, true)[0]) + require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTx}, true)[0]) // need to re-insert previously included tx into the block miner.ActL1IncludeTx(sd.RollupCfg.Genesis.SystemConfig.BatcherAddr)(t) miner.ActL1EndBlock(t) @@ -177,7 +177,7 @@ func ReorgFlipFlop(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // re-include the batch tx that submitted L2 chain data that pointed to A0, in the new block B1 miner.ActL1SetFeeRecipient(common.Address{'B', 1}) miner.ActL1StartBlock(12)(t) - require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTxA}, true, true)[0]) + require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTxA}, true)[0]) miner.ActL1IncludeTx(sd.RollupCfg.Genesis.SystemConfig.BatcherAddr)(t) miner.ActL1EndBlock(t) @@ -242,7 +242,7 @@ func ReorgFlipFlop(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { miner.ActL1SetFeeRecipient(common.Address{'A', 2}) miner.ActL1StartBlock(12)(t) - require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTxA}, true, true)[0]) // replay chain A batches, but now in A2 instead of A1 + require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTxA}, true)[0]) // replay chain A batches, but now in A2 instead of A1 miner.ActL1IncludeTx(sd.RollupCfg.Genesis.SystemConfig.BatcherAddr)(t) miner.ActL1EndBlock(t) diff --git a/op-e2e/actions/helpers/l1_miner.go b/op-e2e/actions/helpers/l1_miner.go index 316ffc6e57d99..b33a68c12c439 100644 --- a/op-e2e/actions/helpers/l1_miner.go +++ b/op-e2e/actions/helpers/l1_miner.go @@ -224,15 +224,7 @@ func (s *L1Miner) ActL1EndBlock(t Testing) *types.Block { isCancun := s.l1Cfg.Config.IsCancun(s.l1BuildingHeader.Number, s.l1BuildingHeader.Time) if isCancun { parent := s.l1Chain.GetHeaderByHash(s.l1BuildingHeader.ParentHash) - var ( - parentExcessBlobGas uint64 - parentBlobGasUsed uint64 - ) - if parent.ExcessBlobGas != nil { - parentExcessBlobGas = *parent.ExcessBlobGas - parentBlobGasUsed = *parent.BlobGasUsed - } - excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + excessBlobGas := eip4844.CalcExcessBlobGas(s.l1Cfg.Config, parent, s.l1BuildingHeader.Time) s.l1BuildingHeader.ExcessBlobGas = &excessBlobGas } diff --git a/op-e2e/actions/helpers/l2_batcher.go b/op-e2e/actions/helpers/l2_batcher.go index f270bddb717a0..3e67166d92f6e 100644 --- a/op-e2e/actions/helpers/l2_batcher.go +++ b/op-e2e/actions/helpers/l2_batcher.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -343,8 +342,8 @@ func (s *L2Batcher) ActL2BatchSubmitRaw(t Testing, payload []byte, txOpts ...fun opt(rawTx) } - gas, err := core.IntrinsicGas(rawTx.Data, nil, nil, false, true, true, false) - require.NoError(t, err, "need to compute intrinsic gas") + gas, err := core.FloorDataGas(rawTx.Data) + require.NoError(t, err, "need to compute floor data gas") rawTx.Gas = gas txData = rawTx } else if s.l2BatcherCfg.DataAvailabilityType == batcherFlags.BlobsType { @@ -353,7 +352,7 @@ func (s *L2Batcher) ActL2BatchSubmitRaw(t Testing, payload []byte, txOpts ...fun sidecar, blobHashes, err := txmgr.MakeSidecar([]*eth.Blob{&b}) require.NoError(t, err) require.NotNil(t, pendingHeader.ExcessBlobGas, "need L1 header with 4844 properties") - blobBaseFee := eip4844.CalcBlobFee(*pendingHeader.ExcessBlobGas) + blobBaseFee := eth.CalcBlobFeeDefault(pendingHeader) blobFeeCap := new(uint256.Int).Mul(uint256.NewInt(2), uint256.MustFromBig(blobBaseFee)) if blobFeeCap.Lt(uint256.NewInt(params.GWei)) { // ensure we meet 1 gwei geth tx-pool minimum blobFeeCap = uint256.NewInt(params.GWei) @@ -384,11 +383,13 @@ func (s *L2Batcher) ActL2BatchSubmitRaw(t Testing, payload []byte, txOpts ...fun } func (s *L2Batcher) ActL2BatchSubmitMultiBlob(t Testing, numBlobs int) { + // Update to Prague if L1 changes to Prague and we need more blobs in multi-blob tests. + maxBlobsPerBlock := params.DefaultCancunBlobConfig.Max if s.l2BatcherCfg.DataAvailabilityType != batcherFlags.BlobsType { t.InvalidAction("ActL2BatchSubmitMultiBlob only available for Blobs DA type") return - } else if numBlobs > eth.MaxBlobsPerBlobTx || numBlobs < 1 { - t.InvalidAction("invalid number of blobs %d, must be within [1,%d]", numBlobs, eth.MaxBlobsPerBlobTx) + } else if numBlobs > maxBlobsPerBlock || numBlobs < 1 { + t.InvalidAction("invalid number of blobs %d, must be within [1,%d]", numBlobs, maxBlobsPerBlock) } // Don't run this action if there's no data to submit @@ -435,7 +436,7 @@ func (s *L2Batcher) ActL2BatchSubmitMultiBlob(t Testing, numBlobs int) { sidecar, blobHashes, err := txmgr.MakeSidecar(blobs) require.NoError(t, err) require.NotNil(t, pendingHeader.ExcessBlobGas, "need L1 header with 4844 properties") - blobBaseFee := eip4844.CalcBlobFee(*pendingHeader.ExcessBlobGas) + blobBaseFee := eth.CalcBlobFeeDefault(pendingHeader) blobFeeCap := new(uint256.Int).Mul(uint256.NewInt(2), uint256.MustFromBig(blobBaseFee)) if blobFeeCap.Lt(uint256.NewInt(params.GWei)) { // ensure we meet 1 gwei geth tx-pool minimum blobFeeCap = uint256.NewInt(params.GWei) diff --git a/op-e2e/actions/safedb/safedb_test.go b/op-e2e/actions/safedb/safedb_test.go index f4a2a1767a1a4..8e2e7b783853e 100644 --- a/op-e2e/actions/safedb/safedb_test.go +++ b/op-e2e/actions/safedb/safedb_test.go @@ -88,7 +88,7 @@ func TestRecordSafeHeadUpdates(gt *testing.T) { miner.ActL1SetFeeRecipient(common.Address{'C'}) // note: the geth tx pool reorgLoop is too slow (responds to chain head events, but async), // and there's no way to manually trigger runReorg, so we re-insert it ourselves. - require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTx}, true, true)[0]) + require.NoError(t, miner.Eth.TxPool().Add([]*types.Transaction{batchTx}, true)[0]) // need to re-insert previously included tx into the block miner.ActL1IncludeTx(sd.RollupCfg.Genesis.SystemConfig.BatcherAddr)(t) miner.ActL1EndBlock(t) diff --git a/op-e2e/actions/sync/sync_test.go b/op-e2e/actions/sync/sync_test.go index 54cb72a011464..8531e2ef52722 100644 --- a/op-e2e/actions/sync/sync_test.go +++ b/op-e2e/actions/sync/sync_test.go @@ -956,7 +956,7 @@ func TestInvalidPayloadInSpanBatch(gt *testing.T) { aliceNonce, err := seqEng.EthClient().PendingNonceAt(t.Ctx(), dp.Addresses.Alice) require.NoError(t, err) data := make([]byte, rand.Intn(100)) - gas, err := core.IntrinsicGas(data, nil, nil, false, true, true, false) + gas, err := core.FloorDataGas(data) require.NoError(t, err) baseFee := seqEng.L2Chain().CurrentBlock().BaseFee tx := types.MustSignNewTx(dp.Secrets.Alice, signer, &types.DynamicFeeTx{ diff --git a/op-e2e/actions/upgrades/dencun_fork_test.go b/op-e2e/actions/upgrades/dencun_fork_test.go index d634a836be079..0541a11904d86 100644 --- a/op-e2e/actions/upgrades/dencun_fork_test.go +++ b/op-e2e/actions/upgrades/dencun_fork_test.go @@ -216,7 +216,7 @@ func TestDencunBlobTxInTxPool(gt *testing.T) { log := testlog.Logger(t, log.LevelDebug) engine := newEngine(t, sd, log) tx := aliceSimpleBlobTx(t, dp) - errs := engine.Eth.TxPool().Add([]*types.Transaction{tx}, true, true) + errs := engine.Eth.TxPool().Add([]*types.Transaction{tx}, true) require.ErrorContains(t, errs[0], "transaction type not supported") } diff --git a/op-e2e/actions/upgrades/isthmus_fork_test.go b/op-e2e/actions/upgrades/isthmus_fork_test.go index cd7de34f9bf7a..ce774be1a1b43 100644 --- a/op-e2e/actions/upgrades/isthmus_fork_test.go +++ b/op-e2e/actions/upgrades/isthmus_fork_test.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/predeploys" @@ -323,10 +322,10 @@ func TestIsthmusNetworkUpgradeTransactions(gt *testing.T) { zero := hexutil.Uint64(0) - // Activate all forks at genesis, and schedule Ecotone the block after + // Activate all forks at genesis, and schedule Isthmus the block after dp.DeployConfig.L2GenesisHoloceneTimeOffset = &zero dp.DeployConfig.L2GenesisIsthmusTimeOffset = &isthmusOffset - dp.DeployConfig.L1PragueTimeOffset = nil + dp.DeployConfig.L1PragueTimeOffset = &zero // New forks have to be added here... require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") @@ -364,7 +363,7 @@ func TestIsthmusNetworkUpgradeTransactions(gt *testing.T) { require.NotEmpty(t, txn.Data(), "upgrade tx must provide input data") // EIP-2935 contract is deployed - expectedBlockHashAddress := crypto.CreateAddress(derive.BlockHashDeployerAddress, 0) + expectedBlockHashAddress := crypto.CreateAddress(predeploys.EIP2935ContractDeployer, 0) require.Equal(t, predeploys.EIP2935ContractAddr, expectedBlockHashAddress) code := verifyCodeHashMatches(t, ethCl, predeploys.EIP2935ContractAddr, predeploys.EIP2935ContractCodeHash) require.Equal(t, predeploys.EIP2935ContractCode, code) diff --git a/op-e2e/system/da/eip4844_test.go b/op-e2e/system/da/eip4844_test.go index 7c5b0c89d066d..c90097b7f9cca 100644 --- a/op-e2e/system/da/eip4844_test.go +++ b/op-e2e/system/da/eip4844_test.go @@ -35,6 +35,9 @@ import ( "github.com/ethereum/go-ethereum/params" ) +// Update to Prague if L1 changes to Prague and we need more blobs in multi-blob tests. +var maxBlobsPerBlock = params.DefaultCancunBlobConfig.Max + // TestSystem4844E2E* run the SystemE2E test with 4844 enabled on L1, and active on the rollup in // the op-batcher and verifier. It submits a txpool-blocking transaction before running // each test to ensure the batcher is able to clear it. @@ -60,9 +63,9 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva var maxL1TxSize int if multiBlob { - cfg.BatcherTargetNumFrames = eth.MaxBlobsPerBlobTx + cfg.BatcherTargetNumFrames = maxBlobsPerBlock cfg.BatcherUseMaxTxSizeForBlobs = true - // leads to eth.MaxBlobsPerBlobTx blobs for an L2 block with a user tx with 400 random bytes + // leads to maxBlobsPerBlock blobs for an L2 block with a user tx with 400 random bytes // while all other L2 blocks take 1 blob (deposit tx) maxL1TxSize = derive.FrameV0OverHeadSize + 100 cfg.BatcherMaxL1TxSizeBytes = uint64(maxL1TxSize) @@ -137,7 +140,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva opts.Value = big.NewInt(1_000_000_000) opts.Nonce = 1 // Already have deposit opts.ToAddr = &common.Address{0xff, 0xff} - // put some random data in the tx to make it fill up eth.MaxBlobsPerBlobTx blobs (multi-blob case) + // put some random data in the tx to make it fill up maxBlobsPerBlock blobs (multi-blob case) opts.Data = testutils.RandomData(rand.New(rand.NewSource(420)), 400) opts.Gas, err = core.IntrinsicGas(opts.Data, nil, nil, false, true, true, false) require.NoError(t, err) @@ -215,21 +218,20 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva if !multiBlob { require.NotZero(t, numBlobs, "single-blob: expected to find L1 blob tx") } else { - const maxBlobs = eth.MaxBlobsPerBlobTx - require.Equal(t, maxBlobs, numBlobs, fmt.Sprintf("multi-blob: expected to find L1 blob tx with %d blobs", maxBlobs)) + require.Equal(t, maxBlobsPerBlock, numBlobs, fmt.Sprintf("multi-blob: expected to find L1 blob tx with %d blobs", maxBlobsPerBlock)) // blob tx should have filled up all but last blob bcl := sys.L1BeaconHTTPClient() hashes := toIndexedBlobHashes(blobTx.BlobHashes()...) sidecars, err := bcl.BeaconBlobSideCars(context.Background(), false, sys.L1Slot(blobBlock.Time()), hashes) require.NoError(t, err) - require.Len(t, sidecars.Data, maxBlobs) - for i := 0; i < maxBlobs-1; i++ { + require.Len(t, sidecars.Data, maxBlobsPerBlock) + for i := 0; i < maxBlobsPerBlock-1; i++ { data, err := sidecars.Data[i].Blob.ToData() require.NoError(t, err) require.Len(t, data, maxL1TxSize) } // last blob should only be partially filled - data, err := sidecars.Data[maxBlobs-1].Blob.ToData() + data, err := sidecars.Data[maxBlobsPerBlock-1].Blob.ToData() require.NoError(t, err) require.Less(t, len(data), maxL1TxSize) } @@ -261,12 +263,14 @@ func TestBatcherAutoDA(t *testing.T) { cfg.DataAvailabilityType = batcherFlags.AutoType // We set the genesis fee values and block gas limit such that calldata txs are initially cheaper, // but then manipulate the fee markets over the coming L1 blocks such that blobs become cheaper again. - cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(3100)) - // 100 blob targets leads to 130_393 starting blob base fee, which is ~ 42 * 2_000 (equilibrium is ~16x or ~40x under Pectra) - cfg.DeployConfig.L1GenesisBlockExcessBlobGas = (*hexutil.Uint64)(u64Ptr(100 * params.BlobTxTargetBlobGasPerBlock)) + cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(3000)) + // The following excess blob gas leads to a blob base fee ~41 times higher than the base fee at genesis, + // so the batcher starts with calldata (equilibrium is ~16x or ~40x under Pectra). + cfg.DeployConfig.L1GenesisBlockExcessBlobGas = (*hexutil.Uint64)(u64Ptr( + 450 * params.BlobTxBlobGasPerBlob)) cfg.DeployConfig.L1GenesisBlockBlobGasUsed = (*hexutil.Uint64)(u64Ptr(0)) cfg.DeployConfig.L1GenesisBlockGasLimit = 2_500_000 - cfg.BatcherTargetNumFrames = eth.MaxBlobsPerBlobTx + cfg.BatcherTargetNumFrames = maxBlobsPerBlock sys, err := cfg.Start(t) require.NoError(t, err, "Error starting up system") log := testlog.Logger(t, log.LevelInfo) diff --git a/op-e2e/system/fees/l1info_test.go b/op-e2e/system/fees/l1info_test.go index a4fc16d94a595..7ae066d993d5c 100644 --- a/op-e2e/system/fees/l1info_test.go +++ b/op-e2e/system/fees/l1info_test.go @@ -16,7 +16,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/require" @@ -172,7 +171,7 @@ func TestL1InfoContract(t *testing.T) { l1blocks[h].BlobBaseFeeScalar = scalars.BlobBaseFeeScalar l1blocks[h].BaseFeeScalar = scalars.BaseFeeScalar if excess := b.ExcessBlobGas(); excess != nil { - l1blocks[h].BlobBaseFee = eip4844.CalcBlobFee(*excess) + l1blocks[h].BlobBaseFee = eth.CalcBlobFeeDefault(b.Header()) } else { l1blocks[h].BlobBaseFee = big.NewInt(1) } diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions.go b/op-node/rollup/derive/isthmus_upgrade_transactions.go index fd8663e46f3cd..595bf50fd9427 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions.go @@ -3,23 +3,21 @@ package derive import ( "math/big" + "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" ) var ( - BlockHashDeployerAddress = common.HexToAddress("0xE9f0662359Bb2c8111840eFFD73B9AFA77CbDE10") blockHashDeployerSource = UpgradeDepositSource{Intent: "Isthmus: EIP-2935 Contract Deployment"} blockHashDeploymentBytecode = common.FromHex("0x60538060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500") ) func IsthmusNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { - upgradeTxns := make([]hexutil.Bytes, 0, 1) - deployHistoricalBlockHashesContract, err := types.NewTx(&types.DepositTx{ SourceHash: blockHashDeployerSource.SourceHash(), - From: BlockHashDeployerAddress, + From: predeploys.EIP2935ContractDeployer, To: nil, Mint: big.NewInt(0), Value: big.NewInt(0), @@ -32,7 +30,5 @@ func IsthmusNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { return nil, err } - upgradeTxns = append(upgradeTxns, deployHistoricalBlockHashesContract) - - return upgradeTxns, nil + return []hexutil.Bytes{deployHistoricalBlockHashesContract}, nil } diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go index 8a2181702f87c..5527e76e20e89 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go @@ -3,6 +3,7 @@ package derive import ( "testing" + "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" @@ -28,7 +29,7 @@ func TestIsthmusNetworkTransactions(t *testing.T) { require.Len(t, upgradeTxns, 1) deployBlockHashesSender, deployBlockHashesContract := toDepositTxn(t, upgradeTxns[0]) - require.Equal(t, deployBlockHashesSender, common.HexToAddress("0xE9f0662359Bb2c8111840eFFD73B9AFA77CbDE10")) + require.Equal(t, deployBlockHashesSender, predeploys.EIP2935ContractDeployer) require.Equal(t, blockHashDeployerSource.SourceHash(), deployBlockHashesContract.SourceHash()) require.Nil(t, deployBlockHashesContract.To()) require.Equal(t, uint64(250_000), deployBlockHashesContract.Gas()) diff --git a/op-program/client/l2/db_test.go b/op-program/client/l2/db_test.go index 5b92a516504f0..6395fd525cf87 100644 --- a/op-program/client/l2/db_test.go +++ b/op-program/client/l2/db_test.go @@ -135,7 +135,7 @@ func TestUpdateState(t *testing.T) { statedb.MakeSinglethreaded() statedb.SetBalance(userAccount, uint256.NewInt(50), tracing.BalanceChangeUnspecified) require.Equal(t, uint256.NewInt(50), statedb.GetBalance(userAccount)) - statedb.SetNonce(userAccount, uint64(5)) + statedb.SetNonce(userAccount, uint64(5), tracing.NonceChangeUnspecified) require.Equal(t, uint64(5), statedb.GetNonce(userAccount)) statedb.SetBalance(unknownAccount, uint256.NewInt(60), tracing.BalanceChangeUnspecified) diff --git a/op-program/client/l2/fast_canon.go b/op-program/client/l2/fast_canon.go index e450b16e994c5..4b40786dd779d 100644 --- a/op-program/client/l2/fast_canon.go +++ b/op-program/client/l2/fast_canon.go @@ -44,7 +44,7 @@ func NewFastCanonicalBlockHeaderOracle( fallback *CanonicalBlockHeaderOracle, ) *FastCanonicalBlockHeaderOracle { chainID := eth.ChainIDFromBig(chainCfg.ChainID) - ctx := &chainContext{engine: beacon.New(nil)} + ctx := &chainContext{engine: beacon.New(nil), config: chainCfg} db := NewOracleBackedDB(kvdb, stateOracle, chainID) cache, _ := simplelru.NewLRU[uint64, *types.Header](historicalCacheSize, nil) return &FastCanonicalBlockHeaderOracle{ @@ -150,12 +150,17 @@ func (o *FastCanonicalBlockHeaderOracle) SetCanonical(head *types.Header) common type chainContext struct { engine consensus.Engine + config *params.ChainConfig } func (c *chainContext) Engine() consensus.Engine { return c.engine } +func (c *chainContext) Config() *params.ChainConfig { + return c.config +} + func (c *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { // The EVM should never call this method during eip-2935 historical block retrieval panic("unexpected call to GetHeader") diff --git a/op-program/client/l2/test/miner.go b/op-program/client/l2/test/miner.go index e1fd48d90107a..94635e58a6a8f 100644 --- a/op-program/client/l2/test/miner.go +++ b/op-program/client/l2/test/miner.go @@ -44,6 +44,8 @@ func NewMiner(t *testing.T, logger log.Logger, isthmusTime uint64) (*Miner, *cor EIP1559Elasticity: 10, EIP1559DenominatorCanyon: &denomCanyon, } + // OP-Stack chain configs must have nil blob schedule + config.BlobScheduleConfig = nil genesis := &core.Genesis{ Config: &config, Difficulty: common.Big0, diff --git a/op-service/eth/blob.go b/op-service/eth/blob.go index b7cf4524a48a0..142feba08968f 100644 --- a/op-service/eth/blob.go +++ b/op-service/eth/blob.go @@ -4,21 +4,23 @@ import ( "crypto/sha256" "errors" "fmt" + "math/big" "reflect" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" ) const ( - BlobSize = 4096 * 32 - MaxBlobDataSize = (4*31+3)*1024 - 4 - EncodingVersion = 0 - VersionOffset = 1 // offset of the version byte in the blob encoding - Rounds = 1024 // number of encode/decode rounds - MaxBlobsPerBlobTx = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob + BlobSize = 4096 * 32 + MaxBlobDataSize = (4*31+3)*1024 - 4 + EncodingVersion = 0 + VersionOffset = 1 // offset of the version byte in the blob encoding + Rounds = 1024 // number of encode/decode rounds ) var ( @@ -280,3 +282,37 @@ func (b *Blob) Clear() { b[i] = 0 } } + +// CalcBlobFeeDefault calculates the blob fee for the given header using eip4844.CalcBlobFee, +// using the requests hash field of the header as a best-effort heuristic whether +// Prague is active, and the default Ethereum blob schedule. +// +// This is to deal in a best-effort way with situations where the chain config is not +// available, but it can be assumed that per the definition of the Prague fork that +// Prague is active iff the requests hash field is present. +func CalcBlobFeeDefault(header *types.Header) *big.Int { + // We make the assumption that eip4844.CalcBlobFee only needs + // - London and Cancun to be active + // - the Prague time to be set relative to the header time + // and that the caller assumes the default prod Ethereum Blob schedule config. + dummyChainCfg := ¶ms.ChainConfig{ + LondonBlock: common.Big0, + CancunTime: ptr(uint64(0)), + BlobScheduleConfig: params.DefaultBlobSchedule, + } + // We assume that the requests hash is set iff Prague is active. + if header.RequestsHash != nil { + dummyChainCfg.PragueTime = ptr(uint64(0)) + } + return eip4844.CalcBlobFee(dummyChainCfg, header) +} + +func CalcBlobFeeCancun(excessBlobGas uint64) *big.Int { + // Dummy Cancun header for calculation. + cancunHeader := &types.Header{ + ExcessBlobGas: &excessBlobGas, + } + return CalcBlobFeeDefault(cancunHeader) +} + +func ptr[T any](t T) *T { return &t } diff --git a/op-service/eth/blob_test.go b/op-service/eth/blob_test.go index 83e21ed88b4e2..5b77e9bd29a35 100644 --- a/op-service/eth/blob_test.go +++ b/op-service/eth/blob_test.go @@ -1,9 +1,13 @@ package eth import ( + "math/big" "math/rand" "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) @@ -291,3 +295,19 @@ func TestExtraneousData(t *testing.T) { require.ErrorIs(t, err, ErrBlobExtraneousData, len(decoded)) } } + +// TestCalcBlobFeeDefault ensures that the best-effort implementation of CalcBlobFeeDefault +// works as expected. In particular, this test will quickly fail and help detect any changes +// made to the internals of the upstream eip4844.CalcBlobFee function, on which +// CalcBlobFeeDefault relies on with certain assumptions. +func TestCalcBlobFeeDefault(t *testing.T) { + header := &types.Header{ + ExcessBlobGas: ptr(uint64(20 * params.DefaultCancunBlobConfig.UpdateFraction)), + } + cancunBlobFee := CalcBlobFeeDefault(header) + require.Equal(t, big.NewInt(485165195), cancunBlobFee) + + header.RequestsHash = &(common.Hash{}) + pragueBlobFee := CalcBlobFeeDefault(header) + require.Equal(t, big.NewInt(617436), pragueBlobFee) +} diff --git a/op-service/eth/block_info.go b/op-service/eth/block_info.go index f0e203233fee3..9530c17ca66d7 100644 --- a/op-service/eth/block_info.go +++ b/op-service/eth/block_info.go @@ -4,7 +4,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -62,7 +61,7 @@ func (b blockInfo) BlobBaseFee() *big.Int { if ebg == nil { return nil } - return eip4844.CalcBlobFee(*ebg) + return CalcBlobFeeDefault(b.Header()) } func (b blockInfo) HeaderRLP() ([]byte, error) { @@ -128,7 +127,7 @@ func (h *headerBlockInfo) BlobBaseFee() *big.Int { if h.header.ExcessBlobGas == nil { return nil } - return eip4844.CalcBlobFee(*h.header.ExcessBlobGas) + return CalcBlobFeeDefault(h.header) } func (h *headerBlockInfo) ReceiptHash() common.Hash { diff --git a/op-service/predeploys/eip2935.go b/op-service/predeploys/eip2935.go index 52cb5bea2cf90..7566accf1f0c4 100644 --- a/op-service/predeploys/eip2935.go +++ b/op-service/predeploys/eip2935.go @@ -1,12 +1,15 @@ package predeploys -import "github.com/ethereum/go-ethereum/common" +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" +) // EIP-2935 defines a deterministic deployment transaction that deploys the recent block hashes contract. // See https://eips.ethereum.org/EIPS/eip-2935 var ( - EIP2935ContractAddr = common.HexToAddress("0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC") - EIP2935ContractCode = common.FromHex("0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500") + EIP2935ContractAddr = params.HistoryStorageAddress + EIP2935ContractCode = params.HistoryStorageCode EIP2935ContractCodeHash = common.HexToHash("0x6e49e66782037c0555897870e29fa5e552daf4719552131a0abce779daec0a5d") - EIP2935ContractDeployer = common.HexToAddress("0xE9f0662359Bb2c8111840eFFD73B9AFA77CbDE10") + EIP2935ContractDeployer = common.HexToAddress("0x3462413Af4609098e1E27A490f554f260213D685") ) diff --git a/op-service/txmgr/estimator.go b/op-service/txmgr/estimator.go index c9968a1018a7a..627e69910443b 100644 --- a/op-service/txmgr/estimator.go +++ b/op-service/txmgr/estimator.go @@ -5,7 +5,7 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum-optimism/optimism/op-service/eth" ) type GasPriceEstimatorFn func(ctx context.Context, backend ETHBackend) (*big.Int, *big.Int, *big.Int, error) @@ -26,7 +26,7 @@ func DefaultGasPriceEstimatorFn(ctx context.Context, backend ETHBackend) (*big.I var blobFee *big.Int if head.ExcessBlobGas != nil { - blobFee = eip4844.CalcBlobFee(*head.ExcessBlobGas) + blobFee = eth.CalcBlobFeeDefault(head) } return tip, head.BaseFee, blobFee, nil diff --git a/op-service/txmgr/txmgr.go b/op-service/txmgr/txmgr.go index 97fd45954b3ee..f439d086f0713 100644 --- a/op-service/txmgr/txmgr.go +++ b/op-service/txmgr/txmgr.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/errutil" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" @@ -760,7 +759,7 @@ func (m *SimpleTxManager) queryReceipt(ctx context.Context, txHash common.Hash, m.metr.RecordBaseFee(tip.BaseFee) if tip.ExcessBlobGas != nil { - blobFee := eip4844.CalcBlobFee(*tip.ExcessBlobGas) + blobFee := eth.CalcBlobFeeDefault(tip) m.metr.RecordBlobBaseFee(blobFee) } diff --git a/op-service/txmgr/txmgr_test.go b/op-service/txmgr/txmgr_test.go index 9b96338e3fafe..b79319689e380 100644 --- a/op-service/txmgr/txmgr_test.go +++ b/op-service/txmgr/txmgr_test.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" @@ -152,7 +151,8 @@ func (g *gasPricer) expGasFeeCap() *big.Int { func (g *gasPricer) expBlobFeeCap() *big.Int { _, _, excessBlobGas := g.feesForEpoch(g.mineAtEpoch) - return eip4844.CalcBlobFee(excessBlobGas) + // Needs to be adjusted when Prague gas pricing is needed. + return eth.CalcBlobFeeCancun(excessBlobGas) } func (g *gasPricer) shouldMine(gasFeeCap *big.Int) bool { @@ -504,7 +504,8 @@ func TestTxMgrConfirmsBlobTxAtHigherGasPrice(t *testing.T) { h := newTestHarness(t) gasTipCap, gasFeeCap, excessBlobGas := h.gasPricer.sample() - blobFeeCap := eip4844.CalcBlobFee(excessBlobGas) + // Needs to be adjusted when testing with Prague activated on L1. + blobFeeCap := eth.CalcBlobFeeCancun(excessBlobGas) t.Log("Blob fee cap:", blobFeeCap, "gasFeeCap:", gasFeeCap) tx := types.NewTx(&types.BlobTx{ diff --git a/op-wheel/cheat/cheat.go b/op-wheel/cheat/cheat.go index ae43bd5624343..0f1ce16c88e42 100644 --- a/op-wheel/cheat/cheat.go +++ b/op-wheel/cheat/cheat.go @@ -134,11 +134,6 @@ func (ch *Cheater) RunAndClose(fn HeadFn) error { // rawdb.WriteTxLookupEntriesByBlock(batch, block) rawdb.WriteHeadBlockHash(batch, blockHash) - // Geth stores the TD for each block separately from the block itself. We must update this - // manually, otherwise Geth thinks we haven't reached TTD yet and tries to build a block - // using pre-merge consensus, which causes a panic. - rawdb.WriteTd(batch, blockHash, preID.Number, ch.Blockchain.GetTd(preID.Hash, preID.Number)) - // Need to copy over receipts since they are keyed by block hash. receipts := rawdb.ReadReceipts(ch.DB, preID.Hash, preID.Number, preHeader.Time, ch.Blockchain.Config()) rawdb.WriteReceipts(batch, blockHash, preID.Number, receipts) @@ -351,7 +346,7 @@ func SetCode(addr common.Address, code hexutil.Bytes) HeadFn { func SetNonce(addr common.Address, nonce uint64) HeadFn { return func(_ *types.Header, headState *state.StateDB) error { - headState.SetNonce(addr, nonce) + headState.SetNonce(addr, nonce, tracing.NonceChangeEoACall) return nil } }