mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
chore: make libevm/examples/extraparams a params testable example
This commit is contained in:
parent
d9dedd76d4
commit
35c8988d4f
2 changed files with 66 additions and 102 deletions
|
|
@ -2,8 +2,6 @@ package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -16,88 +14,6 @@ func testOnlyClearRegisteredExtras() {
|
||||||
registeredExtras = nil
|
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 {
|
type rawJSON struct {
|
||||||
json.RawMessage
|
json.RawMessage
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +87,7 @@ func TestRegisterExtras(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
testOnlyClearRegisteredExtras()
|
||||||
tt.register()
|
tt.register()
|
||||||
defer testOnlyClearRegisteredExtras()
|
defer testOnlyClearRegisteredExtras()
|
||||||
|
|
||||||
|
|
@ -196,6 +113,9 @@ func TestRegisterExtras(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtrasPanic(t *testing.T) {
|
func TestExtrasPanic(t *testing.T) {
|
||||||
|
testOnlyClearRegisteredExtras()
|
||||||
|
defer testOnlyClearRegisteredExtras()
|
||||||
|
|
||||||
assertPanics(
|
assertPanics(
|
||||||
t, func() {
|
t, func() {
|
||||||
RegisterExtras(Extras[int, struct{}]{})
|
RegisterExtras(Extras[int, struct{}]{})
|
||||||
|
|
@ -225,7 +145,6 @@ func TestExtrasPanic(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
RegisterExtras(Extras[struct{}, struct{}]{})
|
RegisterExtras(Extras[struct{}, struct{}]{})
|
||||||
defer testOnlyClearRegisteredExtras()
|
|
||||||
|
|
||||||
assertPanics(
|
assertPanics(
|
||||||
t, func() {
|
t, func() {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,22 @@
|
||||||
package extraparams
|
package params_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra]
|
// TODO: explain why this isn't in an init()
|
||||||
|
func initFn() {
|
||||||
func init() {
|
|
||||||
getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
||||||
NewForRules: constructRulesExtra,
|
NewForRules: constructRulesExtra,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainConfigExtra struct {
|
var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra]
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra {
|
func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra {
|
||||||
return getter.FromChainConfig(c)
|
return getter.FromChainConfig(c)
|
||||||
|
|
@ -35,3 +25,58 @@ func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra {
|
||||||
func FromRules(r *params.Rules) *RulesExtra {
|
func FromRules(r *params.Rules) *RulesExtra {
|
||||||
return getter.FromRules(r)
|
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}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue