-
Notifications
You must be signed in to change notification settings - Fork 848
test: add ACP-224 gas price manager simulated backend tests #5220
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
Open
JonathanOppenheimer
wants to merge
100
commits into
master
Choose a base branch
from
JonathanOppenheimer/acp-224-add-bindings-test
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 69 commits
Commits
Show all changes
100 commits
Select commit
Hold shift + click to select a range
a620a92
refactor: use slices for precompile config test tables
JonathanOppenheimer f9588d3
build: add precompile interface and build
JonathanOppenheimer fcf11e7
feat: add acp224 precompile
JonathanOppenheimer c103b0f
fix: collisions and non zero
JonathanOppenheimer bc3cf91
refactor: use new spec
JonathanOppenheimer 0b0f4ba
chore: new test error
JonathanOppenheimer 7f1e2db
chore: unexport errors
JonathanOppenheimer ba6971d
chore: lint
JonathanOppenheimer ba9166f
chore: copilot review comments
JonathanOppenheimer fe02d3d
chore: lint
JonathanOppenheimer ab3cb77
chore: further hardcode address
JonathanOppenheimer 9519ce0
chore: more address
JonathanOppenheimer b4138c6
chore: build bazel
JonathanOppenheimer 786ade2
test: add tests
JonathanOppenheimer 320adb2
chore: bazel
JonathanOppenheimer 680e6f2
fix: remove invalid validation check
JonathanOppenheimer add6e93
Update graft/subnet-evm/commontype/fee_config.go
JonathanOppenheimer a0138f6
refactor: Cey feedback
JonathanOppenheimer 3d440a2
chore: bazel
JonathanOppenheimer 1fae150
chore: lint
JonathanOppenheimer 317ca7f
refactor: tests + copilot feedback
JonathanOppenheimer 446203c
fix: nil
JonathanOppenheimer 24a7788
chore: claude nits
JonathanOppenheimer 734067a
fix: nil fee config
JonathanOppenheimer a56e576
chore: revert
JonathanOppenheimer cfac83d
docs: godoc
JonathanOppenheimer 1e0b887
chore: organize contract.go
JonathanOppenheimer 4721e0d
test: use table
JonathanOppenheimer 9eaaf02
chore: remove duplication verification
JonathanOppenheimer 83763bc
chore: Cey review
JonathanOppenheimer 316f2e8
fix: tests
JonathanOppenheimer c6d91d2
test: don't use init()
JonathanOppenheimer a27af0f
Revert "refactor: use slices for precompile config test tables"
JonathanOppenheimer b7c27a5
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 4e08c51
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 49691d4
chore: Cey review
JonathanOppenheimer d469314
Update graft/subnet-evm/precompile/contracts/acp224feemanager/config.go
JonathanOppenheimer de42e5d
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer bf26095
refactor: fall back to default config
JonathanOppenheimer 14de17d
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 1ad2df6
chore: lint
JonathanOppenheimer ecad503
chore: lint
JonathanOppenheimer dc3a8e1
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 816351e
docs: add uint comment
JonathanOppenheimer 79cd64e
docs: document per uint
JonathanOppenheimer 23c83fa
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 4a0d14f
Update graft/subnet-evm/commontype/acp224_fee_config.go
JonathanOppenheimer 095aa9b
Update graft/subnet-evm/commontype/acp224_fee_config.go
JonathanOppenheimer fb88e4d
Update graft/subnet-evm/commontype/acp224_fee_config.go
JonathanOppenheimer bf97714
chore: Austin review
JonathanOppenheimer da32c31
chore: bazel
JonathanOppenheimer 5293c45
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 13bd5a4
chore: lint
JonathanOppenheimer 01cd7ce
chore: revert one Austin suggestion
JonathanOppenheimer a7d2595
chore: Austin comments
JonathanOppenheimer 428e5a3
fix: nolint
JonathanOppenheimer b6c0ada
Update graft/subnet-evm/precompile/contracts/acp224feemanager/module.go
JonathanOppenheimer 99067b2
chore: Arran feedback
JonathanOppenheimer eda0e76
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 4f3b020
fix: use uint64 directly
JonathanOppenheimer c2d66e0
chore: remove abi bridge code
JonathanOppenheimer 3eb9e0c
chore: un-inline error
JonathanOppenheimer a4e1ab9
docs: precompile comments
JonathanOppenheimer 42faaff
Update graft/subnet-evm/precompile/contracts/acp224feemanager/contrac…
JonathanOppenheimer c323071
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer c135ec5
Merge branch 'JonathanOppenheimer/acp224-add-precompile' of github.co…
JonathanOppenheimer 2ac9012
Update graft/subnet-evm/commontype/acp224_fee_config_test.go
JonathanOppenheimer 2e3d644
Merge branch 'JonathanOppenheimer/acp224-add-precompile' of github.co…
JonathanOppenheimer d089ed2
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer ed56a19
test: add ACP-224 fee manager simulated backend tests
JonathanOppenheimer cc2b7f9
docs: duplication
JonathanOppenheimer d465d46
Update graft/subnet-evm/commontype/acp224_fee_config_test.go
JonathanOppenheimer 2a9bd38
Update graft/subnet-evm/commontype/acp224_fee_config_test.go
JonathanOppenheimer d0dbc94
Update graft/subnet-evm/commontype/acp224_fee_config_test.go
JonathanOppenheimer e30a9ed
Update graft/subnet-evm/precompile/contracts/acp224feemanager/config.go
JonathanOppenheimer 6fd3b7f
chore: Arran review
JonathanOppenheimer 2b7770a
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 4142b2f
chore: fix auto-apply
JonathanOppenheimer 78d2129
fix: ordering + lint
JonathanOppenheimer 09c8d2b
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer abbdb71
style: take 2
JonathanOppenheimer b074422
chore: Cey review
JonathanOppenheimer 9d11237
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer ccd5efb
test: convert fuzz to table test
JonathanOppenheimer fd16177
chore: bazel
JonathanOppenheimer 886df70
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 906252a
chore: lint
JonathanOppenheimer 5e99002
test: properly fuzz graft targets
JonathanOppenheimer 6d21d50
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 1f262ee
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer b990bb5
test: add fuzz corpora
JonathanOppenheimer 4285c45
Merge branch 'JonathanOppenheimer/acp224-add-precompile' into Jonatha…
JonathanOppenheimer 0d0c2e8
refactor: use a test contract
JonathanOppenheimer f8cdb17
chore: lint
JonathanOppenheimer 6e293fe
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
ceyonur 570a4d0
Merge branch 'master' into JonathanOppenheimer/acp224-add-precompile
JonathanOppenheimer 30cf7f9
chore: bazel metadata
JonathanOppenheimer 32d11ed
Merge branch 'JonathanOppenheimer/acp224-add-precompile' into Jonatha…
JonathanOppenheimer d3cd199
Merge remote-tracking branch 'origin/master' into JonathanOppenheimer…
JonathanOppenheimer a4bf037
chore: lint
JonathanOppenheimer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 { | ||
| ValidatorTargetGas bool `json:"validatorTargetGas,omitempty"` // when true, validators control targetGas via node preferences | ||
| TargetGas uint64 `json:"targetGas"` // target gas consumption per second | ||
| StaticPricing bool `json:"staticPricing,omitempty"` // when true, gas price is always minGasPrice | ||
| 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: | ||
| 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 | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| // 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) { | ||
| 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) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| 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) | ||
| }) | ||
| } | ||
|
|
||
| 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()), | ||
| want: true, | ||
| }, | ||
| { | ||
| name: "different targetGas", | ||
| a: utils.PointerTo(DefaultACP224FeeConfig()), | ||
| b: func() *ACP224FeeConfig { | ||
| c := DefaultACP224FeeConfig() | ||
| c.TargetGas = 20_000_000 | ||
| 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()") | ||
| }) | ||
| } | ||
| } |
59 changes: 59 additions & 0 deletions
59
graft/subnet-evm/precompile/contracts/acp224feemanager/BUILD.bazel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| 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", | ||
| "simulated_test.go", | ||
| ], | ||
| embed = [":acp224feemanager"], | ||
| deps = [ | ||
| "//graft/subnet-evm/accounts/abi/bind", | ||
| "//graft/subnet-evm/commontype", | ||
| "//graft/subnet-evm/core", | ||
| "//graft/subnet-evm/core/extstate", | ||
| "//graft/subnet-evm/ethclient/simulated", | ||
| "//graft/subnet-evm/params", | ||
| "//graft/subnet-evm/plugin/evm/customtypes", | ||
| "//graft/subnet-evm/precompile/allowlist", | ||
| "//graft/subnet-evm/precompile/allowlist/allowlisttest", | ||
| "//graft/subnet-evm/precompile/contract", | ||
| "//graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings", | ||
| "//graft/subnet-evm/precompile/contracts/utilstest", | ||
| "//graft/subnet-evm/precompile/modules", | ||
| "//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_ava_labs_libevm//crypto", | ||
| "@com_github_stretchr_testify//require", | ||
| "@org_uber_go_mock//gomock", | ||
| ], | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We export these errors for use in the test.