From 17f4179f2ae55a0731b1292af78579efa7d0491e Mon Sep 17 00:00:00 2001 From: keroro Date: Thu, 18 May 2023 17:02:31 +0800 Subject: [PATCH 1/3] ci: add docker-build-push.yml --- .github/workflows/docker-build-push.yml | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/docker-build-push.yml diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml new file mode 100644 index 000000000000..329043656362 --- /dev/null +++ b/.github/workflows/docker-build-push.yml @@ -0,0 +1,48 @@ +name: Build and Push Docker Images + +on: + push: + tags: + - '*' + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push op-node image + uses: docker/build-push-action@v4 + with: + context: . + file: ./op-node/Dockerfile + push: true + tags: ghcr.io/node-real/optimism/op-node:${{ github.ref_name }} + + - name: Build and push op-batcher image + uses: docker/build-push-action@v4 + with: + context: . + file: ./op-batcher/Dockerfile + push: true + tags: ghcr.io/node-real/optimism/op-batcher:${{ github.ref_name }} + + - name: Build and push op-proposer image + uses: docker/build-push-action@v4 + with: + context: . + file: ./op-proposer/Dockerfile + push: true + tags: ghcr.io/node-real/optimism/op-proposer:${{ github.ref_name }} From 9f1167ff5aa1b15078c03b00a32497963aa24780 Mon Sep 17 00:00:00 2001 From: keroro Date: Wed, 7 Jun 2023 11:45:32 +0800 Subject: [PATCH 2/3] feat: create feature module --- op-service/feature/coordinator.go | 36 ++++++ op-service/feature/feature.go | 196 ++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 op-service/feature/coordinator.go create mode 100644 op-service/feature/feature.go diff --git a/op-service/feature/coordinator.go b/op-service/feature/coordinator.go new file mode 100644 index 000000000000..f4a0a4fbd58c --- /dev/null +++ b/op-service/feature/coordinator.go @@ -0,0 +1,36 @@ +package feature + +import ( + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +type CoordinatorClient struct { + sequencerId string + rpc *rpc.Client +} + +func NewCoordinatorClient(url string, sequencerId string) (*CoordinatorClient, error) { + rpc, err := rpc.Dial(url) + if err != nil { + return nil, err + } + return &CoordinatorClient{ + sequencerId: sequencerId, + rpc: rpc, + }, nil +} + +func (c *CoordinatorClient) RequestBuildingBlock() bool { + var respErr error + err := c.rpc.Call(respErr, "coordinator_requestBuildingBlock", c.sequencerId) + if err != nil { + log.Warn("Failed to call coordinator_requestBuildingBlock", "error", err) + return false + } + if respErr != nil { + log.Warn("coordinator_requestBuildingBlock refused request", "error", respErr) + return false + } + return true +} diff --git a/op-service/feature/feature.go b/op-service/feature/feature.go new file mode 100644 index 000000000000..ec83cc5865a9 --- /dev/null +++ b/op-service/feature/feature.go @@ -0,0 +1,196 @@ +package feature + +import ( + "context" + "fmt" + "github.com/ethereum/go-ethereum" + "math/big" + "os" + + "github.com/ethereum-optimism/optimism/op-node/eth" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +var EnableCustomizeL1BlockBaseFee bool +var EnableCustomizeSuggestedL1BaseFee bool +var EnableCustomizeL1Label bool +var EnableCustomizeCraftL1Transaction bool +var EnableCustomizeProposeL1BlockHash bool + +// EnableCoordinator is true when the driver should request permission from op-coordinator before building new blocks. +var EnableCoordinator bool + +// CoordinatorAddr is the address of the Coordinator JSON-RPC endpoint to use. +var CoordinatorAddr string + +// CoordinatorSequencerID is the identifier of the sequencer node to request blocks from. +// It must be unique and same as the name of the sequencer node configured in the Coordinator service. +var CoordinatorSequencerID string +var Coordinator *CoordinatorClient + +var DefaultCustomizedBaseFee = big.NewInt(5000000000) +var DefaultCustomizedSuggestedL1BaseFee = big.NewInt(0) +var DefaultCustomizedL1LabelSub = uint64(15) +var DefaultCustomizedProposeL1BlockHash = common.Hash{} + +func init() { + EnableCustomizeL1BlockBaseFee = os.Getenv("OP_FEATURE_ENABLE_CUSTOMIZE_L1_BLOCK_BASE_FEE") == "true" + EnableCustomizeSuggestedL1BaseFee = os.Getenv("OP_FEATURE_ENABLE_CUSTOMIZE_SUGGESTED_L1_BASE_FEE") == "true" + EnableCustomizeL1Label = os.Getenv("OP_FEATURE_ENABLE_CUSTOMIZE_L1_LABEL") == "true" + EnableCustomizeCraftL1Transaction = os.Getenv("OP_FEATURE_ENABLE_CUSTOMIZE_CRAFT_L1_TRANSACTION") == "true" + EnableCustomizeProposeL1BlockHash = os.Getenv("OP_FEATURE_ENABLE_CUSTOMIZE_PROPOSE_L1_BLOCK_HASH") == "true" + EnableCoordinator = os.Getenv("OP_FEATURE_ENABLE_COORDINATOR") == "true" + CoordinatorAddr = os.Getenv("OP_FEATURE_COORDINATOR_ADDR") + CoordinatorSequencerID = os.Getenv("OP_FEATURE_COORDINATOR_SEQUENCER_ID") + + // Initialize coordinator client + if EnableCoordinator { + if CoordinatorAddr == "" || CoordinatorSequencerID == "" { + panic("CoordinatorAddr and CoordinatorSequencerID must be set when EnableCoordinator is true") + } + + coord, err := NewCoordinatorClient(CoordinatorAddr, CoordinatorSequencerID) + if err != nil { + panic(fmt.Sprintf("Failed to initialize coordinator client: %v", err)) + } + Coordinator = coord + } +} + +func CustomizeL1BaseFeeByTransactions(originBaseFee *big.Int, transactions types.Transactions) *big.Int { + if EnableCustomizeL1BlockBaseFee { + return calcAvgGasPriceByBlockTransactions(transactions) + } else { + return originBaseFee + } +} + +func CustomizeL1BlockInfoByReceipts(originInfo eth.BlockInfo, receipts types.Receipts) eth.BlockInfo { + if EnableCustomizeL1BlockBaseFee { + return &customizedBlockInfo{ + BlockInfo: originInfo, + avgGasPrice: calcAvgGasPriceByBlockReceipts(receipts), + } + } else { + return originInfo + } +} + +func CustomizeSuggestedL1BaseFee(originBaseFee *big.Int) *big.Int { + if EnableCustomizeSuggestedL1BaseFee && originBaseFee == nil { + return DefaultCustomizedSuggestedL1BaseFee + } else { + return originBaseFee + } +} + +// CustomizeL1Label customize the L1 labels "safe" and "finalized" when the feature "EnableCustomizeL1Label" is enabled: +// - keep the "unsafe" label as it is +// - redefine the "safe" label and "finalized" to be the block with 15 blocks less than the "unsafe" block +func CustomizeL1Label(ctx context.Context, l1Source l1BlockInfoSource, label eth.BlockLabel) (eth.BlockInfo, error) { + if EnableCustomizeL1Label && label != eth.Unsafe { + unsafeInfo, err := l1Source.InfoByLabel(ctx, eth.Unsafe) + if err != nil { + return nil, err + } + + if unsafeInfo.NumberU64() <= DefaultCustomizedL1LabelSub { + return l1Source.InfoByNumber(ctx, 0) + } else { + return l1Source.InfoByNumber(ctx, unsafeInfo.NumberU64()-DefaultCustomizedL1LabelSub) + } + } else { + return l1Source.InfoByLabel(ctx, label) + } +} + +func CustomizeCraftL1Transaction(dynRawTx *types.DynamicFeeTx) types.TxData { + if EnableCustomizeCraftL1Transaction { + return &types.LegacyTx{ + Nonce: dynRawTx.Nonce, + GasPrice: dynRawTx.GasFeeCap, + Gas: dynRawTx.Gas, + To: dynRawTx.To, + Value: dynRawTx.Value, + Data: dynRawTx.Data, + } + } else { + return dynRawTx + } +} + +func CustomizeCraftL1CallMsg(callMsg ethereum.CallMsg) ethereum.CallMsg { + if EnableCustomizeCraftL1Transaction { + return ethereum.CallMsg{ + From: callMsg.From, + To: callMsg.To, + GasPrice: callMsg.GasFeeCap, + Data: callMsg.Data, + } + } else { + return callMsg + } +} + +func CustomizeProposeL1BlockHash(originHash common.Hash) common.Hash { + if EnableCustomizeProposeL1BlockHash { + return DefaultCustomizedProposeL1BlockHash + } else { + return originHash + } +} + +// calcAvgGasPriceByBlockTransactions calculates the average gas price of the non-zero-gas-price transactions in the block. +// If there is no non-zero-gas-price transaction in the block, it returns DefaultCustomizedBaseFee. +func calcAvgGasPriceByBlockTransactions(transactions types.Transactions) *big.Int { + nonZeroTxsCnt := big.NewInt(0) + nonZeroTxsSum := big.NewInt(0) + for _, tx := range transactions { + if tx.GasPrice().Cmp(common.Big0) > 0 { + nonZeroTxsCnt.Add(nonZeroTxsCnt, big.NewInt(1)) + nonZeroTxsSum.Add(nonZeroTxsSum, tx.GasPrice()) + } + } + + if nonZeroTxsCnt.Cmp(big.NewInt(0)) == 0 { + return DefaultCustomizedBaseFee + } + return nonZeroTxsSum.Div(nonZeroTxsSum, nonZeroTxsCnt) +} + +// calcAvgGasPriceByBlockReceipts calculates the average gas price of the non-zero-gas-price transactions in the block. +// If there is no non-zero-gas-price transaction in the block, it returns DefaultCustomizedBaseFee. +func calcAvgGasPriceByBlockReceipts(receipts types.Receipts) *big.Int { + nonZeroTxsCnt := big.NewInt(0) + nonZeroTxsSum := big.NewInt(0) + for _, tx := range receipts { + if tx.L1GasPrice.Cmp(common.Big0) > 0 { + nonZeroTxsCnt.Add(nonZeroTxsCnt, big.NewInt(1)) + nonZeroTxsSum.Add(nonZeroTxsSum, tx.L1GasPrice) + } + } + + if nonZeroTxsCnt.Cmp(big.NewInt(0)) == 0 { + return DefaultCustomizedBaseFee + } + return nonZeroTxsSum.Div(nonZeroTxsSum, nonZeroTxsCnt) +} + +// l1BlockInfoSource is a helper interface to avoid circular dependencies when we need to use op-node.source.EthClient +// to get block info. +type l1BlockInfoSource interface { + InfoByLabel(ctx context.Context, label eth.BlockLabel) (eth.BlockInfo, error) + InfoByNumber(ctx context.Context, num uint64) (eth.BlockInfo, error) +} + +type customizedBlockInfo struct { + eth.BlockInfo + avgGasPrice *big.Int +} + +var _ eth.BlockInfo = (*customizedBlockInfo)(nil) + +func (c *customizedBlockInfo) BaseFee() *big.Int { + return c.avgGasPrice +} From 5034a0b1d572adf76c7b936f0b0a5cbaca0d1a12 Mon Sep 17 00:00:00 2001 From: keroro Date: Wed, 7 Jun 2023 11:45:55 +0800 Subject: [PATCH 3/3] feat: apply customized features --- op-chain-ops/genesis/config.go | 6 ++++-- op-e2e/actions/l2_verifier.go | 4 ++++ op-node/node/api.go | 5 +++++ op-node/node/server_test.go | 4 ++++ op-node/rollup/derive/attributes.go | 10 ++++++++++ op-node/rollup/derive/l1_block_info.go | 10 ++++++---- op-node/rollup/driver/sequencer.go | 7 +++++++ op-node/rollup/driver/sequencer_test.go | 2 +- op-node/rollup/driver/state.go | 4 ++++ op-node/sources/l1_client.go | 4 +++- op-proposer/proposer/l2_output_submitter.go | 4 +++- op-service/txmgr/txmgr.go | 15 ++++++++------- .../contracts/L1/ResourceMetering.sol | 2 +- 13 files changed, 60 insertions(+), 17 deletions(-) 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-e2e/actions/l2_verifier.go b/op-e2e/actions/l2_verifier.go index d1293ecc7c6f..6fe7b64ed9d8 100644 --- a/op-e2e/actions/l2_verifier.go +++ b/op-e2e/actions/l2_verifier.go @@ -121,6 +121,10 @@ func (s *l2VerifierBackend) StopSequencer(ctx context.Context) (common.Hash, err return common.Hash{}, errors.New("stopping the L2Verifier sequencer is not supported") } +func (s *l2VerifierBackend) SequencerStopped(ctx context.Context) bool { + return true +} + func (s *L2Verifier) L2Finalized() eth.L2BlockRef { return s.derivation.Finalized() } diff --git a/op-node/node/api.go b/op-node/node/api.go index 46fef276251d..ede83051fa87 100644 --- a/op-node/node/api.go +++ b/op-node/node/api.go @@ -27,6 +27,7 @@ type driverClient interface { SyncStatus(ctx context.Context) (*eth.SyncStatus, error) BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error) ResetDerivationPipeline(context.Context) error + SequencerStopped(ctx context.Context) bool StartSequencer(ctx context.Context, blockHash common.Hash) error StopSequencer(context.Context) (common.Hash, error) } @@ -54,6 +55,10 @@ func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error { return n.dr.ResetDerivationPipeline(ctx) } +func (n *adminAPI) SequencerStopped(ctx context.Context) bool { + return n.dr.SequencerStopped(ctx) +} + func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error { recordDur := n.m.RecordRPCServerRequest("admin_startSequencer") defer recordDur() diff --git a/op-node/node/server_test.go b/op-node/node/server_test.go index 9f89fc7edd03..0f8086ea800a 100644 --- a/op-node/node/server_test.go +++ b/op-node/node/server_test.go @@ -227,3 +227,7 @@ func (c *mockDriverClient) StartSequencer(ctx context.Context, blockHash common. func (c *mockDriverClient) StopSequencer(ctx context.Context) (common.Hash, error) { return c.Mock.MethodCalled("StopSequencer").Get(0).(common.Hash), nil } + +func (c *mockDriverClient) SequencerStopped(ctx context.Context) bool { + return c.Mock.MethodCalled("SequencerStopped").Get(0).(bool) +} 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.go b/op-node/rollup/driver/sequencer.go index af6d469cc19d..41267cdbe8b4 100644 --- a/op-node/rollup/driver/sequencer.go +++ b/op-node/rollup/driver/sequencer.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/ethereum-optimism/optimism/op-service/feature" "time" "github.com/ethereum/go-ethereum/common" @@ -85,6 +86,12 @@ func (d *Sequencer) StartBuildingBlock(ctx context.Context) error { return err } + // Request coordinator for the permission to start building a new block. + // If we are not allowed to build a block, then we wait for the next block time. + if feature.Coordinator != nil && !feature.Coordinator.RequestBuildingBlock() { + return fmt.Errorf("failed to request permission for building block") + } + // If our next L2 block timestamp is beyond the Sequencer drift threshold, then we must produce // empty blocks (other than the L1 info deposit and any user deposits). We handle this by // setting NoTxPool to true, which will cause the Sequencer to not include any transactions 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/rollup/driver/state.go b/op-node/rollup/driver/state.go index 79fd55f2af9a..51a8923651b7 100644 --- a/op-node/rollup/driver/state.go +++ b/op-node/rollup/driver/state.go @@ -371,6 +371,10 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error { } } +func (s *Driver) SequencerStopped(_ctx context.Context) bool { + return s.driverConfig.SequencerStopped +} + func (s *Driver) StartSequencer(ctx context.Context, blockHash common.Hash) error { if !s.driverConfig.SequencerEnabled { return errors.New("sequencer is not enabled") 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