diff --git a/arbos/l2pricing/l2pricing.go b/arbos/l2pricing/l2pricing.go index 1a16de5ee64..cbdf7ed7f2d 100644 --- a/arbos/l2pricing/l2pricing.go +++ b/arbos/l2pricing/l2pricing.go @@ -206,12 +206,13 @@ func (ps *L2PricingState) setMultiGasConstraintsFromSingleGasConstraints() error // Transfer to multi-gas constraint with equal weights weights := map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindHistoryGrowth): 1, - uint8(multigas.ResourceKindStorageAccess): 1, - uint8(multigas.ResourceKindStorageGrowth): 1, - uint8(multigas.ResourceKindL2Calldata): 1, - uint8(multigas.ResourceKindWasmComputation): 1, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindHistoryGrowth): 1, + uint8(multigas.ResourceKindStorageAccessRead): 1, + uint8(multigas.ResourceKindStorageAccessWrite): 1, + uint8(multigas.ResourceKindStorageGrowth): 1, + uint8(multigas.ResourceKindL2Calldata): 1, + uint8(multigas.ResourceKindWasmComputation): 1, } var adjustmentWindow uint32 diff --git a/arbos/l2pricing/l2pricing_test.go b/arbos/l2pricing/l2pricing_test.go index 252516727fd..4a419c23272 100644 --- a/arbos/l2pricing/l2pricing_test.go +++ b/arbos/l2pricing/l2pricing_test.go @@ -167,8 +167,8 @@ func TestMultiGasConstraints(t *testing.T) { const n uint64 = 5 for i := range n { weights := map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 10 + i, - uint8(multigas.ResourceKindStorageAccess): 20 + i, + uint8(multigas.ResourceKindComputation): 10 + i, + uint8(multigas.ResourceKindStorageAccessRead): 20 + i, } Require(t, // #nosec G115 @@ -209,8 +209,8 @@ func TestMultiGasConstraints(t *testing.T) { if weights[multigas.ResourceKindComputation] != 10+i { t.Errorf("wrong computation weight: got %v, want %v", weights[multigas.ResourceKindComputation], 10+i) } - if weights[multigas.ResourceKindStorageAccess] != 20+i { - t.Errorf("wrong storage weight: got %v, want %v", weights[multigas.ResourceKindStorageAccess], 20+i) + if weights[multigas.ResourceKindStorageAccessRead] != 20+i { + t.Errorf("wrong storage weight: got %v, want %v", weights[multigas.ResourceKindStorageAccessRead], 20+i) } } @@ -242,7 +242,7 @@ func TestMultiGasConstraintsExponents(t *testing.T) { 20, 200, map[uint8]uint64{ - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindStorageAccessWrite): 2, }, ) Require(t, err) @@ -256,8 +256,8 @@ func TestMultiGasConstraintsExponents(t *testing.T) { } expected = arbmath.Bips(2500) - if exps[multigas.ResourceKindStorageAccess] != expected { - t.Fatalf("wrong exponent: got %v, want %v", exps[multigas.ResourceKindStorageAccess], expected) + if exps[multigas.ResourceKindStorageAccessWrite] != expected { + t.Fatalf("wrong exponent: got %v, want %v", exps[multigas.ResourceKindStorageAccessWrite], expected) } } diff --git a/arbos/l2pricing/model_test.go b/arbos/l2pricing/model_test.go index 20f7408a79e..ca1ec19699f 100644 --- a/arbos/l2pricing/model_test.go +++ b/arbos/l2pricing/model_test.go @@ -139,8 +139,8 @@ func TestCalcMultiGasConstraintsExponents(t *testing.T) { 10, 20000, map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, }, )) Require(t, pricing.AddMultiGasConstraint( @@ -158,7 +158,7 @@ func TestCalcMultiGasConstraintsExponents(t *testing.T) { if got, want := exponents[multigas.ResourceKindComputation], arbmath.Bips(100); got != want { t.Errorf("unexpected computation exponent: got %v, want %v", got, want) } - if got, want := exponents[multigas.ResourceKindStorageAccess], arbmath.Bips(200); got != want { + if got, want := exponents[multigas.ResourceKindStorageAccessRead], arbmath.Bips(200); got != want { t.Errorf("unexpected storage-access exponent: got %v, want %v", got, want) } @@ -170,6 +170,9 @@ func TestCalcMultiGasConstraintsExponents(t *testing.T) { if got := exponents[multigas.ResourceKindHistoryGrowth]; got != 0 { t.Errorf("expected zero history-growth exponent, got %v", got) } + if got := exponents[multigas.ResourceKindStorageAccessWrite]; got != 0 { + t.Errorf("expected zero storage-access-write exponent, got %v", got) + } if got := exponents[multigas.ResourceKindSingleDim]; got != 0 { t.Errorf("expected zero single-dimensional gas exponent, got %v", got) } @@ -189,7 +192,7 @@ func TestMultiDimensionalPriceForRefund(t *testing.T) { multiGas := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 50000}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 15000}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 15000}, ) // #nosec G115 singleGas := big.NewInt(int64(multiGas.SingleGas())) @@ -212,8 +215,8 @@ func TestMultiDimensionalPriceForRefund(t *testing.T) { 10, 20000, map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, }, )) Require(t, pricing.AddMultiGasConstraint( @@ -221,13 +224,13 @@ func TestMultiDimensionalPriceForRefund(t *testing.T) { 5, 15000, map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 2, - uint8(multigas.ResourceKindStorageAccess): 1, + uint8(multigas.ResourceKindComputation): 2, + uint8(multigas.ResourceKindStorageAccessRead): 1, }, )) usedMultiGas := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 500000}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 1500000}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 1500000}, ) err = pricing.GrowBacklog(usedMultiGas.SingleGas(), usedMultiGas) Require(t, err) diff --git a/arbos/l2pricing/multi_gas_constraint_test.go b/arbos/l2pricing/multi_gas_constraint_test.go index c9d1a12c600..59fc28ff22f 100644 --- a/arbos/l2pricing/multi_gas_constraint_test.go +++ b/arbos/l2pricing/multi_gas_constraint_test.go @@ -30,26 +30,26 @@ func TestMultiGasConstraint(t *testing.T) { require.Equal(t, uint64(789), backlog) weightedResources := map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 10, - uint8(multigas.ResourceKindStorageAccess): 20, + uint8(multigas.ResourceKindComputation): 10, + uint8(multigas.ResourceKindStorageAccessRead): 20, } require.NoError(t, c.SetResourceWeights(weightedResources)) w1, _ := c.ResourceWeight(uint8(multigas.ResourceKindComputation)) - w2, _ := c.ResourceWeight(uint8(multigas.ResourceKindStorageAccess)) + w2, _ := c.ResourceWeight(uint8(multigas.ResourceKindStorageAccessRead)) require.Equal(t, uint64(10), w1) require.Equal(t, uint64(20), w2) res, err := c.GetResourceWeights() require.NoError(t, err) require.Equal(t, uint64(10), res[multigas.ResourceKindComputation]) - require.Equal(t, uint64(20), res[multigas.ResourceKindStorageAccess]) + require.Equal(t, uint64(20), res[multigas.ResourceKindStorageAccessRead]) used, err := c.UsedResources() require.NoError(t, err) require.Len(t, used, 2) require.Contains(t, used, multigas.ResourceKindComputation) - require.Contains(t, used, multigas.ResourceKindStorageAccess) + require.Contains(t, used, multigas.ResourceKindStorageAccessRead) maxWeight, err := c.MaxWeight() require.NoError(t, err) @@ -84,8 +84,8 @@ func TestMultiGasConstraintResourceWeightsValidation(t *testing.T) { // valid set valid := map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 3, - uint8(multigas.ResourceKindStorageAccess): 7, + uint8(multigas.ResourceKindComputation): 3, + uint8(multigas.ResourceKindStorageAccessRead): 7, } require.NoError(t, c.SetResourceWeights(valid)) @@ -102,13 +102,13 @@ func TestMultiGasConstraintBacklogAggregation(t *testing.T) { require.NoError(t, c.SetAdjustmentWindow(2)) require.NoError(t, c.SetResourceWeights(map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, })) mg := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 10}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 10}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 10}, ) require.NoError(t, c.GrowBacklog(mg)) @@ -122,13 +122,13 @@ func TestMultiGasConstraintBacklogGrowth(t *testing.T) { require.NoError(t, c.SetAdjustmentWindow(5)) require.NoError(t, c.SetResourceWeights(map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, })) mg1 := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 10}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 10}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 10}, ) require.NoError(t, c.GrowBacklog(mg1)) @@ -139,7 +139,7 @@ func TestMultiGasConstraintBacklogGrowth(t *testing.T) { mg2 := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 5}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 15}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 15}, ) require.NoError(t, c.GrowBacklog(mg2)) @@ -158,14 +158,14 @@ func TestMultiGasConstraintBacklogDecay(t *testing.T) { require.NoError(t, c.SetAdjustmentWindow(5)) require.NoError(t, c.SetResourceWeights(map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, })) // Initial backlog: 1*10 + 2*10 = 30 mgGrow := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 10}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 10}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 10}, ) require.NoError(t, c.GrowBacklog(mgGrow)) @@ -176,7 +176,7 @@ func TestMultiGasConstraintBacklogDecay(t *testing.T) { // First decay: 1*3 + 2*4 = 11 → new backlog = 30 - 11 = 19 mgDecay1 := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 3}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 4}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 4}, ) require.NoError(t, c.ShrinkBacklog(mgDecay1)) @@ -187,7 +187,7 @@ func TestMultiGasConstraintBacklogDecay(t *testing.T) { // Second decay underflows: 1*50 + 2*50 = 150 → should clamp to zero mgDecay2 := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: 50}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 50}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: 50}, ) require.NoError(t, c.ShrinkBacklog(mgDecay2)) diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index d01afc98a64..dc02b60ba6a 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -472,7 +472,7 @@ func fragmentReadGasCost(warm bool, codeSize uint64) (multigas.MultiGas, error) if warm { cost = multigas.ComputationGas(gethParams.WarmStorageReadCostEIP2929) } else { - cost = multigas.StorageAccessGas(gethParams.ColdAccountAccessCostEIP2929) + cost = multigas.StorageAccessReadGas(gethParams.ColdAccountAccessCostEIP2929) } words := ToWordSize(codeSize) copyGas, overflow := gethMath.SafeMul(words, gethParams.CopyGas) @@ -480,7 +480,7 @@ func fragmentReadGasCost(warm bool, codeSize uint64) (multigas.MultiGas, error) log.Trace("fragment copy gas overflow", "codeSize", codeSize, "words", words, "copyGas", gethParams.CopyGas) return multigas.ZeroGas(), vm.ErrGasUintOverflow } - if cost, overflow = cost.SafeIncrement(multigas.ResourceKindStorageAccess, copyGas); overflow { + if cost, overflow = cost.SafeIncrement(multigas.ResourceKindStorageAccessRead, copyGas); overflow { log.Trace("fragment copy gas overflow", "codeSize", codeSize, "copyGas", copyGas) return multigas.ZeroGas(), vm.ErrGasUintOverflow } @@ -621,7 +621,7 @@ func (p Programs) SetProgramCached( } // pay to cache the program, or to re-cache in case of upcoming revert - if err := p.programs.Burner().Burn(multigas.ResourceKindStorageAccess, uint64(program.initCost)); err != nil { + if err := p.programs.Burner().Burn(multigas.ResourceKindStorageAccessRead, uint64(program.initCost)); err != nil { return err } moduleHash, err := p.moduleHashes.Get(codeHash) diff --git a/arbos/storage/storage.go b/arbos/storage/storage.go index 0b440abee3a..e67153928d3 100644 --- a/arbos/storage/storage.go +++ b/arbos/storage/storage.go @@ -137,7 +137,7 @@ func (s *Storage) Account() common.Address { } func (s *Storage) Get(key common.Hash) (common.Hash, error) { - err := s.burner.Burn(multigas.ResourceKindStorageAccess, StorageReadCost) + err := s.burner.Burn(multigas.ResourceKindStorageAccessRead, StorageReadCost) if err != nil { return common.Hash{}, err } @@ -185,7 +185,7 @@ func (s *Storage) Set(key common.Hash, value common.Hash) error { log.Error("Read-only burner attempted to mutate state", "key", key, "value", value) return vm.ErrWriteProtection } - err := s.burner.Burn(multigas.ResourceKindStorageAccess, writeCost(value)) + err := s.burner.Burn(multigas.ResourceKindStorageAccessWrite, writeCost(value)) if err != nil { return err } @@ -334,7 +334,7 @@ func (s *Storage) ClearBytes() error { } func (s *Storage) GetCodeHash(address common.Address) (common.Hash, error) { - err := s.burner.Burn(multigas.ResourceKindStorageAccess, StorageCodeHashCost) + err := s.burner.Burn(multigas.ResourceKindStorageAccessRead, StorageCodeHashCost) if err != nil { return common.Hash{}, err } @@ -395,7 +395,7 @@ func (s *Storage) NewSlot(offset uint64) StorageSlot { } func (ss *StorageSlot) Get() (common.Hash, error) { - err := ss.burner.Burn(multigas.ResourceKindStorageAccess, StorageReadCost) + err := ss.burner.Burn(multigas.ResourceKindStorageAccessRead, StorageReadCost) if err != nil { return common.Hash{}, err } @@ -410,7 +410,7 @@ func (ss *StorageSlot) Set(value common.Hash) error { log.Error("Read-only burner attempted to mutate state", "value", value) return vm.ErrWriteProtection } - err := ss.burner.Burn(multigas.ResourceKindStorageAccess, writeCost(value)) + err := ss.burner.Burn(multigas.ResourceKindStorageAccessWrite, writeCost(value)) if err != nil { return err } diff --git a/arbos/tx_processor_multigas_test.go b/arbos/tx_processor_multigas_test.go index c0639e03f7b..7a6b2645415 100644 --- a/arbos/tx_processor_multigas_test.go +++ b/arbos/tx_processor_multigas_test.go @@ -109,10 +109,10 @@ func TestEndTxHookMultiGasRefundNormalTx(t *testing.T) { gasUsed := gasLimit - gasLeft - // Distribute used gas equally between computation and storage access. + // Distribute used gas equally between computation and storage access read. usedMultiGas := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: gasUsed / 2}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: gasUsed / 2}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: gasUsed / 2}, ) // Set up multi-gas constraints and spin model to produce different multi-dimensional cost. @@ -184,7 +184,7 @@ func TestEndTxHookMultiGasRefundRetryableTx(t *testing.T) { gasUsed := gasLimit - gasLeft usedMultiGas := multigas.MultiGasFromPairs( multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: gasUsed / 2}, - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: gasUsed / 2}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: gasUsed / 2}, ) // Set up multi-gas constraints and spin model to produce a different multi-dimensional cost. diff --git a/changelog/mrogachev-nit-4654.md b/changelog/mrogachev-nit-4654.md new file mode 100644 index 00000000000..3590e0341e4 --- /dev/null +++ b/changelog/mrogachev-nit-4654.md @@ -0,0 +1,2 @@ +### Changed +- Split `ResourceKindStorageAccess` into `ResourceKindStorageAccessRead` and `ResourceKindStorageAccessWrite` for finer-grained multi-dimensional gas metering diff --git a/cmd/l2pricing-simulator/multigas.go b/cmd/l2pricing-simulator/multigas.go index 9bb8320f073..ad1d3282a49 100644 --- a/cmd/l2pricing-simulator/multigas.go +++ b/cmd/l2pricing-simulator/multigas.go @@ -16,8 +16,10 @@ func ParseResourceKind(s string) (multigas.ResourceKind, error) { return multigas.ResourceKindComputation, nil case "HistoryGrowth": return multigas.ResourceKindHistoryGrowth, nil - case "StorageAccess": - return multigas.ResourceKindStorageAccess, nil + case "StorageAccessRead": + return multigas.ResourceKindStorageAccessRead, nil + case "StorageAccessWrite": + return multigas.ResourceKindStorageAccessWrite, nil case "StorageGrowth": return multigas.ResourceKindStorageGrowth, nil case "SingleDim": @@ -91,7 +93,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } @@ -105,7 +108,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } @@ -119,7 +123,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } @@ -133,7 +138,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } @@ -147,7 +153,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } @@ -161,7 +168,8 @@ const DefaultMultiGasConstraints string = `[ "Computation": 1, "WasmComputation": 1, "HistoryGrowth": 1, - "StorageAccess": 1, + "StorageAccessRead": 1, + "StorageAccessWrite": 1, "StorageGrowth": 1, "L2Calldata": 1 } diff --git a/contracts-local/src/mocks/AddressFilterTest.sol b/contracts-local/src/mocks/AddressFilterTest.sol index af5ff7b0163..3d06ebaed59 100644 --- a/contracts-local/src/mocks/AddressFilterTest.sol +++ b/contracts-local/src/mocks/AddressFilterTest.sol @@ -5,7 +5,9 @@ pragma solidity ^0.8.0; interface IArbRetryableTx { - function redeem(bytes32 ticketId) external returns (bytes32); + function redeem( + bytes32 ticketId + ) external returns (bytes32); } /// @notice Test contract for exercising different call opcodes for address filtering tests @@ -105,13 +107,18 @@ contract AddressFilterTest { event UnfilteredEvent(address some); /// @notice Forwards a call to target with arbitrary calldata - function forwardCall(address target, bytes calldata data) external returns (bool success, bytes memory result) { + function forwardCall( + address target, + bytes calldata data + ) external returns (bool success, bytes memory result) { (success, result) = target.call(data); require(success, "forwardCall failed"); } /// @notice Increments dummy counter then chains into a redeem - function incrementDummyThenRedeem(bytes32 ticketId) external returns (bytes32) { + function incrementDummyThenRedeem( + bytes32 ticketId + ) external returns (bytes32) { dummy++; return IArbRetryableTx(address(0x6e)).redeem(ticketId); } diff --git a/docs/decisions/0002-multi-dimensional-gas-metering.md b/docs/decisions/0002-multi-dimensional-gas-metering.md index 685ea7e8187..28e95e0224d 100644 --- a/docs/decisions/0002-multi-dimensional-gas-metering.md +++ b/docs/decisions/0002-multi-dimensional-gas-metering.md @@ -17,14 +17,19 @@ A multi-dimensional gas metering approach is adopted, introducing distinct `Reso - Hashing - Bloom filter updates -- ResourceKindStorageAccess. Represents read access to the global state: - - Account lookups (CALL, EXTCODESIZE, BALANCE) - - Storage slot reads - - Storage slot writes (nonzero → nonzero and nonzero → zero) - - Witness generation for reads (e.g. Verkle/stateless mode) - - Access list updates (EIP-2929/2930) - - Verkle proof traversal - - Target address resolution (DELEGATECALL, STATICCALL) +- ResourceKindStorageAccessRead. Represents read access to the global state: + - Storage slot reads (SLOAD, SSTORE cold slot load) + - Account lookups (BALANCE, EXTCODESIZE, EXTCODEHASH, EXTCODECOPY) + - CALL/DELEGATECALL/STATICCALL cold account access and target resolution + - SELFDESTRUCT cold beneficiary access + - Access list intrinsic gas (EIP-2929/2930) + - Verkle/EIP-4762 witness reads and code chunk reads + - WASM state loads and cold access + +- ResourceKindStorageAccessWrite. Represents write access to the global state: + - SSTORE write costs (EIP-2200, EIP-1283, Verkle, WASM) + - SELFDESTRUCT base cost (EIP-150) and deletion + - Verkle/EIP-4762 witness writes and value transfers - ResourceKindStorageGrowth. Includes operations that increase the persistent state size: - New account creation diff --git a/go-ethereum b/go-ethereum index a4edc802e04..2af9c1f710c 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit a4edc802e0497eab31cde74e1a8f3c27ae201f2b +Subproject commit 2af9c1f710c0d637b1cd902b4056e24853c42dc5 diff --git a/precompiles/ArbGasInfo_test.go b/precompiles/ArbGasInfo_test.go index 49386549f87..ea2a8eff41b 100644 --- a/precompiles/ArbGasInfo_test.go +++ b/precompiles/ArbGasInfo_test.go @@ -150,8 +150,9 @@ func TestGetMultiGasPricingConstraintsOrder(t *testing.T) { Require(t, state.L2PricingState().AddMultiGasConstraint( 20_000_000, 10, 100_000, map[uint8]uint64{ - uint8(multigas.ResourceKindStorageAccess): 3, - uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 3, + uint8(multigas.ResourceKindStorageAccessWrite): 5, + uint8(multigas.ResourceKindComputation): 1, }, )) diff --git a/precompiles/ArbInfo.go b/precompiles/ArbInfo.go index 100913fb977..e8f4aac22b1 100644 --- a/precompiles/ArbInfo.go +++ b/precompiles/ArbInfo.go @@ -25,12 +25,12 @@ func (con ArbInfo) GetBalance(c ctx, evm mech, account addr) (huge, error) { // GetCode retrieves a contract's deployed code func (con ArbInfo) GetCode(c ctx, evm mech, account addr) ([]byte, error) { - if err := c.Burn(multigas.ResourceKindStorageAccess, params.ColdSloadCostEIP2929); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessRead, params.ColdSloadCostEIP2929); err != nil { return nil, err } code := evm.StateDB.GetCode(account) words := arbmath.WordsForBytes(uint64(len(code))) - if err := c.Burn(multigas.ResourceKindStorageAccess, params.CopyGas*words); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessRead, params.CopyGas*words); err != nil { return nil, err } return code, nil diff --git a/precompiles/ArbNativeTokenManager.go b/precompiles/ArbNativeTokenManager.go index f0a165dfd28..f20af7043c0 100644 --- a/precompiles/ArbNativeTokenManager.go +++ b/precompiles/ArbNativeTokenManager.go @@ -30,7 +30,7 @@ func (con ArbNativeTokenManager) MintNativeToken(c ctx, evm mech, amount huge) e if !con.hasAccess(c) { return c.BurnOut() } - if err := c.Burn(multigas.ResourceKindStorageAccess, mintBurnGasCost); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessWrite, mintBurnGasCost); err != nil { return err } @@ -44,7 +44,7 @@ func (con ArbNativeTokenManager) BurnNativeToken(c ctx, evm mech, amount huge) e if !con.hasAccess(c) { return c.BurnOut() } - if err := c.Burn(multigas.ResourceKindStorageAccess, mintBurnGasCost); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessWrite, mintBurnGasCost); err != nil { return err } diff --git a/precompiles/ArbRetryableTx.go b/precompiles/ArbRetryableTx.go index c9084f0bd2d..28cb115aabe 100644 --- a/precompiles/ArbRetryableTx.go +++ b/precompiles/ArbRetryableTx.go @@ -57,7 +57,7 @@ func (con ArbRetryableTx) Redeem(c ctx, evm mech, ticketId bytes32) (bytes32, er return hash{}, err } writeBytes := arbmath.WordsForBytes(byteCount) - if err := c.Burn(multigas.ResourceKindStorageAccess, params.SloadGas*writeBytes); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessWrite, params.SloadGas*writeBytes); err != nil { return hash{}, err } @@ -192,7 +192,7 @@ func (con ArbRetryableTx) Keepalive(c ctx, evm mech, ticketId bytes32) (huge, er return nil, con.oldNotFoundError(c) } updateCost := arbmath.WordsForBytes(nbytes) * params.SstoreSetGas / 100 - if err := c.Burn(multigas.ResourceKindStorageAccess, updateCost); err != nil { + if err := c.Burn(multigas.ResourceKindStorageAccessWrite, updateCost); err != nil { return big.NewInt(0), err } diff --git a/precompiles/ArbRetryableTx_test.go b/precompiles/ArbRetryableTx_test.go index cae65f39d64..f10494ccd36 100644 --- a/precompiles/ArbRetryableTx_test.go +++ b/precompiles/ArbRetryableTx_test.go @@ -198,12 +198,13 @@ func TestRetryableRedeemWithMultiGasConstraints(t *testing.T) { backlog := uint64((i + 1) * 500000) weights := map[uint8]uint64{ - uint8(multigas.ResourceKindComputation): 1, - uint8(multigas.ResourceKindStorageAccess): 2, - uint8(multigas.ResourceKindStorageGrowth): 3, - uint8(multigas.ResourceKindSingleDim): 4, - uint8(multigas.ResourceKindL2Calldata): 5, - uint8(multigas.ResourceKindWasmComputation): 6, + uint8(multigas.ResourceKindComputation): 1, + uint8(multigas.ResourceKindStorageAccessRead): 2, + uint8(multigas.ResourceKindStorageAccessWrite): 3, + uint8(multigas.ResourceKindStorageGrowth): 4, + uint8(multigas.ResourceKindSingleDim): 5, + uint8(multigas.ResourceKindL2Calldata): 6, + uint8(multigas.ResourceKindWasmComputation): 7, } err := precompileCtx.State.L2PricingState().AddMultiGasConstraint(target, window, backlog, weights) diff --git a/precompiles/constraints_test.go b/precompiles/constraints_test.go index a0f17a0b31c..a52d938d192 100644 --- a/precompiles/constraints_test.go +++ b/precompiles/constraints_test.go @@ -216,7 +216,7 @@ func TestEnableAndDisableMultiConstraints(t *testing.T) { { Resources: []WeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 5}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 7}, + {Resource: uint8(multigas.ResourceKindStorageAccessRead), Weight: 7}, }, AdjustmentWindowSecs: 12, TargetPerSec: 7_000_000, @@ -258,7 +258,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { { Resources: []WeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 1}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 2}, + {Resource: uint8(multigas.ResourceKindStorageAccessRead), Weight: 2}, }, AdjustmentWindowSecs: 1, TargetPerSec: 30_000_000, @@ -267,7 +267,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { { Resources: []WeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 2}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 3}, + {Resource: uint8(multigas.ResourceKindStorageAccessRead), Weight: 3}, }, AdjustmentWindowSecs: 102, TargetPerSec: 15_000_000, @@ -299,7 +299,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { resMap, err := first.GetResourceWeights() require.NoError(t, err) require.Equal(t, uint64(1), resMap[multigas.ResourceKindComputation]) - require.Equal(t, uint64(2), resMap[multigas.ResourceKindStorageAccess]) + require.Equal(t, uint64(2), resMap[multigas.ResourceKindStorageAccessRead]) // Second constraint target, err = second.Target() @@ -315,7 +315,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { resMap, err = second.GetResourceWeights() require.NoError(t, err) require.Equal(t, uint64(2), resMap[multigas.ResourceKindComputation]) - require.Equal(t, uint64(3), resMap[multigas.ResourceKindStorageAccess]) + require.Equal(t, uint64(3), resMap[multigas.ResourceKindStorageAccessRead]) // Verify via getter precompile results, err := arbGasInfo.GetMultiGasPricingConstraints(callCtx, evm) @@ -337,7 +337,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { { Resources: []WeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 5}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 7}, + {Resource: uint8(multigas.ResourceKindStorageAccessRead), Weight: 7}, }, AdjustmentWindowSecs: 12, TargetPerSec: 7_000_000, @@ -366,7 +366,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { resMap, err = first.GetResourceWeights() require.NoError(t, err) require.Equal(t, uint64(5), resMap[multigas.ResourceKindComputation]) - require.Equal(t, uint64(7), resMap[multigas.ResourceKindStorageAccess]) + require.Equal(t, uint64(7), resMap[multigas.ResourceKindStorageAccessRead]) results, err = arbGasInfo.GetMultiGasPricingConstraints(callCtx, evm) require.NoError(t, err) @@ -381,7 +381,7 @@ func TestMultiGasConstraintsStorage(t *testing.T) { gotWeights[r.Resource] = r.Weight } require.Equal(t, uint64(5), gotWeights[uint8(multigas.ResourceKindComputation)]) - require.Equal(t, uint64(7), gotWeights[uint8(multigas.ResourceKindStorageAccess)]) + require.Equal(t, uint64(7), gotWeights[uint8(multigas.ResourceKindStorageAccessRead)]) } func TestMultiGasConstraintsCantExceedLimit(t *testing.T) { @@ -394,7 +394,7 @@ func TestMultiGasConstraintsCantExceedLimit(t *testing.T) { { Resources: []WeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 1}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 2}, + {Resource: uint8(multigas.ResourceKindStorageAccessWrite), Weight: 2}, }, AdjustmentWindowSecs: 1, TargetPerSec: 30_000_000, diff --git a/precompiles/context_test.go b/precompiles/context_test.go index 43191a96f51..eeb5aef5b73 100644 --- a/precompiles/context_test.go +++ b/precompiles/context_test.go @@ -25,7 +25,7 @@ func TestContextBurn(t *testing.T) { } // Burn 700 storage access - if err := ctx.Burn(multigas.ResourceKindStorageAccess, 700); err != nil { + if err := ctx.Burn(multigas.ResourceKindStorageAccessWrite, 700); err != nil { t.Errorf("unexpected error from burn: %v", err) } if got, want := ctx.GasLeft(), uint64(300); got != want { @@ -58,7 +58,7 @@ func TestContextBurn(t *testing.T) { } // Check the multigas dimensions - if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageAccess), uint64(700); got != want { + if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageAccessWrite), uint64(700); got != want { t.Errorf("wrong storage access: got %v, want %v", got, want) } if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageGrowth), uint64(200); got != want { @@ -82,7 +82,7 @@ func TestContextBurnMultiGas(t *testing.T) { } gasToBurn := multigas.MultiGasFromPairs( - multigas.Pair{Kind: multigas.ResourceKindStorageAccess, Amount: 400}, + multigas.Pair{Kind: multigas.ResourceKindStorageAccessWrite, Amount: 400}, multigas.Pair{Kind: multigas.ResourceKindStorageGrowth, Amount: 200}, ) if err := ctx.BurnMultiGas(gasToBurn); err != nil { @@ -105,7 +105,7 @@ func TestContextBurnMultiGas(t *testing.T) { t.Errorf("wrong gas burned: got %v, want %v", got, want) } - if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageAccess), uint64(400); got != want { + if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageAccessWrite), uint64(400); got != want { t.Errorf("wrong storage access: got %v, want %v", got, want) } if got, want := ctx.gasUsed.Get(multigas.ResourceKindStorageGrowth), uint64(200); got != want { diff --git a/system_tests/filtered_transactions_test.go b/system_tests/filtered_transactions_test.go index 41cf4e9bcf6..63d4e34e86a 100644 --- a/system_tests/filtered_transactions_test.go +++ b/system_tests/filtered_transactions_test.go @@ -263,11 +263,11 @@ func TestFilteredTransactionsManagerFreeOps(t *testing.T) { require.NoError(t, err) receipt, err := builder.L2.EnsureTxSucceeded(tx) require.NoError(t, err) - require.Equal(t, uint64(0), receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess)) + require.Equal(t, uint64(0), receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessWrite)) tx, err = arbFilteredTxs.DeleteFilteredTransaction(&filtererTxOpts, txHash) require.NoError(t, err) receipt, err = builder.L2.EnsureTxSucceeded(tx) require.NoError(t, err) - require.Equal(t, uint64(0), receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess)) + require.Equal(t, uint64(0), receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessWrite)) } diff --git a/system_tests/multi_constraint_pricer_test.go b/system_tests/multi_constraint_pricer_test.go index 049fa0c5b2f..36e52633fce 100644 --- a/system_tests/multi_constraint_pricer_test.go +++ b/system_tests/multi_constraint_pricer_test.go @@ -86,7 +86,7 @@ func TestSetAndGetMultiGasPricingConstraints(t *testing.T) { Resources: []precompilesgen.ArbMultiGasConstraintsTypesWeightedResource{ {Resource: uint8(multigas.ResourceKindComputation), Weight: 3}, {Resource: uint8(multigas.ResourceKindHistoryGrowth), Weight: 2}, - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 1}, + {Resource: uint8(multigas.ResourceKindStorageAccessWrite), Weight: 1}, {Resource: uint8(multigas.ResourceKindStorageGrowth), Weight: 4}, {Resource: uint8(multigas.ResourceKindSingleDim), Weight: 5}, }, @@ -97,7 +97,7 @@ func TestSetAndGetMultiGasPricingConstraints(t *testing.T) { constraint1 := precompilesgen.ArbMultiGasConstraintsTypesResourceConstraint{ Resources: []precompilesgen.ArbMultiGasConstraintsTypesWeightedResource{ - {Resource: uint8(multigas.ResourceKindStorageAccess), Weight: 7}, + {Resource: uint8(multigas.ResourceKindStorageAccessRead), Weight: 7}, {Resource: uint8(multigas.ResourceKindSingleDim), Weight: 9}, {Resource: uint8(multigas.ResourceKindHistoryGrowth), Weight: 11}, }, diff --git a/system_tests/multigas_stylus_program_test.go b/system_tests/multigas_stylus_program_test.go index 41d77f7fe56..ef97af9cd31 100644 --- a/system_tests/multigas_stylus_program_test.go +++ b/system_tests/multigas_stylus_program_test.go @@ -45,7 +45,7 @@ func TestMultigasStylus_GetBytes32(t *testing.T) { receipt, err := EnsureTxSucceeded(ctx, l2client, tx) require.NoError(t, err) - require.Equal(t, params.ColdSloadCostEIP2929-params.WarmStorageReadCostEIP2929, receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess)) + require.Equal(t, params.ColdSloadCostEIP2929-params.WarmStorageReadCostEIP2929, receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessRead)) require.Equal(t, params.TxGas+params.WarmStorageReadCostEIP2929, receipt.MultiGasUsed.Get(multigas.ResourceKindComputation)) require.Equal(t, receipt.GasUsed, receipt.MultiGasUsed.SingleGas()) @@ -114,7 +114,7 @@ func TestMultigasStylus_AccountAccessHostIOs(t *testing.T) { } require.Equal(t, expectedAccess, - receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess), + receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessRead), ) require.Equal(t, expectedCompute, receipt.MultiGasUsed.Get(multigas.ResourceKindComputation), @@ -330,7 +330,7 @@ func TestMultigasStylus_Calls(t *testing.T) { require.Equal(t, expectedStorageAccess, - receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess), + receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessRead), ) }) } @@ -374,7 +374,7 @@ func TestMultigasStylus_StorageWrite(t *testing.T) { // Expected multigas for create slot operation require.Equal(t, receipt.GasUsed, receipt.MultiGasUsed.SingleGas()) - require.Equal(t, params.ColdSloadCostEIP2929, receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccess)) + require.Equal(t, params.ColdSloadCostEIP2929, receipt.MultiGasUsed.Get(multigas.ResourceKindStorageAccessRead)) require.Equal(t, params.SstoreSetGasEIP2200, receipt.MultiGasUsed.Get(multigas.ResourceKindStorageGrowth)) } else { require.Error(t, err)