Skip to content

Commit 03949e7

Browse files
Merge pull request #4070 from OffchainLabs/port-arbos51-redeem-fix-to-con5-rel
Fix retryable gas calculation bug and add ArbOS51 version (#4047)
2 parents 475b033 + 6f6d6e9 commit 03949e7

25 files changed

+245
-66
lines changed

arbos/arbosState/arbosstate.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func OpenArbosState(stateDB vm.StateDB, burner burn.Burner) (*ArbosState, error)
8585
upgradeTimestamp: backingStorage.OpenStorageBackedUint64(uint64(upgradeTimestampOffset)),
8686
networkFeeAccount: backingStorage.OpenStorageBackedAddress(uint64(networkFeeAccountOffset)),
8787
l1PricingState: l1pricing.OpenL1PricingState(backingStorage.OpenCachedSubStorage(l1PricingSubspace), arbosVersion),
88-
l2PricingState: l2pricing.OpenL2PricingState(backingStorage.OpenCachedSubStorage(l2PricingSubspace)),
88+
l2PricingState: l2pricing.OpenL2PricingState(backingStorage.OpenCachedSubStorage(l2PricingSubspace), arbosVersion),
8989
retryableState: retryables.OpenRetryableState(backingStorage.OpenCachedSubStorage(retryablesSubspace), stateDB),
9090
addressTable: addressTable.Open(backingStorage.OpenCachedSubStorage(addressTableSubspace)),
9191
chainOwners: addressSet.OpenAddressSet(backingStorage.OpenCachedSubStorage(chainOwnerSubspace)),
@@ -391,6 +391,10 @@ func (state *ArbosState) UpgradeArbosVersion(
391391
ensure(p.UpgradeToArbosVersion(nextArbosVersion))
392392
ensure(p.Save())
393393
ensure(state.l2PricingState.SetMaxPerTxGasLimit(l2pricing.InitialPerTxGasLimitV50))
394+
395+
case params.ArbosVersion_51:
396+
// nothing
397+
394398
default:
395399
return fmt.Errorf(
396400
"the chain is upgrading to unsupported ArbOS version %v, %w",
@@ -409,6 +413,7 @@ func (state *ArbosState) UpgradeArbosVersion(
409413
state.arbosVersion = nextArbosVersion
410414
state.programs.ArbosVersion = nextArbosVersion
411415
state.l1PricingState.ArbosVersion = nextArbosVersion
416+
state.l2PricingState.ArbosVersion = nextArbosVersion
412417
}
413418

414419
if firstTime && upgradeTo >= params.ArbosVersion_6 {

arbos/internal_tx.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func ApplyInternalTxUpdate(tx *types.ArbitrumInternalTx, state *arbosState.Arbos
104104
_ = state.RetryableState().TryToReapOneRetryable(currentTime, evm, util.TracingDuringEVM)
105105
_ = state.RetryableState().TryToReapOneRetryable(currentTime, evm, util.TracingDuringEVM)
106106

107-
state.L2PricingState().UpdatePricingModel(timePassed, state.ArbOSVersion())
107+
state.L2PricingState().UpdatePricingModel(timePassed)
108108

109109
return state.UpgradeArbosVersionIfNecessary(currentTime, evm.StateDB, evm.ChainConfig())
110110
case InternalTxBatchPostingReportMethodID:

arbos/l2pricing/l2pricing.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ type L2PricingState struct {
7474
backlogTolerance storage.StorageBackedUint64
7575
perTxGasLimit storage.StorageBackedUint64
7676
constraints *storage.SubStorageVector
77+
78+
ArbosVersion uint64
7779
}
7880

7981
const (
@@ -90,6 +92,7 @@ const (
9092
var constraintsKey []byte = []byte{0}
9193

9294
const GethBlockGasLimit = 1 << 50
95+
const gasConstraintsMaxNum = 20
9396

9497
func InitializeL2PricingState(sto *storage.Storage) error {
9598
_ = sto.SetUint64ByUint64(speedLimitPerSecondOffset, InitialSpeedLimitPerSecondV0)
@@ -101,7 +104,7 @@ func InitializeL2PricingState(sto *storage.Storage) error {
101104
return sto.SetUint64ByUint64(minBaseFeeWeiOffset, InitialMinimumBaseFeeWei)
102105
}
103106

104-
func OpenL2PricingState(sto *storage.Storage) *L2PricingState {
107+
func OpenL2PricingState(sto *storage.Storage, arbosVersion uint64) *L2PricingState {
105108
return &L2PricingState{
106109
storage: sto,
107110
speedLimitPerSecond: sto.OpenStorageBackedUint64(speedLimitPerSecondOffset),
@@ -113,6 +116,7 @@ func OpenL2PricingState(sto *storage.Storage) *L2PricingState {
113116
backlogTolerance: sto.OpenStorageBackedUint64(backlogToleranceOffset),
114117
perTxGasLimit: sto.OpenStorageBackedUint64(perTxGasLimitOffset),
115118
constraints: storage.OpenSubStorageVector(sto.OpenSubStorage(constraintsKey)),
119+
ArbosVersion: arbosVersion,
116120
}
117121
}
118122

@@ -254,3 +258,7 @@ func (ps *L2PricingState) ClearConstraints() error {
254258
}
255259
return nil
256260
}
261+
262+
func (ps *L2PricingState) GasConstraintsMaxNum() int {
263+
return gasConstraintsMaxNum
264+
}

arbos/l2pricing/l2pricing_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"testing"
99

10+
"github.com/ethereum/go-ethereum/params"
11+
1012
"github.com/offchainlabs/nitro/arbos/burn"
1113
"github.com/offchainlabs/nitro/arbos/storage"
1214
"github.com/offchainlabs/nitro/util/arbmath"
@@ -18,7 +20,7 @@ func PricingForTest(t *testing.T) *L2PricingState {
1820
storage := storage.NewMemoryBacked(burn.NewSystemBurner(nil, false))
1921
err := InitializeL2PricingState(storage)
2022
Require(t, err)
21-
return OpenL2PricingState(storage)
23+
return OpenL2PricingState(storage, params.MaxDebugArbosVersionSupported)
2224
}
2325

2426
func fakeBlockUpdate(t *testing.T, pricing *L2PricingState, gasUsed int64, timePassed uint64) {

arbos/l2pricing/model.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ethereum/go-ethereum/params"
1111

12+
"github.com/offchainlabs/nitro/arbos/storage"
1213
"github.com/offchainlabs/nitro/util/arbmath"
1314
)
1415

@@ -24,8 +25,8 @@ const InitialPricingInertia = 102
2425
const InitialBacklogTolerance = 10
2526
const InitialPerTxGasLimitV50 uint64 = 32 * 1000000
2627

27-
func (ps *L2PricingState) ShouldUseMultiConstraints(arbosVersion uint64) (bool, error) {
28-
if arbosVersion >= ArbosMultiConstraintsVersion {
28+
func (ps *L2PricingState) ShouldUseGasConstraints() (bool, error) {
29+
if ps.ArbosVersion >= ArbosMultiConstraintsVersion {
2930
constraintsLength, err := ps.ConstraintsLength()
3031
if err != nil {
3132
return false, err
@@ -35,8 +36,8 @@ func (ps *L2PricingState) ShouldUseMultiConstraints(arbosVersion uint64) (bool,
3536
return false, nil
3637
}
3738

38-
func (ps *L2PricingState) AddToGasPool(gas int64, arbosVersion uint64) error {
39-
shouldUseMultiConstraints, err := ps.ShouldUseMultiConstraints(arbosVersion)
39+
func (ps *L2PricingState) AddToGasPool(gas int64) error {
40+
shouldUseMultiConstraints, err := ps.ShouldUseGasConstraints()
4041
if err != nil {
4142
return err
4243
}
@@ -74,10 +75,32 @@ func (ps *L2PricingState) addToGasPoolMultiConstraints(gas int64) error {
7475
return nil
7576
}
7677

78+
func (ps *L2PricingState) GasPoolUpdateCost() uint64 {
79+
result := storage.StorageReadCost + storage.StorageWriteCost
80+
81+
// Multi-Constraint pricer requires an extra storage read, since ArbOS must load the constraints from state.
82+
// This overhead applies even when no constraints are configured.
83+
if ps.ArbosVersion >= params.ArbosVersion_50 {
84+
result += storage.StorageReadCost // read length for "souldUseGasConstraints"
85+
}
86+
87+
if ps.ArbosVersion >= params.ArbosVersion_MultiConstraintFix {
88+
// addToGasPoolWithGasConstraints costs (ArbOS 51 and later)
89+
constraintsLength, _ := ps.constraints.Length()
90+
if constraintsLength > 0 {
91+
result += storage.StorageReadCost // read length to traverse
92+
// updating (read+write) all constraints, first one was already accounted for
93+
result += uint64(constraintsLength-1) * (storage.StorageReadCost + storage.StorageWriteCost)
94+
}
95+
}
96+
97+
return result
98+
}
99+
77100
// UpdatePricingModel updates the pricing model with info from the last block
78-
func (ps *L2PricingState) UpdatePricingModel(timePassed uint64, arbosVersion uint64) {
79-
shouldUseMultiConstraints, _ := ps.ShouldUseMultiConstraints(arbosVersion)
80-
if shouldUseMultiConstraints {
101+
func (ps *L2PricingState) UpdatePricingModel(timePassed uint64) {
102+
shouldUseGasConstraints, _ := ps.ShouldUseGasConstraints()
103+
if shouldUseGasConstraints {
81104
ps.updatePricingModelMultiConstraints(timePassed)
82105
} else {
83106
ps.updatePricingModelLegacy(timePassed)

arbos/tx_processor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ func (p *TxProcessor) EndTxHook(gasLeft uint64, success bool) {
632632
}
633633
}
634634
// we've already credited the network fee account, but we didn't charge the gas pool yet
635-
p.state.Restrict(p.state.L2PricingState().AddToGasPool(-arbmath.SaturatingCast[int64](gasUsed), p.state.ArbOSVersion()))
635+
p.state.Restrict(p.state.L2PricingState().AddToGasPool(-arbmath.SaturatingCast[int64](gasUsed)))
636636
return
637637
}
638638

@@ -695,7 +695,7 @@ func (p *TxProcessor) EndTxHook(gasLeft uint64, success bool) {
695695
log.Error("total gas used < poster gas component", "gasUsed", gasUsed, "posterGas", p.posterGas)
696696
computeGas = gasUsed
697697
}
698-
p.state.Restrict(p.state.L2PricingState().AddToGasPool(-arbmath.SaturatingCast[int64](computeGas), p.state.ArbOSVersion()))
698+
p.state.Restrict(p.state.L2PricingState().AddToGasPool(-arbmath.SaturatingCast[int64](computeGas)))
699699
}
700700
}
701701

cmd/chaininfo/arbitrum_chain_info.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
"EnableArbOS": true,
174174
"AllowDebugPrecompiles": true,
175175
"DataAvailabilityCommittee": false,
176-
"InitialArbOSVersion": 50,
176+
"InitialArbOSVersion": 51,
177177
"InitialChainOwner": "0x0000000000000000000000000000000000000000",
178178
"GenesisBlockNum": 0
179179
}

contracts-local/src/mocks/Simple.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ contract Simple {
6464
) external payable {
6565
for (uint256 i = 0; i < ticketIds.length; i++) {
6666
// Attempt to redeem each retryable ticket
67-
try ArbRetryableTx(address(110)).redeem{gas: 100000}(ticketIds[i]) {
67+
try ArbRetryableTx(address(110)).redeem{gas: 200000}(ticketIds[i]) {
6868
// Ticket redeemed successfully
6969
counter++;
7070
} catch {

go-ethereum

precompiles/ArbOwner.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,13 @@ func (con ArbOwner) SetGasPricingConstraints(c ctx, evm mech, constraints [][3]u
466466
return fmt.Errorf("failed to clear existing constraints: %w", err)
467467
}
468468

469+
if c.State.ArbOSVersion() >= params.ArbosVersion_MultiConstraintFix {
470+
limit := c.State.L2PricingState().GasConstraintsMaxNum()
471+
if len(constraints) > limit {
472+
return fmt.Errorf("too many constraints. Max: %d", limit)
473+
}
474+
}
475+
469476
for _, constraint := range constraints {
470477
gasTargetPerSecond := constraint[0]
471478
adjustmentWindowSeconds := constraint[1]

0 commit comments

Comments
 (0)