Skip to content

Commit 83e865f

Browse files
Add unit test for resource constraints precompile
1 parent 1f78770 commit 83e865f

File tree

2 files changed

+126
-3
lines changed

2 files changed

+126
-3
lines changed

arbos/constraints/constraints.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type ResourceSet struct {
2323
weights [multigas.NumResourceKind]ResourceWeight
2424
}
2525

26-
const MaxResourceWeight = 1_000_000
26+
const MaxResourceWeight = 1_000_000 // 1e6
2727

2828
// EmptyResourceSet creates a new set with all weights initialized to zero.
2929
func EmptyResourceSet() ResourceSet {
@@ -69,14 +69,18 @@ type ResourceConstraint struct {
6969
// AddToBacklog increases the constraint backlog given the multi-dimensional gas used multiplied by their weights.
7070
func (c *ResourceConstraint) AddToBacklog(gasUsed multigas.MultiGas) {
7171
for resource, weight := range c.Resources.All() {
72-
weightedGas := gasUsed.Get(resource) * uint64(weight)
72+
if weight == 0 {
73+
continue
74+
}
75+
weightedGas := arbmath.SaturatingUMul(gasUsed.Get(resource), uint64(weight))
7376
c.Backlog = arbmath.SaturatingUAdd(c.Backlog, weightedGas)
7477
}
7578
}
7679

7780
// RemoveFromBacklog decreases the backlog by its target given the amount of time passed.
7881
func (c *ResourceConstraint) RemoveFromBacklog(timeElapsed uint64) {
79-
c.Backlog = arbmath.SaturatingUSub(c.Backlog, timeElapsed*c.TargetPerSec)
82+
amount := arbmath.SaturatingUMul(timeElapsed, c.TargetPerSec)
83+
c.Backlog = arbmath.SaturatingUSub(c.Backlog, amount)
8084
}
8185

8286
// constraintKey identifies a resource constraint. There can be only one constraint given the
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2025, Offchain Labs, Inc.
2+
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE.md
3+
4+
package precompiles
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/require"
10+
11+
"github.com/ethereum/go-ethereum/arbitrum/multigas"
12+
"github.com/ethereum/go-ethereum/common"
13+
"github.com/ethereum/go-ethereum/core/types"
14+
"github.com/ethereum/go-ethereum/core/vm"
15+
"github.com/ethereum/go-ethereum/crypto"
16+
17+
"github.com/offchainlabs/nitro/arbos/arbosState"
18+
"github.com/offchainlabs/nitro/arbos/burn"
19+
"github.com/offchainlabs/nitro/arbos/util"
20+
"github.com/offchainlabs/nitro/util/testhelpers"
21+
)
22+
23+
func setupResourceConstraintHandles(
24+
t *testing.T,
25+
) (
26+
*vm.EVM,
27+
*arbosState.ArbosState,
28+
*Context,
29+
*ArbGasInfo,
30+
*ArbOwner,
31+
) {
32+
evm := newMockEVMForTesting()
33+
caller := common.BytesToAddress(crypto.Keccak256([]byte{})[:20])
34+
tracer := util.NewTracingInfo(evm, testhelpers.RandomAddress(), types.ArbosAddress, util.TracingDuringEVM)
35+
state, err := arbosState.OpenArbosState(evm.StateDB, burn.NewSystemBurner(tracer, false))
36+
Require(t, err)
37+
38+
arbGasInfo := &ArbGasInfo{}
39+
arbOwner := &ArbOwner{}
40+
41+
callCtx := testContext(caller, evm)
42+
43+
return evm, state, callCtx, arbGasInfo, arbOwner
44+
}
45+
46+
func TestStorageResourceConstraintsManagment(t *testing.T) {
47+
t.Parallel()
48+
49+
evm, _, callCtx, arbGasInfo, arbOwner := setupResourceConstraintHandles(t)
50+
51+
// Expect error when setting empty resource constraints
52+
err := arbOwner.SetResourceConstraint(callCtx, evm, []resourceWeight{}, 0, 0)
53+
require.Error(t, err)
54+
55+
// Expect error when setting resource constraint with invalid weight
56+
err = arbOwner.SetResourceConstraint(callCtx, evm, []resourceWeight{
57+
{ResourceKind: multigas.ResourceKindComputation, Weight: 0},
58+
}, 0, 0)
59+
require.Error(t, err)
60+
61+
// Expect error when setting resource constraint with duplicate resource kinds
62+
err = arbOwner.SetResourceConstraint(callCtx, evm, []resourceWeight{
63+
{ResourceKind: multigas.ResourceKindComputation, Weight: 1},
64+
{ResourceKind: multigas.ResourceKindComputation, Weight: 2},
65+
}, 0, 0)
66+
require.Error(t, err)
67+
68+
// Check that no resource constraints are set initially
69+
rcs, err := arbGasInfo.ListResourceConstraints(callCtx, evm)
70+
require.NoError(t, err)
71+
require.Empty(t, rcs)
72+
73+
// Set a valid resource constraint
74+
rc1 := []resourceWeight{
75+
{ResourceKind: multigas.ResourceKindComputation, Weight: 1},
76+
{ResourceKind: multigas.ResourceKindStorageAccess, Weight: 2},
77+
}
78+
err = arbOwner.SetResourceConstraint(callCtx, evm, rc1, 12, 10_000_000)
79+
require.NoError(t, err)
80+
81+
// Verify the resource constraint was set
82+
rcs, err = arbGasInfo.ListResourceConstraints(callCtx, evm)
83+
require.NoError(t, err)
84+
require.Len(t, rcs, 1)
85+
require.Equal(t, uint32(12), rcs[0].PeriodSecs)
86+
require.Equal(t, uint64(10_000_000), rcs[0].TargetPerSec)
87+
require.Len(t, rcs[0].ResourceWeight, 2)
88+
require.Contains(t, rcs[0].ResourceWeight, resourceWeight{ResourceKind: multigas.ResourceKindComputation, Weight: 1})
89+
require.Contains(t, rcs[0].ResourceWeight, resourceWeight{ResourceKind: multigas.ResourceKindStorageAccess, Weight: 2})
90+
91+
// Set another valid resource constraint
92+
rc2 := []resourceWeight{
93+
{ResourceKind: multigas.ResourceKindStorageGrowth, Weight: 5},
94+
}
95+
err = arbOwner.SetResourceConstraint(callCtx, evm, rc2, 60, 50_000_000)
96+
require.NoError(t, err)
97+
98+
// Verify both resource constraints are set
99+
rcs, err = arbGasInfo.ListResourceConstraints(callCtx, evm)
100+
require.NoError(t, err)
101+
require.Len(t, rcs, 2)
102+
103+
// Remove the first resource constraint
104+
err = arbOwner.ClearConstraint(callCtx, evm, rc1, 12)
105+
require.NoError(t, err)
106+
107+
// Reset the second resource constraint with new values
108+
err = arbOwner.SetResourceConstraint(callCtx, evm, rc2, 60, 20_000_000)
109+
require.NoError(t, err)
110+
111+
// Verify only the updated second resource constraint remains
112+
rcs, err = arbGasInfo.ListResourceConstraints(callCtx, evm)
113+
require.NoError(t, err)
114+
require.Len(t, rcs, 1)
115+
require.Equal(t, uint32(60), rcs[0].PeriodSecs)
116+
require.Equal(t, uint64(20_000_000), rcs[0].TargetPerSec)
117+
require.Len(t, rcs[0].ResourceWeight, 1)
118+
require.Contains(t, rcs[0].ResourceWeight, resourceWeight{ResourceKind: multigas.ResourceKindStorageGrowth, Weight: 5})
119+
}

0 commit comments

Comments
 (0)