diff --git a/arbos/addressSet/addressSet.go b/arbos/addressSet/addressSet.go index d47f08fc5e..b6894d48ed 100644 --- a/arbos/addressSet/addressSet.go +++ b/arbos/addressSet/addressSet.go @@ -44,9 +44,9 @@ func (aset *AddressSet) GetAnyMember() (*common.Address, error) { if err != nil || size == 0 { return nil, err } - addrAsHash, err := aset.backingStorage.GetByUint64(1) - addr := common.BytesToAddress(addrAsHash.Bytes()) - return &addr, err + sba := aset.backingStorage.OpenStorageBackedAddressOrNil(1) + addr, err := sba.Get() + return addr, err } func (aset *AddressSet) Clear() error { @@ -72,11 +72,11 @@ func (aset *AddressSet) AllMembers() ([]common.Address, error) { } ret := make([]common.Address, size) for i := range ret { - bytes, err := aset.backingStorage.GetByUint64(uint64(i + 1)) + sba := aset.backingStorage.OpenStorageBackedAddress(uint64(i + 1)) + ret[i], err = sba.Get() if err != nil { return nil, err } - ret[i] = common.BytesToAddress(bytes.Bytes()) } return ret, nil } @@ -90,13 +90,15 @@ func (aset *AddressSet) Add(addr common.Address) error { if err != nil { return err } + sba := aset.backingStorage.OpenStorageBackedAddress(1 + size) slot := util.UintToHash(1 + size) addrAsHash := common.BytesToHash(addr.Bytes()) err = aset.byAddress.Set(addrAsHash, slot) if err != nil { return err } - err = aset.backingStorage.Set(slot, addrAsHash) + sba = aset.backingStorage.OpenStorageBackedAddress(1 + size) + err = sba.Set(addr) if err != nil { return err } diff --git a/arbos/incomingmessage.go b/arbos/incomingmessage.go index b2ba70bf66..0edd5035ef 100644 --- a/arbos/incomingmessage.go +++ b/arbos/incomingmessage.go @@ -511,7 +511,11 @@ func parseBatchPostingReportMessage(rd io.Reader, chainId *big.Int, batchFetcher if err != nil { return nil, err } - batchPosterAddr, err := util.AddressFrom256FromReader(rd) + batchPosterAddr, err := util.AddressFromReader(rd) + if err != nil { + return nil, err + } + _, err = util.HashFromReader(rd) // unused: data hash if err != nil { return nil, err } @@ -534,7 +538,9 @@ func parseBatchPostingReportMessage(rd io.Reader, chainId *big.Int, batchFetcher batchDataGas += params.TxDataNonZeroGasEIP2028 } } - data, err := util.PackInternalTxDataBatchPostingReport(batchTimestamp, batchPosterAddr, batchNum, batchDataGas, l1BaseFee.Big()) + data, err := util.PackInternalTxDataBatchPostingReport( + batchTimestamp.Big(), batchPosterAddr, batchNum, batchDataGas, l1BaseFee.Big(), + ) if err != nil { return nil, err } diff --git a/arbos/internal_tx.go b/arbos/internal_tx.go index 7445e761cc..3cb340c0e3 100644 --- a/arbos/internal_tx.go +++ b/arbos/internal_tx.go @@ -81,7 +81,6 @@ func ApplyInternalTxUpdate(tx *types.ArbitrumInternalTx, state *arbosState.Arbos _ = state.RetryableState().TryToReapOneRetryable(currentTime, evm, util.TracingDuringEVM) state.L2PricingState().UpdatePricingModel(l2BaseFee, timePassed, state.FormatVersion(), false) - state.L1PricingState().UpdateTime(currentTime) state.UpgradeArbosVersionIfNecessary(currentTime, evm.ChainConfig()) case InternalTxBatchPostingReportMethodID: diff --git a/arbos/l1pricing/batchPoster.go b/arbos/l1pricing/batchPoster.go index 7dbe50bf5c..73b6a16b29 100644 --- a/arbos/l1pricing/batchPoster.go +++ b/arbos/l1pricing/batchPoster.go @@ -5,18 +5,18 @@ package l1pricing import ( "errors" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/offchainlabs/nitro/arbos/addressSet" "github.com/offchainlabs/nitro/arbos/storage" "github.com/offchainlabs/nitro/util/arbmath" - "math/big" ) var ( PosterAddrsKey = []byte{0} PosterInfoKey = []byte{1} - ErrNotExist = errors.New("batch poster does not exist in table") ErrAlreadyExists = errors.New("tried to add a batch poster that already exists") ) @@ -49,7 +49,7 @@ func (bpt *BatchPostersTable) OpenPoster(poster common.Address) (*BatchPosterSta return nil, err } if !isBatchPoster { - return nil, ErrNotExist + return bpt.AddPoster(poster, poster) } return bpt.internalOpen(poster), nil } @@ -75,7 +75,7 @@ func (bpt *BatchPostersTable) AddPoster(posterAddress common.Address, payTo comm return nil, ErrAlreadyExists } bpState := bpt.internalOpen(posterAddress) - if err := bpState.fundsDue.Set(big.NewInt(0)); err != nil { + if err := bpState.fundsDue.Set(common.Big0); err != nil { return nil, err } if err := bpState.payTo.Set(payTo); err != nil { @@ -98,7 +98,7 @@ func (bpt *BatchPostersTable) TotalFundsDue() (*big.Int, error) { if err != nil { return nil, err } - ret := big.NewInt(0) + ret := common.Big0 for _, posterAddr := range allPosters { poster, err := bpt.OpenPoster(posterAddr) if err != nil { diff --git a/arbos/l1pricing/l1pricing.go b/arbos/l1pricing/l1pricing.go index df738cee24..733a9aeb53 100644 --- a/arbos/l1pricing/l1pricing.go +++ b/arbos/l1pricing/l1pricing.go @@ -25,13 +25,12 @@ type L1PricingState struct { storage *storage.Storage // parameters - batchPosterTable *BatchPostersTable - payRewardsTo storage.StorageBackedAddress - equilibrationTime storage.StorageBackedUint64 - inertia storage.StorageBackedUint64 - perUnitReward storage.StorageBackedUint64 + batchPosterTable *BatchPostersTable + payRewardsTo storage.StorageBackedAddress + equilibrationUnits storage.StorageBackedBigInt + inertia storage.StorageBackedUint64 + perUnitReward storage.StorageBackedUint64 // variables - currentTime storage.StorageBackedUint64 lastUpdateTime storage.StorageBackedUint64 // timestamp of the last update from L1 that we processed fundsDueForRewards storage.StorageBackedBigInt // funds collected since update are recorded as the balance in account L1PricerFundsPoolAddress @@ -50,21 +49,20 @@ var ( const ( payRewardsToOffset uint64 = iota - equilibrationTimeOffset + equilibrationUnitsOffset inertiaOffset perUnitRewardOffset - currentTimeOffset lastUpdateTimeOffset - fundsDueForRewards + fundsDueForRewardsOffset unitsSinceOffset pricePerUnitOffset ) const ( - InitialEquilibrationTime = 60 * 60 // one hour - InitialInertia = 10 - InitialPerUnitReward = 10 - InitialPricePerUnitWei = 50 * params.GWei + InitialEquilibrationUnits uint64 = 60 * params.TxDataNonZeroGasEIP2028 * 100000 // one minute at 100000 bytes / sec + InitialInertia = 10 + InitialPerUnitReward = 10 + InitialPricePerUnitWei = 50 * params.GWei ) func InitializeL1PricingState(sto *storage.Storage) error { @@ -79,12 +77,17 @@ func InitializeL1PricingState(sto *storage.Storage) error { if err := sto.SetByUint64(payRewardsToOffset, util.AddressToHash(BatchPosterAddress)); err != nil { return err } - if err := sto.SetUint64ByUint64(equilibrationTimeOffset, InitialEquilibrationTime); err != nil { + equilibrationUnits := sto.OpenStorageBackedBigInt(equilibrationUnitsOffset) + if err := equilibrationUnits.Set(am.UintToBig(InitialEquilibrationUnits)); err != nil { return err } if err := sto.SetUint64ByUint64(inertiaOffset, InitialInertia); err != nil { return err } + fundsDueForRewards := sto.OpenStorageBackedBigInt(fundsDueForRewardsOffset) + if err := fundsDueForRewards.Set(common.Big0); err != nil { + return err + } if err := sto.SetUint64ByUint64(perUnitRewardOffset, InitialPerUnitReward); err != nil { return err } @@ -97,12 +100,11 @@ func OpenL1PricingState(sto *storage.Storage) *L1PricingState { sto, OpenBatchPostersTable(sto.OpenSubStorage(BatchPosterTableKey)), sto.OpenStorageBackedAddress(payRewardsToOffset), - sto.OpenStorageBackedUint64(equilibrationTimeOffset), + sto.OpenStorageBackedBigInt(equilibrationUnitsOffset), sto.OpenStorageBackedUint64(inertiaOffset), sto.OpenStorageBackedUint64(perUnitRewardOffset), - sto.OpenStorageBackedUint64(currentTimeOffset), sto.OpenStorageBackedUint64(lastUpdateTimeOffset), - sto.OpenStorageBackedBigInt(fundsDueForRewards), + sto.OpenStorageBackedBigInt(fundsDueForRewardsOffset), sto.OpenStorageBackedUint64(unitsSinceOffset), sto.OpenStorageBackedBigInt(pricePerUnitOffset), } @@ -120,12 +122,12 @@ func (ps *L1PricingState) SetPayRewardsTo(addr common.Address) error { return ps.payRewardsTo.Set(addr) } -func (ps *L1PricingState) EquilibrationTime() (uint64, error) { - return ps.equilibrationTime.Get() +func (ps *L1PricingState) EquilibrationUnits() (*big.Int, error) { + return ps.equilibrationUnits.Get() } -func (ps *L1PricingState) SetEquilibrationTime(equilTime uint64) error { - return ps.equilibrationTime.Set(equilTime) +func (ps *L1PricingState) SetEquilibrationUnits(equilUnits *big.Int) error { + return ps.equilibrationUnits.Set(equilUnits) } func (ps *L1PricingState) Inertia() (uint64, error) { @@ -144,14 +146,6 @@ func (ps *L1PricingState) SetPerUnitReward(weiPerUnit uint64) error { return ps.perUnitReward.Set(weiPerUnit) } -func (ps *L1PricingState) CurrentTime() (uint64, error) { - return ps.currentTime.Get() -} - -func (ps *L1PricingState) SetCurrentTime(t uint64) error { - return ps.currentTime.Set(t) -} - func (ps *L1PricingState) LastUpdateTime() (uint64, error) { return ps.lastUpdateTime.Get() } @@ -192,11 +186,6 @@ func (ps *L1PricingState) SetPricePerUnit(price *big.Int) error { return ps.pricePerUnit.Set(price) } -// Update the pricing model with info from the start of a block -func (ps *L1PricingState) UpdateTime(currentTime uint64) { - _ = ps.SetCurrentTime(currentTime) -} - // Update the pricing model based on a payment by a batch poster func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm *vm.EVM, updateTime uint64, currentTime uint64, batchPoster common.Address, weiSpent *big.Int) error { batchPosterTable := ps.BatchPosterTable() @@ -214,7 +203,7 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * if err != nil { return err } - oldShortfall := am.BigSub(am.BigAdd(totalFundsDue, fundsDueForRewards), statedb.GetBalance(L1PricerFundsPoolAddress)) + oldShortfall := am.BigSub(statedb.GetBalance(L1PricerFundsPoolAddress), am.BigAdd(totalFundsDue, fundsDueForRewards)) // compute allocation fraction -- will allocate updateTimeDelta/timeDelta fraction of units and funds to this update lastUpdateTime, err := ps.LastUpdateTime() @@ -267,7 +256,8 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * if am.BigLessThan(availableFunds, paymentForRewards) { paymentForRewards = availableFunds } - if err := ps.SetFundsDueForRewards(am.BigSub(fundsDueForRewards, paymentForRewards)); err != nil { + fundsDueForRewards = am.BigSub(fundsDueForRewards, paymentForRewards) + if err := ps.SetFundsDueForRewards(fundsDueForRewards); err != nil { return err } payRewardsTo, err := ps.PayRewardsTo() @@ -285,7 +275,6 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * if err != nil { return err } - remainingFundsDueToPosters := big.NewInt(0) for _, posterAddr := range allPosterAddrs { poster, err := batchPosterTable.OpenPoster(posterAddr) if err != nil { @@ -315,9 +304,6 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * return err } } - if balanceDueToPoster.Sign() > 0 { - remainingFundsDueToPosters = am.BigAdd(remainingFundsDueToPosters, balanceDueToPoster) - } } // update time @@ -327,32 +313,44 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * // adjust the price if unitsAllocated > 0 { - shortfall := am.BigSub(am.BigAdd(remainingFundsDueToPosters, fundsDueForRewards), statedb.GetBalance(L1PricerFundsPoolAddress)) + totalFundsDue, err = batchPosterTable.TotalFundsDue() + if err != nil { + return err + } + fundsDueForRewards, err = ps.FundsDueForRewards() + if err != nil { + return err + } + shortfall := am.BigSub(statedb.GetBalance(L1PricerFundsPoolAddress), am.BigAdd(totalFundsDue, fundsDueForRewards)) + inertia, err := ps.Inertia() if err != nil { return err } - equilTime, err := ps.EquilibrationTime() + equilUnits, err := ps.EquilibrationUnits() if err != nil { return err } + inertiaUnits := am.BigDivByUint(equilUnits, inertia) price, err := ps.PricePerUnit() if err != nil { return err } - priceChange := am.BigDivByUint( - am.BigAdd(am.BigSub(shortfall, oldShortfall), am.BigDivByUint(shortfall, equilTime)), - unitsAllocated+equilTime/inertia, + allocPlusInert := am.BigAddByUint(inertiaUnits, unitsAllocated) + priceChange := am.BigDiv( + am.BigSub( + am.BigMul(shortfall, am.BigSub(equilUnits, common.Big1)), + am.BigMul(oldShortfall, equilUnits), + ), + am.BigMul(equilUnits, allocPlusInert), ) - newPrice := am.BigSub(price, priceChange) - if newPrice.Sign() >= 0 { - price = newPrice - } else { - price = big.NewInt(0) + newPrice := am.BigAdd(price, priceChange) + if newPrice.Sign() < 0 { + newPrice = common.Big0 } - if err := ps.SetPricePerUnit(price); err != nil { + if err := ps.SetPricePerUnit(newPrice); err != nil { return err } } @@ -360,7 +358,7 @@ func (ps *L1PricingState) UpdateForBatchPosterSpending(statedb vm.StateDB, evm * } func (ps *L1PricingState) AddPosterInfo(tx *types.Transaction, posterAddr common.Address) { - tx.PosterCost = big.NewInt(0) + tx.PosterCost = common.Big0 tx.PosterIsReimbursable = false contains, err := ps.batchPosterTable.ContainsPoster(posterAddr) @@ -400,7 +398,7 @@ func (ps *L1PricingState) PosterDataCost(message core.Message, poster common.Add byteCount, err := byteCountAfterBrotli0(message.Data()) if err != nil { log.Error("failed to compress tx", "err", err) - return big.NewInt(0), 0, false + return common.Big0, 0, false } // Approximate the l1 fee charged for posting this tx's calldata diff --git a/arbos/l1pricing/l1pricing_test.go b/arbos/l1pricing/l1pricing_test.go index 0a14c690cf..7c83373987 100644 --- a/arbos/l1pricing/l1pricing_test.go +++ b/arbos/l1pricing/l1pricing_test.go @@ -4,6 +4,7 @@ package l1pricing import ( + am "github.com/offchainlabs/nitro/util/arbmath" "math" "math/big" "testing" @@ -61,7 +62,7 @@ func TestL1PriceUpdate(t *testing.T) { Fail(t) } - initialPriceEstimate := big.NewInt(InitialPricePerUnitWei) + initialPriceEstimate := am.UintToBig(InitialPricePerUnitWei) priceEstimate, err := ps.PricePerUnit() Require(t, err) if priceEstimate.Cmp(initialPriceEstimate) != 0 { diff --git a/contracts/src/precompiles/ArbOwner.sol b/contracts/src/precompiles/ArbOwner.sol index eaf8df4fc9..1e6e2b3a86 100644 --- a/contracts/src/precompiles/ArbOwner.sol +++ b/contracts/src/precompiles/ArbOwner.sol @@ -66,8 +66,8 @@ interface ArbOwner { /// @notice Upgrades ArbOS to the requested version at the requested timestamp function scheduleArbOSUpgrade(uint64 newVersion, uint64 timestamp) external; - /// @notice Sets equilibration time parameter for L1 price adjustment algorithm - function setL1PricingEquilibrationTime(uint64 equilibrationTime) external; + /// @notice Sets equilibration units parameter for L1 price adjustment algorithm + function setL1PricingEquilibrationUnits(uint256 equilibrationUnits) external; /// @notice Sets inertia parameter for L1 price adjustment algorithm function setL1PricingInertia(uint64 inertia) external; diff --git a/precompiles/ArbGasInfo.go b/precompiles/ArbGasInfo.go index b94837cf2c..bb0dc7c3cb 100644 --- a/precompiles/ArbGasInfo.go +++ b/precompiles/ArbGasInfo.go @@ -127,7 +127,11 @@ func (con ArbGasInfo) GetL1BaseFeeEstimateInertia(c ctx, evm mech) (uint64, erro // Get the current estimate of the L1 basefee func (con ArbGasInfo) GetL1GasPriceEstimate(c ctx, evm mech) (huge, error) { - return c.State.L1PricingState().PricePerUnit() + ppu, err := c.State.L1PricingState().PricePerUnit() + if err != nil { + return nil, err + } + return arbmath.BigMulByUint(ppu, params.TxDataNonZeroGasEIP2028), nil } // Get the fee paid to the aggregator for posting this tx diff --git a/precompiles/ArbOwner.go b/precompiles/ArbOwner.go index baaeedeed5..56d1cda5c7 100644 --- a/precompiles/ArbOwner.go +++ b/precompiles/ArbOwner.go @@ -118,8 +118,8 @@ func (con ArbOwner) ScheduleArbOSUpgrade(c ctx, evm mech, newVersion uint64, tim return c.State.ScheduleArbOSUpgrade(newVersion, timestamp) } -func (con ArbOwner) SetL1PricingEquilibrationTime(c ctx, evm mech, equilibrationTime uint64) error { - return c.State.L1PricingState().SetEquilibrationTime(equilibrationTime) +func (con ArbOwner) SetL1PricingEquilibrationUnits(c ctx, evm mech, equilibrationUnits huge) error { + return c.State.L1PricingState().SetEquilibrationUnits(equilibrationUnits) } func (con ArbOwner) SetL1PricingInertia(c ctx, evm mech, inertia uint64) error { diff --git a/system_tests/fees_test.go b/system_tests/fees_test.go index 051f6c4965..8ba6a21b5b 100644 --- a/system_tests/fees_test.go +++ b/system_tests/fees_test.go @@ -7,14 +7,19 @@ import ( "context" "math/big" "testing" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbcompress" + "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/arbos/l1pricing" "github.com/ethereum/go-ethereum/common" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/util/arbmath" + "github.com/offchainlabs/nitro/util/colors" ) func TestSequencerFeePaid(t *testing.T) { @@ -33,36 +38,131 @@ func TestSequencerFeePaid(t *testing.T) { networkFeeAccount, err := arbOwnerPublic.GetNetworkFeeAccount(callOpts) Require(t, err, "could not get the network fee account") - l1Estimate, err := arbGasInfo.GetL1GasPriceEstimate(callOpts) + l1Estimate, err := arbGasInfo.GetL1BaseFeeEstimate(callOpts) Require(t, err) networkBefore := GetBalance(t, ctx, l2client, networkFeeAccount) - seqBefore := GetBalance(t, ctx, l2client, l1pricing.BatchPosterAddress) l2info.GasPrice = GetBaseFee(t, l2client, ctx) tx, receipt := TransferBalance(t, "Faucet", "Faucet", big.NewInt(0), l2info, l2client, ctx) + txSize := compressedTxSize(t, tx) networkAfter := GetBalance(t, ctx, l2client, networkFeeAccount) - seqAfter := GetBalance(t, ctx, l2client, l1pricing.BatchPosterAddress) + l1Charge := arbmath.BigMulByUint(l2info.GasPrice, receipt.GasUsedForL1) networkRevenue := arbmath.BigSub(networkAfter, networkBefore) - seqRevenue := arbmath.BigSub(seqAfter, seqBefore) - gasUsedForL2 := receipt.GasUsed - receipt.GasUsedForL1 - if !arbmath.BigEquals(networkRevenue, arbmath.BigMulByUint(tx.GasPrice(), gasUsedForL2)) { Fail(t, "network didn't receive expected payment") } - paidBytes := arbmath.BigDiv(seqRevenue, l1Estimate).Uint64() / params.TxDataNonZeroGasEIP2028 + l1GasBought := arbmath.BigDiv(l1Charge, l1Estimate).Uint64() + l1GasActual := txSize * params.TxDataNonZeroGasEIP2028 + + colors.PrintBlue("bytes ", l1GasBought/params.TxDataNonZeroGasEIP2028, txSize) + + if l1GasBought != l1GasActual { + Fail(t, "the sequencer's future revenue does not match its costs", l1GasBought, l1GasActual) + } +} + +func TestSequencerPriceAdjusts(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + chainConfig := params.ArbitrumDevTestChainConfig() + conf := arbnode.ConfigDefaultL1Test() + conf.DelayedSequencer.FinalizeDistance = 1 + + l2info, node, l2client, _, _, l1client, stack := CreateTestNodeOnL1WithConfig(t, ctx, true, conf, chainConfig) + defer stack.Close() + + arbGasInfo, err := precompilesgen.NewArbGasInfo(common.HexToAddress("0x6c"), l2client) + Require(t, err) + lastEstimate, err := arbGasInfo.GetL1BaseFeeEstimate(&bind.CallOpts{Context: ctx}) + Require(t, err) + lastBatchCount, err := node.InboxTracker.GetBatchCount() + Require(t, err) + l1Header, err := l1client.HeaderByNumber(ctx, nil) + Require(t, err) + + sequencerBalanceBefore := GetBalance(t, ctx, l2client, l1pricing.BatchPosterAddress) + timesPriceAdjusted := 0 + + colors.PrintBlue("Initial values") + colors.PrintBlue(" L1 base fee ", l1Header.BaseFee) + colors.PrintBlue(" L1 estimate ", lastEstimate) + + for i := 0; i < 128; i++ { + tx, receipt := TransferBalance(t, "Owner", "Owner", common.Big1, l2info, l2client, ctx) + header, err := l2client.HeaderByHash(ctx, receipt.BlockHash) + Require(t, err) + + units := compressedTxSize(t, tx) * params.TxDataNonZeroGasEIP2028 + currEstimate := arbmath.BigDivByUint(arbmath.BigMulByUint(header.BaseFee, receipt.GasUsedForL1), units) + + if !arbmath.BigEquals(lastEstimate, currEstimate) { + l1Header, err = l1client.HeaderByNumber(ctx, nil) + Require(t, err) + + callOpts := &bind.CallOpts{Context: ctx, BlockNumber: receipt.BlockNumber} + trueEstimate, err := arbGasInfo.GetL1BaseFeeEstimate(callOpts) + Require(t, err) + + colors.PrintGrey("ArbOS updated its L1 estimate") + colors.PrintGrey(" L1 base fee ", l1Header.BaseFee) + colors.PrintGrey(" L1 estimate ", lastEstimate, " ➤ ", currEstimate, " = ", trueEstimate) + + oldDiff := arbmath.BigAbs(arbmath.BigSub(lastEstimate, l1Header.BaseFee)) + newDiff := arbmath.BigAbs(arbmath.BigSub(trueEstimate, l1Header.BaseFee)) + + if arbmath.BigGreaterThan(newDiff, oldDiff) { + Fail(t, "L1 gas price estimate should tend toward the basefee") + } + if !arbmath.BigEquals(trueEstimate, currEstimate) { + Fail(t, "New L1 estimate does not match receipt") + } + if arbmath.BigEquals(trueEstimate, common.Big0) { + Fail(t, "Estimate is zero", i) + } + lastEstimate = trueEstimate + timesPriceAdjusted++ + } + + if i%16 == 0 { + // see that the inbox advances + + for j := 16; j > 0; j-- { + newBatchCount, err := node.InboxTracker.GetBatchCount() + Require(t, err) + if newBatchCount > lastBatchCount { + colors.PrintGrey("posted new batch ", newBatchCount) + lastBatchCount = newBatchCount + break + } + if j == 1 { + Fail(t, "batch count didn't update in time") + } + time.Sleep(time.Millisecond * 100) + } + } + } + + sequencerBalanceAfter := GetBalance(t, ctx, l2client, l1pricing.BatchPosterAddress) + colors.PrintMint("sequencer balance ", sequencerBalanceBefore, " ➤ ", sequencerBalanceAfter) + colors.PrintMint("price changes ", timesPriceAdjusted) + + if timesPriceAdjusted == 0 { + Fail(t, "L1 gas price estimate never adjusted") + } + if !arbmath.BigGreaterThan(sequencerBalanceAfter, sequencerBalanceBefore) { + Fail(t, "sequencer didn't get paid") + } +} +func compressedTxSize(t *testing.T, tx *types.Transaction) uint64 { txBin, err := tx.MarshalBinary() Require(t, err) compressed, err := arbcompress.CompressFast(txBin) Require(t, err) - - _ = paidBytes - _ = compressed - // if uint64(len(compressed)) != paidBytes { - // t.Fatal("unexpected number of bytes paid for") - //} + return uint64(len(compressed)) } diff --git a/util/arbmath/math.go b/util/arbmath/math.go index 336c334a31..e54c3aa64f 100644 --- a/util/arbmath/math.go +++ b/util/arbmath/math.go @@ -118,6 +118,11 @@ func BigDiv(dividend *big.Int, divisor *big.Int) *big.Int { return new(big.Int).Div(dividend, divisor) } +// absolute value of a huge +func BigAbs(value *big.Int) *big.Int { + return new(big.Int).Abs(value) +} + // add a uint to a huge func BigAddByUint(augend *big.Int, addend uint64) *big.Int { return new(big.Int).Add(augend, UintToBig(addend))