-
Notifications
You must be signed in to change notification settings - Fork 857
Add ACP-224 Fee Manager Precompile #4872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 59 commits
a620a92
f9588d3
fcf11e7
c103b0f
bc3cf91
0b0f4ba
7f1e2db
ba6971d
ba9166f
fe02d3d
ab3cb77
9519ce0
b4138c6
786ade2
320adb2
680e6f2
add6e93
a0138f6
3d440a2
1fae150
317ca7f
446203c
24a7788
734067a
a56e576
cfac83d
1e0b887
4721e0d
9eaaf02
83763bc
316f2e8
c6d91d2
a27af0f
b7c27a5
4e08c51
49691d4
d469314
de42e5d
bf26095
14de17d
1ad2df6
ecad503
dc3a8e1
816351e
79cd64e
23c83fa
4a0d14f
095aa9b
fb88e4d
bf97714
da32c31
5293c45
13bd5a4
01cd7ce
a7d2595
428e5a3
b6c0ada
99067b2
eda0e76
4f3b020
c2d66e0
3eb9e0c
a4e1ab9
42faaff
c323071
c135ec5
2ac9012
2e3d644
d089ed2
d465d46
2a9bd38
d0dbc94
e30a9ed
6fd3b7f
2b7770a
4142b2f
78d2129
09c8d2b
abbdb71
b074422
9d11237
ccd5efb
fd16177
886df70
906252a
5e99002
6d21d50
1f262ee
b990bb5
6e293fe
570a4d0
30cf7f9
b32f61d
77b0c6f
7f927ef
e0c6473
2f052cb
f2bdf43
dd1ad0f
5a8a0e4
414fd7a
e07e7d1
497500a
d5156f4
aa8c530
c2911ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // Copyright (C) 2019, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package commontype | ||
|
|
||
| import ( | ||
| "encoding/binary" | ||
| "errors" | ||
|
|
||
| "github.com/ava-labs/libevm/common" | ||
| ) | ||
|
|
||
| const MinTargetGasACP224 uint64 = 1_000_000 | ||
|
|
||
| // DefaultACP224FeeConfig returns a copy of the default ACP-224 fee | ||
| // config. | ||
| // | ||
| // The default values are: | ||
| // - TargetGas: 1_000_000 | ||
| // - MinGasPrice: 1 | ||
| // - TimeToDouble: 60 | ||
| func DefaultACP224FeeConfig() ACP224FeeConfig { | ||
| return ACP224FeeConfig{ | ||
| TargetGas: 1_000_000, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 60, | ||
| } | ||
| } | ||
|
|
||
| var ( | ||
| ErrMinGasPriceTooLow = errors.New("minGasPrice must be greater than 0") | ||
|
|
||
| errTargetGasMustBeZero = errors.New("targetGas must be 0 when validatorTargetGas is true") | ||
| errTargetGasTooLowACP224 = errors.New("targetGas must be at least MinTargetGasACP224") | ||
| errTimeToDoubleTooLow = errors.New("timeToDouble must be greater than 0") | ||
| errTimeToDoubleMustBeZero = errors.New("timeToDouble must be 0 when staticPricing is true") | ||
| ) | ||
|
|
||
| // ACP224FeeConfig specifies the parameters for the ACP-224 dynamic gas limit mechanism. | ||
| // See [ACP224FeeConfig.Verify] for validation constraints between fields. | ||
| type ACP224FeeConfig struct { | ||
|
alarso16 marked this conversation as resolved.
Outdated
|
||
| ValidatorTargetGas bool `json:"validatorTargetGas,omitempty"` // when true, validators control targetGas via node preferences | ||
|
JonathanOppenheimer marked this conversation as resolved.
Outdated
|
||
| TargetGas uint64 `json:"targetGas"` // target gas consumption per second | ||
| StaticPricing bool `json:"staticPricing,omitempty"` // when true, gas price is always minGasPrice | ||
|
alarso16 marked this conversation as resolved.
Outdated
|
||
| MinGasPrice uint64 `json:"minGasPrice"` // minimum gas price in wei | ||
| TimeToDouble uint64 `json:"timeToDouble"` // seconds for gas price to double at max capacity | ||
| } | ||
|
|
||
| // Verify returns an error if the config violates any field constraints. | ||
| func (a *ACP224FeeConfig) Verify() error { | ||
| switch { | ||
| case a.MinGasPrice == 0: | ||
| return ErrMinGasPriceTooLow | ||
| case a.ValidatorTargetGas && a.TargetGas != 0: | ||
| return errTargetGasMustBeZero | ||
| case !a.ValidatorTargetGas && a.TargetGas < MinTargetGasACP224: | ||
|
alarso16 marked this conversation as resolved.
Outdated
|
||
| return errTargetGasTooLowACP224 | ||
| case a.StaticPricing && a.TimeToDouble != 0: | ||
| return errTimeToDoubleMustBeZero | ||
| case !a.StaticPricing && a.TimeToDouble == 0: | ||
| return errTimeToDoubleTooLow | ||
| default: | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
| // Pack encodes the fee config into a single common.Hash (32 bytes). | ||
| // | ||
| // Layout (26 bytes used, 6 bytes padding): | ||
| // | ||
| // h[0] ValidatorTargetGas (bool) | ||
| // h[1:9] TargetGas (uint64) | ||
| // h[9] StaticPricing (bool) | ||
| // h[10:18] MinGasPrice (uint64) | ||
| // h[18:26] TimeToDouble (uint64) | ||
| func (a *ACP224FeeConfig) Pack() common.Hash { | ||
| var h common.Hash | ||
| put := binary.BigEndian.PutUint64 | ||
|
|
||
| if a.ValidatorTargetGas { | ||
| h[0] = 1 | ||
| } | ||
| put(h[1:], a.TargetGas) | ||
| if a.StaticPricing { | ||
| h[9] = 1 | ||
| } | ||
| put(h[10:], a.MinGasPrice) | ||
| put(h[18:], a.TimeToDouble) | ||
| return h | ||
| } | ||
|
|
||
| // UnpackFrom decodes a packed common.Hash into the fee config fields. | ||
| // See [ACP224FeeConfig.Pack] for the byte layout. | ||
| func (a *ACP224FeeConfig) UnpackFrom(h common.Hash) { | ||
| u64 := binary.BigEndian.Uint64 | ||
|
|
||
| a.ValidatorTargetGas = h[0] != 0 | ||
| a.TargetGas = u64(h[1:]) | ||
| a.StaticPricing = h[9] != 0 | ||
| a.MinGasPrice = u64(h[10:]) | ||
| a.TimeToDouble = u64(h[18:]) | ||
| } | ||
|
|
||
| // Equal returns true if both configs are nil or have identical field values. | ||
| func (a *ACP224FeeConfig) Equal(other *ACP224FeeConfig) bool { | ||
| if a == nil || other == nil { | ||
| return a == other | ||
| } | ||
|
|
||
| return *a == *other | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| // Copyright (C) 2019, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package commontype | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/ava-labs/avalanchego/utils" | ||
| ) | ||
|
|
||
| func TestACP224FeeConfigVerify(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| config ACP224FeeConfig | ||
| want error | ||
| }{ | ||
| { | ||
| name: "valid config", | ||
| config: DefaultACP224FeeConfig(), | ||
| }, | ||
| { | ||
| name: "valid with validatorTargetGas", | ||
| config: ACP224FeeConfig{ | ||
| ValidatorTargetGas: true, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 60, | ||
| }, | ||
| }, | ||
| { | ||
| name: "valid with staticPricing", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224, | ||
| StaticPricing: true, | ||
| MinGasPrice: 1, | ||
| }, | ||
| }, | ||
| { | ||
| name: "valid with both validatorTargetGas and staticPricing", | ||
| config: ACP224FeeConfig{ | ||
| ValidatorTargetGas: true, | ||
| StaticPricing: true, | ||
| MinGasPrice: 1, | ||
| }, | ||
| }, | ||
| { | ||
| name: "minGasPrice zero", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224, | ||
| TimeToDouble: 60, | ||
| }, | ||
| want: ErrMinGasPriceTooLow, | ||
| }, | ||
| { | ||
| name: "targetGas must be zero when validatorTargetGas is true", | ||
| config: ACP224FeeConfig{ | ||
| ValidatorTargetGas: true, | ||
| TargetGas: MinTargetGasACP224, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 60, | ||
| }, | ||
| want: errTargetGasMustBeZero, | ||
| }, | ||
| { | ||
| name: "targetGas below minimum", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224 - 1, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 60, | ||
| }, | ||
| want: errTargetGasTooLowACP224, | ||
| }, | ||
| { | ||
| name: "targetGas at minimum boundary", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 1, | ||
| }, | ||
| }, | ||
| { | ||
| name: "timeToDouble must be zero when staticPricing is true", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224, | ||
| StaticPricing: true, | ||
| MinGasPrice: 1, | ||
| TimeToDouble: 60, | ||
| }, | ||
| want: errTimeToDoubleMustBeZero, | ||
| }, | ||
| { | ||
| name: "timeToDouble must be positive when staticPricing is false", | ||
| config: ACP224FeeConfig{ | ||
| TargetGas: MinTargetGasACP224, | ||
| MinGasPrice: 1, | ||
| }, | ||
| want: errTimeToDoubleTooLow, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| err := tt.config.Verify() | ||
| require.ErrorIs(t, err, tt.want, "Verify") | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func FuzzACP224FeeConfigPacking(f *testing.F) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no directory -- everything is provided via
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then we're not doing any fuzzing at all. Those
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think adding proper fuzz testing for subnet-evm is definitely outside the scope of this PR. I'll just convert this test to a table test unless you object. What do you think?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this test itself is looking good, but we should either run this locally for 5 mins and then add the corpus seeds or setup the fuzz testing in another PR. I think we have employed corpus data approach in strevm so I wonder if we want to do the same here. Could you check this out with avalanchego people to see if we have any preference?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually got rid of the corpus testing with caching and all that with the graft into AvalancheGo, so I'll take the alternative approach.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I reverted my prior change and added it to the fuzz targets (no longer excluded).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm actually not sure why it was excluded in the first place.
ceyonur marked this conversation as resolved.
Outdated
|
||
| for _, v := range []bool{true, false} { | ||
| for _, s := range []bool{true, false} { | ||
| for t := range uint64(3) { | ||
| for m := range uint64(3) { | ||
| for d := range uint64(3) { | ||
| f.Add(v, s, t, m, d) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
JonathanOppenheimer marked this conversation as resolved.
Outdated
|
||
|
|
||
| f.Fuzz(func(t *testing.T, validator, static bool, target, minGas, double uint64) { | ||
| in := &ACP224FeeConfig{validator, target, static, minGas, double} | ||
| got := new(ACP224FeeConfig) | ||
| got.UnpackFrom(in.Pack()) | ||
| require.Equalf(t, *in, *got, "%T.UnpackFrom(%[1]T.Pack()) round trip", in) | ||
|
JonathanOppenheimer marked this conversation as resolved.
|
||
| }) | ||
| } | ||
|
|
||
| func TestACP224FeeConfigEqual(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| a *ACP224FeeConfig | ||
| b *ACP224FeeConfig | ||
| want bool | ||
| }{ | ||
| { | ||
| name: "both equal", | ||
| a: utils.PointerTo(DefaultACP224FeeConfig()), | ||
| b: utils.PointerTo( | ||
| DefaultACP224FeeConfig()), | ||
|
JonathanOppenheimer marked this conversation as resolved.
Outdated
|
||
| want: true, | ||
| }, | ||
| { | ||
| name: "different targetGas", | ||
| a: utils.PointerTo(DefaultACP224FeeConfig()), | ||
| b: func() *ACP224FeeConfig { | ||
| c := DefaultACP224FeeConfig() | ||
| c.TargetGas = 20_000_000 | ||
|
JonathanOppenheimer marked this conversation as resolved.
Outdated
|
||
| return &c | ||
| }(), | ||
| want: false, | ||
| }, | ||
| { | ||
| name: "other nil", | ||
| a: utils.PointerTo(DefaultACP224FeeConfig()), | ||
| b: nil, | ||
| want: false, | ||
| }, | ||
| { | ||
| name: "receiver nil", | ||
| a: nil, | ||
| b: utils.PointerTo(DefaultACP224FeeConfig()), | ||
| want: false, | ||
| }, | ||
| { | ||
| name: "both nil", | ||
| a: nil, | ||
| b: nil, | ||
| want: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| require.Equal(t, tt.want, tt.a.Equal(tt.b), "Equal()") | ||
|
JonathanOppenheimer marked this conversation as resolved.
Outdated
|
||
| }) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
| load("//.bazel:defs.bzl", "graft_go_test") | ||
|
|
||
| go_library( | ||
| name = "acp224feemanager", | ||
| srcs = [ | ||
| "config.go", | ||
| "contract.go", | ||
| "event.go", | ||
| "module.go", | ||
| ], | ||
| embedsrcs = ["IACP224FeeManager.abi"], | ||
| importpath = "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/acp224feemanager", | ||
| visibility = ["//visibility:public"], | ||
| deps = [ | ||
| "//graft/subnet-evm/commontype", | ||
| "//graft/subnet-evm/precompile/allowlist", | ||
| "//graft/subnet-evm/precompile/contract", | ||
| "//graft/subnet-evm/precompile/modules", | ||
| "//graft/subnet-evm/precompile/precompileconfig", | ||
| "@com_github_ava_labs_libevm//accounts/abi", | ||
| "@com_github_ava_labs_libevm//common", | ||
| "@com_github_ava_labs_libevm//core/types", | ||
| "@com_github_ava_labs_libevm//core/vm", | ||
| ], | ||
| ) | ||
|
|
||
| graft_go_test( | ||
| name = "acp224feemanager_test", | ||
| srcs = [ | ||
| "config_test.go", | ||
| "contract_test.go", | ||
| ], | ||
| embed = [":acp224feemanager"], | ||
| deps = [ | ||
| "//graft/subnet-evm/commontype", | ||
| "//graft/subnet-evm/core/extstate", | ||
| "//graft/subnet-evm/precompile/allowlist", | ||
| "//graft/subnet-evm/precompile/allowlist/allowlisttest", | ||
| "//graft/subnet-evm/precompile/contract", | ||
| "//graft/subnet-evm/precompile/precompileconfig", | ||
| "//graft/subnet-evm/precompile/precompiletest", | ||
| "//utils", | ||
| "@com_github_ava_labs_libevm//common", | ||
| "@com_github_ava_labs_libevm//core/vm", | ||
| "@com_github_stretchr_testify//require", | ||
| "@org_uber_go_mock//gomock", | ||
| ], | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.