mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12: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 (
|
||||
"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() {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue