Skip to content

Commit 8d2838d

Browse files
authored
Make EVM transfer gas configurable (#20)
Implement a gas picker for EVM transfer transaction, configurable to a fixed and random bounded generator.
1 parent bca6c99 commit 8d2838d

14 files changed

Lines changed: 204 additions & 31 deletions

File tree

config/config.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ type AccountConfig struct {
6161

6262
// Scenario represents each scenario in the load configuration.
6363
type Scenario struct {
64-
Name string `json:"name,omitempty"`
65-
Weight int `json:"weight,omitempty"`
66-
Accounts *AccountConfig `json:"accounts,omitempty"`
64+
Name string `json:"name,omitempty"`
65+
Weight int `json:"weight,omitempty"`
66+
Accounts *AccountConfig `json:"accounts,omitempty"`
67+
GasPicker *GasPicker `json:"gasPicker,omitempty"`
68+
GasFeeCapPicker *GasPicker `json:"gasFeeCapPicker,omitempty"`
69+
GasTipCapPicker *GasPicker `json:"gasTipCapPicker,omitempty"`
6770
}

config/gas.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package config
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"math/rand/v2"
7+
)
8+
9+
var (
10+
_ gasGenerator = (*GasPicker)(nil)
11+
_ gasGenerator = (*FixedGasGenerator)(nil)
12+
_ gasGenerator = (*RandomGasGenerator)(nil)
13+
)
14+
15+
type gasGenerator interface {
16+
GenerateGas() (uint64, error)
17+
}
18+
19+
type GasPicker struct {
20+
name string
21+
delegate gasGenerator
22+
}
23+
24+
func (g *GasPicker) Name() string { return g.name }
25+
26+
func (g *GasPicker) GenerateGas() (uint64, error) {
27+
if g.delegate == nil {
28+
return 0, nil
29+
}
30+
return g.delegate.GenerateGas()
31+
}
32+
33+
func (g *GasPicker) UnmarshalJSON(data []byte) error {
34+
var temp struct {
35+
Name string `json:"Name"`
36+
}
37+
if err := json.Unmarshal(data, &temp); err != nil {
38+
return err
39+
}
40+
g.name = temp.Name
41+
switch g.name {
42+
case "":
43+
return nil
44+
case "fixed":
45+
var fixed FixedGasGenerator
46+
if err := json.Unmarshal(data, &fixed); err != nil {
47+
return err
48+
}
49+
g.delegate = &fixed
50+
return nil
51+
case "random":
52+
var random RandomGasGenerator
53+
if err := json.Unmarshal(data, &random); err != nil {
54+
return err
55+
}
56+
g.delegate = &random
57+
return nil
58+
default:
59+
return fmt.Errorf("unknown gas generator name: %s", g.name)
60+
}
61+
}
62+
63+
type FixedGasGenerator struct {
64+
Gas uint64 `json:"Gas"`
65+
}
66+
67+
func (f *FixedGasGenerator) GenerateGas() (uint64, error) {
68+
return f.Gas, nil
69+
}
70+
71+
type RandomGasGenerator struct {
72+
Min uint64 `json:"Min"`
73+
Max uint64 `json:"Max"`
74+
}
75+
76+
func (r *RandomGasGenerator) GenerateGas() (uint64, error) {
77+
if r.Min >= r.Max {
78+
return 0, fmt.Errorf("invalid random gas range: min %d must be less than max %d", r.Min, r.Max)
79+
}
80+
return r.Min + rand.Uint64N(r.Max-r.Min+1), nil
81+
}

config/gas_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package config_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/sei-protocol/sei-load/config"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestGasPicker(t *testing.T) {
11+
t.Parallel()
12+
t.Run("empty", func(t *testing.T) {
13+
var subject config.GasPicker
14+
require.NoError(t, subject.UnmarshalJSON([]byte(`{}`)))
15+
gas, err := subject.GenerateGas()
16+
require.NoError(t, err)
17+
require.Zero(t, gas)
18+
})
19+
t.Run("fixed", func(t *testing.T) {
20+
var subject config.GasPicker
21+
require.NoError(t, subject.UnmarshalJSON([]byte(`{"Name":"fixed","Gas":21000}`)))
22+
gas, err := subject.GenerateGas()
23+
require.NoError(t, err)
24+
require.Equal(t, uint64(21000), gas)
25+
})
26+
t.Run("random", func(t *testing.T) {
27+
var subject config.GasPicker
28+
require.NoError(t, subject.UnmarshalJSON([]byte(`{"Name":"random","Min":20000,"Max":30000}`)))
29+
gas, err := subject.GenerateGas()
30+
require.NoError(t, err)
31+
require.GreaterOrEqual(t, gas, uint64(20000))
32+
require.LessOrEqual(t, gas, uint64(30000))
33+
})
34+
t.Run("unknown", func(t *testing.T) {
35+
var subject config.GasPicker
36+
require.Error(t, subject.UnmarshalJSON([]byte(`{"Name":"unknown"}`)))
37+
})
38+
}

