Skip to content

Commit 2bc088b

Browse files
Improve retryable tests and return back GasConstraintsMaxNum
1 parent 44494b0 commit 2bc088b

File tree

4 files changed

+79
-25
lines changed

4 files changed

+79
-25
lines changed

arbos/l2pricing/l2pricing.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ var multigasConstraintsKey []byte = []byte{1}
4646

4747
const GethBlockGasLimit = 1 << 50
4848

49+
// Number of single-gas constraints limited because of retryable redeem gas cost calculation.
50+
// The limit is ignored starting from ArbOS version 60.
51+
const GasConstraintsMaxNum = 20
52+
4953
// MaxPricingExponentBips caps the basefee growth: exp(8.5) ~= x5,000 min base fee.
5054
const MaxPricingExponentBips = arbmath.Bips(85_000)
5155

precompiles/ArbOwner.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,13 @@ func (con ArbOwner) SetGasBacklog(c ctx, evm mech, backlog uint64) error {
462462

463463
// SetGasPricingConstraints sets the gas pricing constraints used by the multi-constraint pricing model
464464
func (con ArbOwner) SetGasPricingConstraints(c ctx, evm mech, constraints [][3]uint64) error {
465+
if c.State.ArbOSVersion() < params.ArbosVersion_60 {
466+
limit := l2pricing.GasConstraintsMaxNum
467+
if len(constraints) > limit {
468+
return fmt.Errorf("too many constraints. Max: %d", limit)
469+
}
470+
}
471+
465472
err := c.State.L2PricingState().ClearGasConstraints()
466473
if err != nil {
467474
return fmt.Errorf("failed to clear existing constraints: %w", err)

precompiles/ArbRetryableTx.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,17 @@ func (con ArbRetryableTx) Redeem(c ctx, evm mech, ticketId bytes32) (bytes32, er
100100
gasCostToReturnResult := params.CopyGas
101101

102102
// `redeem` must prepay the gas needed by the trailing call to
103-
// L2PricingState().AddToGasPool(). BacklogUpdateCost() returns
104-
// that amount based on the storage read/write mix used by AddToGasPool().
105-
gasPoolUpdateCost := uint64(0)
103+
// L2PricingState().ShrinkBacklog(). BacklogUpdateCost() returns
104+
// that amount based on the storage read/write mix used by ShrinkBacklog().
105+
backlogUpdateCost := uint64(0)
106106
if c.State.L2PricingState().ArbosVersion >= params.ArbosVersion_60 {
107107
// Charge static price for any pricer starting from ArbOS 60
108-
gasPoolUpdateCost = l2pricing.ArbOS60StaticBacklogUpdateCost
108+
backlogUpdateCost = l2pricing.ArbOS60StaticBacklogUpdateCost
109109
} else {
110-
gasPoolUpdateCost = c.State.L2PricingState().BacklogUpdateCost()
110+
backlogUpdateCost = c.State.L2PricingState().BacklogUpdateCost()
111111
}
112112

113-
futureGasCosts := eventCost + gasCostToReturnResult + gasPoolUpdateCost
113+
futureGasCosts := eventCost + gasCostToReturnResult + backlogUpdateCost
114114
if c.GasLeft() < futureGasCosts {
115115
return hash{}, c.Burn(multigas.ResourceKindComputation, futureGasCosts) // this will error
116116
}
@@ -139,7 +139,7 @@ func (con ArbRetryableTx) Redeem(c ctx, evm mech, ticketId bytes32) (bytes32, er
139139

140140
// Add the gasToDonate back to the gas pool: the retryable attempt will then consume it.
141141
// This ensures that the gas pool has enough gas to run the retryable attempt.
142-
// Starting from ArbOS 60, we don't charge gas for the AddToGasPool call here
142+
// Starting from ArbOS 60, we don't charge gas for the ShrinkBacklog call here
143143
if c.State.L2PricingState().ArbosVersion >= params.ArbosVersion_60 {
144144
err = c.WithUnmeteredGasAccounting(func() error {
145145
return c.State.L2PricingState().ShrinkBacklog(gasToDonate, multigas.ComputationGas(gasToDonate))

precompiles/ArbRetryableTx_test.go

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/ethereum/go-ethereum/common"
1212
"github.com/ethereum/go-ethereum/core"
1313
"github.com/ethereum/go-ethereum/core/vm"
14+
"github.com/ethereum/go-ethereum/params"
1415

1516
"github.com/offchainlabs/nitro/arbos"
1617
"github.com/offchainlabs/nitro/arbos/burn"
@@ -102,7 +103,15 @@ func testRetryableRedeem(t *testing.T, evm *vm.EVM, precompileCtx *Context) {
102103
}
103104
}
104105

105-
func TestRetryableRedeem(t *testing.T) {
106+
func overrideStateArbOSVersion(evm *vm.EVM, arbosVersion uint64) error {
107+
versionSlot := uint64(0)
108+
version := new(big.Int).SetUint64(arbosVersion)
109+
burner := burn.NewSystemBurner(nil, false)
110+
sto := storage.NewGeth(evm.StateDB, burner)
111+
return sto.SetByUint64(versionSlot, common.BigToHash(version))
112+
}
113+
114+
func TestRetryableRedeemLegacy(t *testing.T) {
106115
evm := newMockEVMForTesting()
107116
precompileCtx := testContext(common.Address{}, evm)
108117

@@ -116,19 +125,33 @@ func TestRetryableRedeem(t *testing.T) {
116125
testRetryableRedeem(t, evm, precompileCtx)
117126
}
118127

119-
func TestRetryableRedeemWithSingleGasConstraints(t *testing.T) {
128+
func TestRetryableRedeemLegacyArbOS60(t *testing.T) {
120129
evm := newMockEVMForTesting()
130+
err := overrideStateArbOSVersion(evm, params.ArbosVersion_60)
131+
Require(t, err)
132+
121133
precompileCtx := testContext(common.Address{}, evm)
122134

123-
for i := range 20 {
124-
// #nosec G115
125-
target0 := uint64((i + 1) * 1000000)
126-
// #nosec G115
127-
window0 := uint64((i + 1) * 10)
128-
// #nosec G115
129-
backlog0 := uint64((i + 1) * 500000)
135+
model, err := precompileCtx.State.L2PricingState().GasModelToUse()
136+
Require(t, err)
130137

131-
err := precompileCtx.State.L2PricingState().AddGasConstraint(target0, window0, backlog0)
138+
if model != l2pricing.GasModelLegacy {
139+
Fail(t, "should use legacy model")
140+
}
141+
142+
testRetryableRedeem(t, evm, precompileCtx)
143+
}
144+
145+
func TestRetryableRedeemWithGasConstraints(t *testing.T) {
146+
evm := newMockEVMForTesting()
147+
precompileCtx := testContext(common.Address{}, evm)
148+
149+
for i := range uint64(l2pricing.GasConstraintsMaxNum) {
150+
target := (i + 1) * 1000000
151+
window := (i + 1) * 10
152+
backlog := (i + 1) * 500000
153+
154+
err := precompileCtx.State.L2PricingState().AddGasConstraint(target, window, backlog)
132155
Require(t, err)
133156
}
134157

@@ -142,19 +165,39 @@ func TestRetryableRedeemWithSingleGasConstraints(t *testing.T) {
142165
testRetryableRedeem(t, evm, precompileCtx)
143166
}
144167

145-
func TestRetryableRedeemWithMultiGasConstraints(t *testing.T) {
168+
func TestRetryableRedeemWithGasConstraintsArbOS60(t *testing.T) {
146169
evm := newMockEVMForTesting()
170+
err := overrideStateArbOSVersion(evm, params.ArbosVersion_60)
171+
Require(t, err)
172+
147173
precompileCtx := testContext(common.Address{}, evm)
148-
precompileCtx.State.L2PricingState().ArbosVersion = l2pricing.ArbosMultiGasConstraintsVersion
149174

150-
// Override default ArbOS varsion in the database
151-
versionSlot := uint64(0)
152-
version := new(big.Int).SetUint64(l2pricing.ArbosMultiGasConstraintsVersion)
153-
burner := burn.NewSystemBurner(nil, false)
154-
sto := storage.NewGeth(evm.StateDB, burner)
155-
err := sto.SetByUint64(versionSlot, common.BigToHash(version))
175+
for i := range uint64(100) {
176+
target := (i + 1) * 1000000
177+
window := (i + 1) * 10
178+
backlog := (i + 1) * 500000
179+
180+
err := precompileCtx.State.L2PricingState().AddGasConstraint(target, window, backlog)
181+
Require(t, err)
182+
}
183+
184+
model, err := precompileCtx.State.L2PricingState().GasModelToUse()
156185
Require(t, err)
157186

187+
if model != l2pricing.GasModelSingleGasConstraints {
188+
Fail(t, "should use single-gas constraints model")
189+
}
190+
191+
testRetryableRedeem(t, evm, precompileCtx)
192+
}
193+
194+
func TestRetryableRedeemWithMultiGasConstraints(t *testing.T) {
195+
evm := newMockEVMForTesting()
196+
err := overrideStateArbOSVersion(evm, l2pricing.ArbosMultiGasConstraintsVersion)
197+
Require(t, err)
198+
199+
precompileCtx := testContext(common.Address{}, evm)
200+
158201
for i := range 100 {
159202
// #nosec G115
160203
target := uint64((i + 1) * 1000000)

0 commit comments

Comments
 (0)