diff --git a/params/config.libevm_test.go b/params/config.libevm_test.go index 4f78888db3..cdbdf3cce6 100644 --- a/params/config.libevm_test.go +++ b/params/config.libevm_test.go @@ -2,8 +2,6 @@ package params import ( "encoding/json" - "fmt" - "log" "math/big" "testing" @@ -16,88 +14,6 @@ func testOnlyClearRegisteredExtras() { registeredExtras = nil } -func ExampleRegisterExtras() { - type ( - chainConfigExtra struct { - Foo string `json:"foo"` - } - rulesExtra struct { - FooCopy string - } - ) - - // In practice, this would be called inside an init() func and the `getter` - // used to access the ExtraPayload() values in a type-safe way. - getter := RegisterExtras(Extras[chainConfigExtra, rulesExtra]{ - NewForRules: func(cc *ChainConfig, r *Rules, cEx *chainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) *rulesExtra { - // This function is called at the end of ChainConfig.Rules(), - // receiving a pointer to the Rules that will be returned. It MAY - // modify the Rules but MUST NOT modify the ChainConfig. The value - // that it returns will be available via Rules.ExtraPayload(). - return &rulesExtra{ - FooCopy: fmt.Sprintf("copy of: %q", cEx.Foo), - } - }, - }) - defer testOnlyClearRegisteredExtras() - - // ChainConfig now unmarshals any JSON field named "extra" into a pointer to - // the registered type, which is available via the ExtraPayload() method. - buf := []byte(`{ - "chainId": 1234, - "extra": { - "foo": "hello, world" - } - }`) - - config := new(ChainConfig) - if err := json.Unmarshal(buf, config); err != nil { - log.Fatal(err) - } - - fmt.Println(config.ChainID) - // The values returned by ExtraPayload() are guaranteed to be pointers to - // the registered types. They MAY, however, be nil pointers. In practice, - // callers SHOULD abstract the type assertion in a reusable function to - // provide a seamless devex. - ccExtra := getter.FromChainConfig(config) - rules := config.Rules(nil, false, 0) - rExtra := getter.FromRules(&rules) - - if ccExtra != nil { - fmt.Println(ccExtra.Foo) - } - if rExtra != nil { - fmt.Println(rExtra.FooCopy) - } - - // Output: - // 1234 - // hello, world - // copy of: "hello, world" -} - -func ExampleChainConfig_ExtraPayload() { - type ( - chainConfigExtra struct{} - rulesExtra struct{} - ) - // Typically called in an `init()` function. - getter := RegisterExtras(Extras[chainConfigExtra, rulesExtra]{ /*...*/ }) - defer testOnlyClearRegisteredExtras() - - var c ChainConfig // Sourced from elsewhere, typically unmarshalled from JSON. - - // Both ChainConfig.ExtraPayload() and Rules.ExtraPayload() return `any` - // that are guaranteed to be pointers to the registered types. - extra := getter.FromChainConfig(&c) - - // Act on the extra payload... - if extra != nil { - // ... - } -} - type rawJSON struct { json.RawMessage } @@ -171,6 +87,7 @@ func TestRegisterExtras(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + testOnlyClearRegisteredExtras() tt.register() defer testOnlyClearRegisteredExtras() @@ -196,6 +113,9 @@ func TestRegisterExtras(t *testing.T) { } func TestExtrasPanic(t *testing.T) { + testOnlyClearRegisteredExtras() + defer testOnlyClearRegisteredExtras() + assertPanics( t, func() { RegisterExtras(Extras[int, struct{}]{}) @@ -225,7 +145,6 @@ func TestExtrasPanic(t *testing.T) { ) RegisterExtras(Extras[struct{}, struct{}]{}) - defer testOnlyClearRegisteredExtras() assertPanics( t, func() { diff --git a/params/example.libevm_test.go b/params/example.libevm_test.go index 0ca03cd3b6..16a88b3708 100644 --- a/params/example.libevm_test.go +++ b/params/example.libevm_test.go @@ -1,32 +1,22 @@ -package extraparams +package params_test import ( + "encoding/json" + "fmt" + "log" "math/big" "github.com/ethereum/go-ethereum/params" ) -var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra] - -func init() { +// TODO: explain why this isn't in an init() +func initFn() { getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{ NewForRules: constructRulesExtra, }) } -type ChainConfigExtra struct { - MyFeatureTime *uint64 -} - -type RulesExtra struct { - IsMyFeature bool -} - -func constructRulesExtra(c *params.ChainConfig, r *params.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) *RulesExtra { - return &RulesExtra{ - IsMyFeature: isMerge && cEx.MyFeatureTime != nil && *cEx.MyFeatureTime < timestamp, - } -} +var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra] func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra { return getter.FromChainConfig(c) @@ -35,3 +25,58 @@ func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra { func FromRules(r *params.Rules) *RulesExtra { return getter.FromRules(r) } + +type ChainConfigExtra struct { + MyForkTime *uint64 `json:"myForkTime"` +} + +type RulesExtra struct { + IsMyFork bool +} + +func constructRulesExtra(c *params.ChainConfig, r *params.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) *RulesExtra { + return &RulesExtra{ + IsMyFork: cEx.MyForkTime != nil && *cEx.MyForkTime <= timestamp, + } +} + +func ExampleRegisterExtras() { + initFn() // TODO: explain + + const forkTime = 530003640 + jsonData := fmt.Sprintf(`{ + "chainId": 1234, + "extra": { + "myForkTime": %d + } + }`, forkTime) + + // ChainConfig now unmarshals any JSON field named "extra" into a pointer to + // the registered type, which is available via the ExtraPayload() method. + config := new(params.ChainConfig) + if err := json.Unmarshal([]byte(jsonData), config); err != nil { + log.Fatal(err) + } + + fmt.Println(config.ChainID) // original geth fields work as expected + + ccExtra := FromChainConfig(config) + if ccExtra != nil && ccExtra.MyForkTime != nil { + fmt.Println(*ccExtra.MyForkTime) + } + + for _, time := range []uint64{forkTime - 1, forkTime, forkTime + 1} { + rules := config.Rules(nil, false, time) + rExtra := FromRules(&rules) + if rExtra != nil { + fmt.Printf("%+v\n", rExtra) + } + } + + // Output: + // 1234 + // 530003640 + // &{IsMyFork:false} + // &{IsMyFork:true} + // &{IsMyFork:true} +}