go-ethereum/params/config.libevm_test.go
Arran Schlosberg 5429fd87c8
chore: squash arr4n/libevm into libevm (#7)
* feat: pseudo-generic extra payloads in `params.ChainConfig` and `params.Rules`

* feat: `params.ExtraPayloadGetter` for end-user type safety

* refactor: payloads only available through `params.ExtraPayloadGetter`

* chore: make `libevm/examples/extraparams` a `params` testable example

* doc: `libevm/pseudo` package comments and improved readability

* doc: `params.*Extra*` comments and improved readability

* doc: `params.ExtraPayloadGetter` comments and improved readability

* doc: `params/config.libevm_test.go` comments and improved readability

* refactor: simplify `params.ChainConfig.UnmarshalJSON()`

* refactor: abstract new/nil-pointer creation into `pseudo.Constructor`s

* feat: precompile override via `params.Extras` hooks

* doc: flesh out `PrecompileOverride()` in example

* doc: complete commentary and improve readability

* refactor: `ChainConfig.Hooks()` + `Rules` equivalent

* chore: rename precompiles test file in keeping with geth equivalent

* feat: stateful precompiles + allowlist hooks

The allowlist hooks are included in this commit because they allow for the same functionality as stateful precompiles in `ava-labs/coreth` and `ava-labs/subnet-evm`.

* fix: `StateTransition.canExecuteTransaction()` used `msg.From` instead of `To`

* test: `params.RulesHooks.CanCreateContract` integration

* test: `params.RulesHooks.CanExecuteTransaction` integration

* test: `vm.NewStatefulPrecompile()` integration

* refactor: simplify test of `CanCreateContract`

* refactor: abstract generation of random `Address`/`Hash` values

* doc: full documentation + readability refactoring/renaming

* fix: remove circular dependency in tests
2024-09-10 19:20:32 +01:00

164 lines
3.3 KiB
Go

package params
import (
"encoding/json"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/libevm/pseudo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type rawJSON struct {
json.RawMessage
NOOPHooks
}
var _ interface {
json.Marshaler
json.Unmarshaler
} = (*rawJSON)(nil)
func TestRegisterExtras(t *testing.T) {
type (
ccExtraA struct {
A string `json:"a"`
ChainConfigHooks
}
rulesExtraA struct {
A string
RulesHooks
}
ccExtraB struct {
B string `json:"b"`
ChainConfigHooks
}
rulesExtraB struct {
B string
RulesHooks
}
)
tests := []struct {
name string
register func()
ccExtra *pseudo.Type
wantRulesExtra any
}{
{
name: "Rules payload copied from ChainConfig payload",
register: func() {
RegisterExtras(Extras[ccExtraA, rulesExtraA]{
NewRules: func(cc *ChainConfig, r *Rules, ex *ccExtraA, _ *big.Int, _ bool, _ uint64) *rulesExtraA {
return &rulesExtraA{
A: ex.A,
}
},
})
},
ccExtra: pseudo.From(&ccExtraA{
A: "hello",
}).Type,
wantRulesExtra: &rulesExtraA{
A: "hello",
},
},
{
name: "no NewForRules() function results in typed but nil pointer",
register: func() {
RegisterExtras(Extras[ccExtraB, rulesExtraB]{})
},
ccExtra: pseudo.From(&ccExtraB{
B: "world",
}).Type,
wantRulesExtra: (*rulesExtraB)(nil),
},
{
name: "custom JSON handling honoured",
register: func() {
RegisterExtras(Extras[rawJSON, struct{ RulesHooks }]{})
},
ccExtra: pseudo.From(&rawJSON{
RawMessage: []byte(`"hello, world"`),
}).Type,
wantRulesExtra: (*struct{ RulesHooks })(nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
TestOnlyClearRegisteredExtras()
tt.register()
defer TestOnlyClearRegisteredExtras()
in := &ChainConfig{
ChainID: big.NewInt(142857),
extra: tt.ccExtra,
}
buf, err := json.Marshal(in)
require.NoError(t, err)
got := new(ChainConfig)
require.NoError(t, json.Unmarshal(buf, got))
assert.Equal(t, tt.ccExtra.Interface(), got.extraPayload().Interface())
assert.Equal(t, in, got)
// TODO: do we need an explicit test of the JSON output, or is a
// Marshal-Unmarshal round trip sufficient?
gotRules := got.Rules(nil, false, 0)
assert.Equal(t, tt.wantRulesExtra, gotRules.extraPayload().Interface())
})
}
}
func TestExtrasPanic(t *testing.T) {
TestOnlyClearRegisteredExtras()
defer TestOnlyClearRegisteredExtras()
assertPanics(
t, func() {
new(ChainConfig).extraPayload()
},
"before RegisterExtras",
)
assertPanics(
t, func() {
new(Rules).extraPayload()
},
"before RegisterExtras",
)
assertPanics(
t, func() {
mustBeStruct[int]()
},
notStructMessage[int](),
)
RegisterExtras(Extras[struct{ ChainConfigHooks }, struct{ RulesHooks }]{})
assertPanics(
t, func() {
RegisterExtras(Extras[struct{ ChainConfigHooks }, struct{ RulesHooks }]{})
},
"re-registration",
)
}
func assertPanics(t *testing.T, fn func(), wantContains string) {
t.Helper()
defer func() {
switch r := recover().(type) {
case nil:
t.Error("function did not panic as expected")
case string:
assert.Contains(t, r, wantContains)
default:
t.Fatalf("BAD TEST SETUP: recover() got unsupported type %T", r)
}
}()
fn()
}