diff --git a/go.mod b/go.mod index 789e145b6fefe..225b380f14ea6 100644 --- a/go.mod +++ b/go.mod @@ -308,7 +308,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101603.2-0.20251016091451-5c6d276814f2 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101603.2-0.20251017174928-6658a36c9862 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index 58101d0357309..61aeed136a44a 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,8 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e h1:iy1vBIzACYUyOVyoADUwvAiq2eOPC0yVsDUdolPwQjk= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e/go.mod h1:DYj7+vYJ4cIB7zera9mv4LcAynCL5u4YVfoeUu6Wa+w= -github.com/ethereum-optimism/op-geth v1.101603.2-0.20251016091451-5c6d276814f2 h1:fvYTR+KOcvSDd/gJuh+ALG/Fx7Y0xU3ZaDkgT/kqVi0= -github.com/ethereum-optimism/op-geth v1.101603.2-0.20251016091451-5c6d276814f2/go.mod h1:Ct2QjqZ2UKgvvgKLLYzoh/DBicJZB8DXsv45DgEjcco= +github.com/ethereum-optimism/op-geth v1.101603.2-0.20251017174928-6658a36c9862 h1:15VLb6evTBOzznvwZxesXxLFI34gHjFfIlU+Oaga3sc= +github.com/ethereum-optimism/op-geth v1.101603.2-0.20251017174928-6658a36c9862/go.mod h1:Ct2QjqZ2UKgvvgKLLYzoh/DBicJZB8DXsv45DgEjcco= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251009180028-9b4658b9b7af h1:WWz0gJM/boaUImtJnROecPirAerKCLpAU4m6Tx0ArOg= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251009180028-9b4658b9b7af/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= diff --git a/op-acceptance-tests/tests/jovian/da_footprint_test.go b/op-acceptance-tests/tests/jovian/da_footprint_test.go index e3a8c83902af7..d778b7ca1fa64 100644 --- a/op-acceptance-tests/tests/jovian/da_footprint_test.go +++ b/op-acceptance-tests/tests/jovian/da_footprint_test.go @@ -3,17 +3,25 @@ package jovian import ( "context" "crypto/rand" + "math/big" "sync" "testing" "time" "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop/loadtest" + "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" + "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/txinclude" + "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" + "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum-optimism/optimism/op-service/txplan" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) type CalldataSpammer struct { @@ -34,62 +42,190 @@ func (s *CalldataSpammer) Spam(t devtest.T) error { return err } +type daFootprintSystemConfig struct { + SetDAFootprintGasScalar func(scalar uint16) bindings.TypedCall[any] `sol:"setDAFootprintGasScalar"` + DAFootprintGasScalar func() bindings.TypedCall[uint16] `sol:"daFootprintGasScalar"` +} + +type daFootprintL1Block struct { + DAFootprintGasScalar func() bindings.TypedCall[uint16] `sol:"daFootprintGasScalar"` +} + +type daFootprintEnv struct { + l1Client *dsl.L1ELNode + l2Network *dsl.L2Network + l2EL *dsl.L2ELNode + systemConfig daFootprintSystemConfig + l1Block daFootprintL1Block +} + +func newDAFootprintEnv(t devtest.T, l2Network *dsl.L2Network, l1EL *dsl.L1ELNode, l2EL *dsl.L2ELNode) *daFootprintEnv { + systemConfig := bindings.NewBindings[daFootprintSystemConfig]( + bindings.WithClient(l1EL.EthClient()), + bindings.WithTo(l2Network.Escape().Deployment().SystemConfigProxyAddr()), + bindings.WithTest(t), + ) + + l1Block := bindings.NewBindings[daFootprintL1Block]( + bindings.WithClient(l2EL.Escape().EthClient()), + bindings.WithTo(common.HexToAddress("0x4200000000000000000000000000000000000015")), + bindings.WithTest(t), + ) + + return &daFootprintEnv{ + l1Client: l1EL, + l2Network: l2Network, + l2EL: l2EL, + systemConfig: systemConfig, + l1Block: l1Block, + } +} + +func (env *daFootprintEnv) checkCompatibility(t devtest.T) { + // Ensure getters exist on both L1 SystemConfig and L2 L1Block + _, err := contractio.Read(env.systemConfig.DAFootprintGasScalar(), t.Ctx()) + t.Require().NoError(err) + _, err = contractio.Read(env.l1Block.DAFootprintGasScalar(), t.Ctx()) + t.Require().NoError(err) +} + +func (env *daFootprintEnv) getSystemConfigOwner(t devtest.T) *dsl.EOA { + priv := env.l2Network.Escape().Keys().Secret(devkeys.SystemConfigOwner.Key(env.l2Network.ChainID().ToBig())) + return dsl.NewKey(t, priv).User(env.l1Client) +} + +func (env *daFootprintEnv) setDAFootprintGasScalarViaSystemConfig(t devtest.T, scalar uint16) *types.Receipt { + owner := env.getSystemConfigOwner(t) + rec, err := contractio.Write(env.systemConfig.SetDAFootprintGasScalar(scalar), t.Ctx(), owner.Plan()) + t.Require().NoError(err, "SetDAFootprintGasScalar transaction failed") + t.Logf("Set DA footprint gas scalar on L1: scalar=%d", scalar) + return rec +} + +// expectL1BlockDAFootprintGasScalar expects the given DA footprint gas scalar to be set in the L1Block contract. +func (env *daFootprintEnv) expectL1BlockDAFootprintGasScalar(t devtest.T, expected uint16) { + current, err := contractio.Read(env.l1Block.DAFootprintGasScalar(), t.Ctx()) + t.Require().NoError(err, "Failed to read DA footprint gas scalar from L1Block") + t.Require().Equal(expected, current) +} + func TestDAFootprint(gt *testing.T) { t := devtest.SerialT(gt) sys := presets.NewMinimal(t) + require := t.Require() + + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Jovian) + require.NoError(err, "Jovian fork must be active for this test") + + env := newDAFootprintEnv(t, sys.L2Chain, sys.L1EL, sys.L2EL) + env.checkCompatibility(t) + + systemOwner := env.getSystemConfigOwner(t) + sys.FunderL1.FundAtLeast(systemOwner, eth.OneTenthEther) l2BlockTime := time.Duration(sys.L2Chain.Escape().RollupConfig().BlockTime) * time.Second + sys.L2EL.WaitForOnline() ethClient := sys.L2EL.Escape().EthClient() - sys.L2EL.WaitForOnline() + s1000 := uint16(1000) + s0 := uint16(0) + cases := []struct { + name string + setScalar *uint16 + expected uint16 + }{ + {"DefaultScalar", nil, uint16(eth.DAFootprintGasScalarDefault)}, + {"Scalar1000", &s1000, uint16(1000)}, + {"ScalarZeroUsesDefault", &s0, uint16(eth.DAFootprintGasScalarDefault)}, + } - var wg sync.WaitGroup - defer wg.Wait() - - ctx, cancel := context.WithTimeout(t.Ctx(), time.Minute) - defer cancel() - t = t.WithCtx(ctx) - - wg.Add(1) - go func() { - defer wg.Done() - eoa := sys.FunderL2.NewFundedEOA(eth.OneEther.Mul(100)) - includer := txinclude.NewPersistent(txinclude.NewPkSigner(eoa.Key().Priv(), eoa.ChainID().ToBig()), struct { - *txinclude.Resubmitter - *txinclude.Monitor - }{ - txinclude.NewResubmitter(ethClient, l2BlockTime), - txinclude.NewMonitor(ethClient, l2BlockTime), - }) - loadtest.NewBurst(l2BlockTime).Run(t, NewCalldataSpammer(loadtest.NewSyncEOA(includer, eoa.Plan()))) - }() - - for range time.Tick(l2BlockTime) { - info, txs, err := ethClient.InfoAndTxsByLabel(t.Ctx(), eth.Unsafe) - t.Require().NoError(err) - - blockGasUsed := info.GasUsed() - - receipt, err := ethClient.TransactionReceipt(t.Ctx(), txs[len(txs)-1].Hash()) - t.Require().NoError(err) - // The last tx's cumulative gas used is the block's total transaction gas used. - totalTxGasUsed := receipt.CumulativeGasUsed - if totalTxGasUsed == blockGasUsed { - t.Logf("Block %d:%s doesn't have excess gas used, trying next...", info.NumberU64(), info.Hash()) - continue - } - - var totalDAFootprint uint64 - for _, tx := range txs { - if tx.IsDepositTx() { - continue + for _, tc := range cases { + t.Run(tc.name, func(t devtest.T) { + if tc.setScalar != nil { + rec := env.setDAFootprintGasScalarViaSystemConfig(t, *tc.setScalar) + // Wait for change to propagate to L2 + env.l2EL.WaitL1OriginReached(eth.Unsafe, rec.BlockNumber.Uint64(), 20) + } else { + sys.L2EL.WaitForBlockNumber(2) // make sure we don't assert on genesis or first block + } + env.expectL1BlockDAFootprintGasScalar(t, tc.expected) + + var wg sync.WaitGroup + defer wg.Wait() + + ctx, cancel := context.WithTimeout(t.Ctx(), time.Minute) + defer cancel() + t = t.WithCtx(ctx) + + wg.Add(1) + go func() { + defer wg.Done() + eoa := sys.FunderL2.NewFundedEOA(eth.OneEther.Mul(100)) + includer := txinclude.NewPersistent(txinclude.NewPkSigner(eoa.Key().Priv(), eoa.ChainID().ToBig()), struct { + *txinclude.Resubmitter + *txinclude.Monitor + }{ + txinclude.NewResubmitter(ethClient, l2BlockTime), + txinclude.NewMonitor(ethClient, l2BlockTime), + }) + loadtest.NewBurst(l2BlockTime).Run(t, NewCalldataSpammer(loadtest.NewSyncEOA(includer, eoa.Plan()))) + }() + + rollupCfg := sys.L2Chain.Escape().RollupConfig() + gasTarget := rollupCfg.Genesis.SystemConfig.GasLimit / rollupCfg.ChainOpConfig.EIP1559Elasticity + + var blockDAFootprint uint64 + info := sys.L2EL.WaitForUnsafe(func(info eth.BlockInfo) (bool, error) { + blockGasUsed := info.GasUsed() + blobGasUsed := info.BlobGasUsed() + t.Require().NotNil(blobGasUsed, "blobGasUsed must not be nil for Jovian chains") + blockDAFootprint = *blobGasUsed + if blockDAFootprint <= blockGasUsed { + t.Logf("Block %s has DA footprint (%d) <= gasUsed (%d), trying next...", + eth.ToBlockID(info), blockDAFootprint, blockGasUsed) + return false, nil + } + if blockDAFootprint <= gasTarget { + t.Logf("Block %s has DA footprint (%d) <= gasTarget (%d), trying next...", + eth.ToBlockID(info), blockDAFootprint, gasTarget) + return false, nil + } + return true, nil + }) + + _, txs, err := ethClient.InfoAndTxsByHash(t.Ctx(), info.Hash()) + t.Require().NoError(err) + + var totalDAFootprint uint64 + for _, tx := range txs { + if tx.IsDepositTx() { + continue + } + totalDAFootprint += tx.RollupCostData().EstimatedDASize().Uint64() * uint64(tc.expected) + } + t.Logf("Block %s has header/calculated DA footprint %d/%d", + eth.ToBlockID(info), blockDAFootprint, totalDAFootprint) + t.Require().Equal(totalDAFootprint, blockDAFootprint, "Calculated DA footprint doesn't match block header DA footprint") + + // Check base fee calculation of next block + // Calculate expected base fee as: + // parentBaseFee + max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) + var ( + baseFee = new(big.Int) + denom = new(big.Int) + ) + baseFee.SetUint64(blockDAFootprint - gasTarget) // gasUsedDelta + baseFee.Mul(baseFee, info.BaseFee()) + baseFee.Div(baseFee, denom.SetUint64(gasTarget)) + baseFee.Div(baseFee, denom.SetUint64(*rollupCfg.ChainOpConfig.EIP1559DenominatorCanyon)) + if baseFee.Cmp(common.Big1) < 0 { + baseFee.Add(info.BaseFee(), common.Big1) + } else { + baseFee.Add(info.BaseFee(), baseFee) } - totalDAFootprint += tx.RollupCostData().EstimatedDASize().Uint64() * eth.DAFootprintGasScalarDefault - } - t.Logf("Block %d:%s has DA footprint exceeding cumulative tx gas used, %d > %d", info.NumberU64(), info.Hash(), - totalDAFootprint, totalTxGasUsed) - t.Require().Less(totalTxGasUsed, blockGasUsed) - t.Require().Equal(totalDAFootprint, blockGasUsed) - return + t.Logf("Expected base fee: %s", baseFee) + + next := sys.L2EL.WaitForBlockNumber(info.NumberU64() + 1) + t.Require().Equal(baseFee, next.BaseFee(), "Wrong base fee") + }) } - t.Require().FailNow("Never saw a block with gasUsed > total transaction gasUsed.") } diff --git a/op-devstack/dsl/el.go b/op-devstack/dsl/el.go index b7e4d97251a72..d727120a00805 100644 --- a/op-devstack/dsl/el.go +++ b/op-devstack/dsl/el.go @@ -36,24 +36,42 @@ func (el *elNode) WaitForBlock() eth.BlockRef { return el.waitForNextBlock(1) } -func (el *elNode) WaitForBlockNumber(targetBlock uint64) eth.BlockRef { - var newRef eth.BlockRef - +func (el *elNode) WaitForLabel(label eth.BlockLabel, predicate func(eth.BlockInfo) (bool, error)) eth.BlockInfo { + var block eth.BlockInfo err := wait.For(el.ctx, 500*time.Millisecond, func() (bool, error) { - newBlock, err := el.inner.EthClient().InfoByLabel(el.ctx, eth.Unsafe) + var err error + block, err = el.inner.EthClient().InfoByLabel(el.ctx, label) if err != nil { return false, err } - - newRef = eth.InfoToL1BlockRef(newBlock) - if newBlock.NumberU64() >= targetBlock { - el.log.Info("Target block reached", "chain", el.ChainID(), "block", newRef) - return true, nil + ok, err := predicate(block) + if ok { + el.log.Info("Target block reached", "chain", el.ChainID(), "block", eth.ToBlockID(block)) + } else if err == nil { + el.log.Debug("Target block not reached yet", "chain", el.ChainID(), "block", eth.ToBlockID(block)) } - return false, nil + return ok, err + }) + el.require.NoError(err, "Failed to find block") + return block +} + +func (el *elNode) WaitForLabelRef(label eth.BlockLabel, predicate func(eth.BlockInfo) (bool, error)) eth.BlockRef { + return eth.InfoToL1BlockRef(el.WaitForLabel(label, predicate)) +} + +func (el *elNode) WaitForUnsafe(predicate func(eth.BlockInfo) (bool, error)) eth.BlockInfo { + return el.WaitForLabel(eth.Unsafe, predicate) +} + +func (el *elNode) WaitForUnsafeRef(predicate func(eth.BlockInfo) (bool, error)) eth.BlockRef { + return eth.InfoToL1BlockRef(el.WaitForUnsafe(predicate)) +} + +func (el *elNode) WaitForBlockNumber(targetBlock uint64) eth.BlockInfo { + return el.WaitForUnsafe(func(info eth.BlockInfo) (bool, error) { + return info.NumberU64() >= targetBlock, nil }) - el.require.NoError(err, "Expected to reach target block") - return newRef } func (el *elNode) WaitForOnline() { @@ -76,43 +94,17 @@ func (el *elNode) waitForNextBlock(blocksFromNow uint64) eth.BlockRef { initial, err := el.inner.EthClient().InfoByLabel(el.ctx, eth.Unsafe) el.require.NoError(err, "Expected to get latest block from execution client") targetBlock := initial.NumberU64() + blocksFromNow - initialRef := eth.InfoToL1BlockRef(initial) - var newRef eth.BlockRef - - err = wait.For(el.ctx, 500*time.Millisecond, func() (bool, error) { - newBlock, err := el.inner.EthClient().InfoByLabel(el.ctx, eth.Unsafe) - if err != nil { - return false, err - } - - newRef = eth.InfoToL1BlockRef(newBlock) - if newBlock.NumberU64() >= targetBlock { - el.log.Info("Target block reached", "block", newRef) - return true, nil - } - if initialRef == newRef { - el.log.Info("Still same block detected as initial", "block", initialRef) - return false, nil - } else { - el.log.Info("New block detected", "new_block", newRef, "prev_block", initialRef) - } - return false, nil + return el.WaitForUnsafeRef(func(info eth.BlockInfo) (bool, error) { + return info.NumberU64() >= targetBlock, nil }) - el.require.NoError(err, "Expected to reach target block") - return newRef } // WaitForTime waits until the chain has reached or surpassed the given timestamp. func (el *elNode) WaitForTime(timestamp uint64) eth.BlockRef { - for range time.Tick(500 * time.Millisecond) { - ref, err := el.inner.EthClient().BlockRefByLabel(el.ctx, eth.Unsafe) - el.require.NoError(err) - if ref.Time >= timestamp { - return ref - } - } - return eth.BlockRef{} // Should never be reached. + return el.WaitForUnsafeRef(func(info eth.BlockInfo) (bool, error) { + return info.Time() >= timestamp, nil + }) } func (el *elNode) stackEL() stack.ELNode { @@ -127,18 +119,7 @@ func (el *elNode) WaitForFinalization() eth.BlockRef { currentBlock, err := el.inner.EthClient().InfoByLabel(el.ctx, eth.Unsafe) el.require.NoError(err, "Expected to get current block from execution client") - var finalizedBlock eth.BlockRef - el.require.Eventually(func() bool { - el.log.Info("Waiting for finalization") - block, err := el.inner.EthClient().InfoByLabel(el.ctx, eth.Finalized) - if err != nil { - return false - } - if block.NumberU64() >= currentBlock.NumberU64() { - finalizedBlock = eth.InfoToL1BlockRef(block) - return true - } - return false - }, 5*time.Minute, 500*time.Millisecond, "Expected to be online") - return finalizedBlock + return el.WaitForLabelRef(eth.Finalized, func(info eth.BlockInfo) (bool, error) { + return info.NumberU64() >= currentBlock.NumberU64(), nil + }) } diff --git a/op-devstack/dsl/l2_el.go b/op-devstack/dsl/l2_el.go index fe0c2518eab3c..ad8e89fbabf0e 100644 --- a/op-devstack/dsl/l2_el.go +++ b/op-devstack/dsl/l2_el.go @@ -178,6 +178,29 @@ func (el *L2ELNode) TransactionTimeout() time.Duration { return el.inner.TransactionTimeout() } +// L1OriginReachedFn returns a lambda that waits for the L1 origin to reach the target block number. +func (el *L2ELNode) L1OriginReachedFn(label eth.BlockLabel, l1OriginTarget uint64, attempts int) CheckFunc { + return func() error { + logger := el.log.With("id", el.inner.ID(), "chain", el.ChainID(), "label", label, "l1OriginTarget", l1OriginTarget) + logger.Info("Expecting L2EL to reach L1 origin") + return retry.Do0(el.ctx, attempts, &retry.FixedStrategy{Dur: 1 * time.Second}, + func() error { + head := el.BlockRefByLabel(label) + if head.L1Origin.Number >= l1OriginTarget { + logger.Info("L2EL advanced L1 origin", "l1OriginTarget", l1OriginTarget) + return nil + } + logger.Debug("L2EL sync status", "head", head.ID()) + return fmt.Errorf("L1 origin of %s not advanced yet", label) + }) + } +} + +// WaitL1OriginReached waits for the L1 origin to reach the target block number. +func (el *L2ELNode) WaitL1OriginReached(label eth.BlockLabel, l1OriginTarget uint64, attempts int) { + el.require.NoError(el.L1OriginReachedFn(label, l1OriginTarget, attempts)()) +} + // VerifyWithdrawalHashChangedIn verifies that the withdrawal hash changed between the parent and current block // This is used to verify that the withdrawal hash changed in the block where the withdrawal was initiated func (el *L2ELNode) VerifyWithdrawalHashChangedIn(blockHash common.Hash) { diff --git a/op-devstack/dsl/l2_network.go b/op-devstack/dsl/l2_network.go index bdba587724a22..92751f231ece0 100644 --- a/op-devstack/dsl/l2_network.go +++ b/op-devstack/dsl/l2_network.go @@ -241,11 +241,9 @@ func (n *L2Network) AwaitActivation(t devtest.T, forkName rollup.ForkName) eth.B } blockNum, err := rollupCfg.TargetBlockNumber(activationTime) require.NoError(err) - NewL2ELNode(el, n.control).WaitForBlockNumber(blockNum).ID() - activationBlock, err := el.EthClient().BlockRefByNumber(t.Ctx(), blockNum) - require.NoError(err, "Failed to get activation block") - t.Logger().Info("Activation block", "block", activationBlock.ID()) - return activationBlock.ID() + activationBlock := eth.ToBlockID(NewL2ELNode(el, n.control).WaitForBlockNumber(blockNum)) + t.Logger().Info("Activation block", "block", activationBlock) + return activationBlock } diff --git a/op-program/client/l2/engineapi/block_processor.go b/op-program/client/l2/engineapi/block_processor.go index c692384267020..be7178b32ed0e 100644 --- a/op-program/client/l2/engineapi/block_processor.go +++ b/op-program/client/l2/engineapi/block_processor.go @@ -177,14 +177,6 @@ func (b *BlockProcessor) Assemble() (*types.Block, types.Receipts, error) { } } - if cfg.IsJovian(b.header.Time) { - gasUsed, err := types.CalcGasUsedJovian(b.transactions, b.header.GasUsed) - if err != nil { - return nil, nil, fmt.Errorf("failed to calculate gas used for Jovian block: %w", err) - } - b.header.GasUsed = gasUsed - } - block, err := b.dataProvider.Engine().FinalizeAndAssemble(b.dataProvider, b.header, b.state, &body, b.receipts) if err != nil { return nil, nil, err diff --git a/op-service/eth/block_info.go b/op-service/eth/block_info.go index 10e6f5761f369..3d09d8ba535a0 100644 --- a/op-service/eth/block_info.go +++ b/op-service/eth/block_info.go @@ -26,6 +26,7 @@ type BlockInfo interface { ExcessBlobGas() *uint64 ReceiptHash() common.Hash GasUsed() uint64 + BlobGasUsed() *uint64 GasLimit() uint64 ParentBeaconRoot() *common.Hash // Dencun extension WithdrawalsRoot() *common.Hash // Isthmus extension @@ -145,6 +146,10 @@ func (h *headerBlockInfo) GasUsed() uint64 { return h.header.GasUsed } +func (h *headerBlockInfo) BlobGasUsed() *uint64 { + return h.header.BlobGasUsed +} + func (h *headerBlockInfo) GasLimit() uint64 { return h.header.GasLimit } diff --git a/op-service/testutils/l1info.go b/op-service/testutils/l1info.go index 39b03f4e00511..d15c9790c617b 100644 --- a/op-service/testutils/l1info.go +++ b/op-service/testutils/l1info.go @@ -28,6 +28,7 @@ type MockBlockInfo struct { InfoExcessBlobGas *uint64 InfoReceiptRoot common.Hash InfoGasUsed uint64 + InfoBlobGasUsed *uint64 InfoGasLimit uint64 InfoHeaderRLP []byte @@ -83,6 +84,10 @@ func (l *MockBlockInfo) GasUsed() uint64 { return l.InfoGasUsed } +func (l *MockBlockInfo) BlobGasUsed() *uint64 { + return l.InfoBlobGasUsed +} + func (l *MockBlockInfo) GasLimit() uint64 { return l.InfoGasLimit }