generator/generator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (g *configBasedGenerator) createScenarios() error {
5757

5858
for i, scenarioCfg := range g.config.Scenarios {
5959
// Create scenario instance using factory
60-
scenario := scenarios.CreateScenario(scenarioCfg.Name)
60+
scenario := scenarios.CreateScenario(scenarioCfg)
6161

6262
// Determine account pool to use
6363
var accountPool types.AccountPool

generator/prewarm.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ type PrewarmGenerator struct {
1818
}
1919

2020
// NewPrewarmGenerator creates a new prewarm generator using all account pools from the main generator
21-
func NewPrewarmGenerator(config *config.LoadConfig, mainGenerator Generator) *PrewarmGenerator {
21+
func NewPrewarmGenerator(cfg *config.LoadConfig, mainGenerator Generator) *PrewarmGenerator {
2222
// Get all account pools from the main generator
2323
accountPools := mainGenerator.GetAccountPools()
2424

2525
// Create EVMTransfer scenario for prewarming
26-
evmScenario := scenarios.NewEVMTransferScenario()
26+
evmScenario := scenarios.NewEVMTransferScenario(config.Scenario{})
2727

2828
// Deploy/initialize the scenario (EVMTransfer doesn't need actual deployment)
2929
deployerAccounts := types.GenerateAccounts(1)
3030
deployer := deployerAccounts[0]
31-
evmScenario.Deploy(config, deployer)
31+
evmScenario.Deploy(cfg, deployer)
3232

3333
return &PrewarmGenerator{
3434
accountPools: accountPools,

generator/scenarios/Disperse.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ type DisperseScenario struct {
2121
}
2222

2323
// NewDisperseScenario creates a new Disperse scenario
24-
func NewDisperseScenario() TxGenerator {
24+
func NewDisperseScenario(cfg config.Scenario) TxGenerator {
2525
scenario := &DisperseScenario{}
26-
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.Disperse](scenario)
26+
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.Disperse](scenario, cfg)
2727
scenario.pool = types.NewAccountPool(&types.AccountConfig{
2828
NewAccountRate: 1.0,
2929
})

generator/scenarios/ERC20.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ func (s *ERC20Scenario) Name() string {
2525
}
2626

2727
// NewERC20Scenario creates a new ERC20 scenario
28-
func NewERC20Scenario() TxGenerator {
28+
func NewERC20Scenario(cfg config.Scenario) TxGenerator {
2929
scenario := &ERC20Scenario{}
30-
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20](scenario)
30+
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20](scenario, cfg)
3131
return scenario
3232
}
3333

generator/scenarios/ERC20Conflict.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ type ERC20ConflictScenario struct {
2020
}
2121

2222
// NewERC20ConflictScenario creates a new ERC20Conflict scenario
23-
func NewERC20ConflictScenario() TxGenerator {
23+
func NewERC20ConflictScenario(cfg config.Scenario) TxGenerator {
2424
scenario := &ERC20ConflictScenario{}
25-
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20Conflict](scenario)
25+
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20Conflict](scenario, cfg)
2626
return scenario
2727
}
2828

generator/scenarios/ERC20Noop.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ func (s *ERC20NoopScenario) Name() string {
2525
}
2626

2727
// NewERC20NoopScenario creates a new ERC20Noop scenario
28-
func NewERC20NoopScenario() TxGenerator {
28+
func NewERC20NoopScenario(cfg config.Scenario) TxGenerator {
2929
scenario := &ERC20NoopScenario{}
30-
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20Noop](scenario)
30+
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC20Noop](scenario, cfg)
3131
return scenario
3232
}
3333

generator/scenarios/ERC721.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ type ERC721Scenario struct {
2424
}
2525

2626
// NewERC721Scenario creates a new ERC721 scenario
27-
func NewERC721Scenario() TxGenerator {
27+
func NewERC721Scenario(cfg config.Scenario) TxGenerator {
2828
scenario := &ERC721Scenario{}
29-
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC721](scenario)
29+
scenario.ContractScenarioBase = NewContractScenarioBase[bindings.ERC721](scenario, cfg)
3030
return scenario
3131
}
3232

0 commit comments

Comments
 (0)