mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
feat: params.ExtraPayloadGetter for end-user type safety
This commit is contained in:
parent
bc6da7c964
commit
0bd2bfc667
5 changed files with 32 additions and 16 deletions
|
|
@ -3,12 +3,13 @@ package extraparams
|
|||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/libevm/pseudo"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra]
|
||||
|
||||
func init() {
|
||||
params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
||||
getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
||||
NewForRules: constructRulesExtra,
|
||||
})
|
||||
}
|
||||
|
|
@ -28,9 +29,9 @@ func constructRulesExtra(c *params.ChainConfig, r *params.Rules, cEx *ChainConfi
|
|||
}
|
||||
|
||||
func FromChainConfig(c *params.ChainConfig) *ChainConfigExtra {
|
||||
return pseudo.NewValueUnsafe[*ChainConfigExtra](c.ExtraPayload()).Get()
|
||||
return getter.FromChainConfig(c)
|
||||
}
|
||||
|
||||
func FromRules(r *params.Rules) *RulesExtra {
|
||||
return pseudo.NewValueUnsafe[*RulesExtra](r.ExtraPayload()).Get()
|
||||
return getter.FromRules(r)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ require github.com/ethereum/go-ethereum v0.0.0-00010101000000-000000000000
|
|||
require (
|
||||
github.com/holiman/uint256 v1.3.1 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
|||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -41,13 +41,27 @@ type Extras[C any, R any] struct {
|
|||
// result in a typed-nil bug. This pattern most-closely resembles a fully
|
||||
// generic implementation and users SHOULD wrap the type assertions in a shared
|
||||
// package.
|
||||
func RegisterExtras[C any, R any](e Extras[C, R]) {
|
||||
func RegisterExtras[C any, R any](e Extras[C, R]) ExtraPayloadGetter[C, R] {
|
||||
if registeredExtras != nil {
|
||||
panic("re-registration of Extras")
|
||||
}
|
||||
mustBeStruct[C]()
|
||||
mustBeStruct[R]()
|
||||
registeredExtras = &e
|
||||
return ExtraPayloadGetter[C, R]{}
|
||||
}
|
||||
|
||||
// An ExtraPayloadGettter ...
|
||||
type ExtraPayloadGetter[C any, R any] struct{}
|
||||
|
||||
// FromChainConfig ...
|
||||
func (ExtraPayloadGetter[C, R]) FromChainConfig(c *ChainConfig) *C {
|
||||
return pseudo.NewValueUnsafe[*C](c.ExtraPayload()).Get()
|
||||
}
|
||||
|
||||
// FromRules ...
|
||||
func (ExtraPayloadGetter[C, R]) FromRules(r *Rules) *R {
|
||||
return pseudo.NewValueUnsafe[*R](r.ExtraPayload()).Get()
|
||||
}
|
||||
|
||||
func mustBeStruct[T any]() {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ func ExampleRegisterExtras() {
|
|||
}
|
||||
)
|
||||
|
||||
// In practice, this would be called inside an init() func.
|
||||
RegisterExtras(Extras[chainConfigExtra, rulesExtra]{
|
||||
// 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
|
||||
|
|
@ -49,8 +50,8 @@ func ExampleRegisterExtras() {
|
|||
}
|
||||
}`)
|
||||
|
||||
var config ChainConfig
|
||||
if err := json.Unmarshal(buf, &config); err != nil {
|
||||
config := new(ChainConfig)
|
||||
if err := json.Unmarshal(buf, config); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
@ -59,9 +60,9 @@ func ExampleRegisterExtras() {
|
|||
// 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 := config.ExtraPayload().Interface().(*chainConfigExtra)
|
||||
ccExtra := getter.FromChainConfig(config)
|
||||
rules := config.Rules(nil, false, 0)
|
||||
rExtra := rules.ExtraPayload().Interface().(*rulesExtra)
|
||||
rExtra := getter.FromRules(&rules)
|
||||
|
||||
if ccExtra != nil {
|
||||
fmt.Println(ccExtra.Foo)
|
||||
|
|
@ -82,14 +83,14 @@ func ExampleChainConfig_ExtraPayload() {
|
|||
rulesExtra struct{}
|
||||
)
|
||||
// Typically called in an `init()` function.
|
||||
RegisterExtras(Extras[chainConfigExtra, rulesExtra]{ /*...*/ })
|
||||
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 := c.ExtraPayload().Interface().(*chainConfigExtra)
|
||||
extra := getter.FromChainConfig(&c)
|
||||
|
||||
// Act on the extra payload...
|
||||
if extra != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue