mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-21 14:14:30 +00:00
feat: params.ExtraPayloads.SetOnChainConfig() + Rules equiv (#14)
* feat: `params.ExtraPayloadGetter.SetOnChainConfig()` + `Rules` equiv * refactor: rename `ExtraPayloadsGetter` to `ExtraPayloads`
This commit is contained in:
parent
d31803a0ee
commit
a574ae6ef0
4 changed files with 54 additions and 42 deletions
|
|
@ -47,27 +47,27 @@ type Extras[C ChainConfigHooks, R RulesHooks] struct {
|
|||
// Calls to [ChainConfig.Rules] will call the `NewRules` function of the
|
||||
// registered [Extras] to create a new `R`.
|
||||
//
|
||||
// The payloads can be accessed via the [ExtraPayloadGetter.FromChainConfig] and
|
||||
// [ExtraPayloadGetter.FromRules] methods of the getter returned by
|
||||
// RegisterExtras. Where stated in the interface definitions, they will also be
|
||||
// used as hooks to alter Ethereum behaviour; if this isn't desired then they
|
||||
// can embed [NOOPHooks] to satisfy either interface.
|
||||
func RegisterExtras[C ChainConfigHooks, R RulesHooks](e Extras[C, R]) ExtraPayloadGetter[C, R] {
|
||||
// The payloads can be accessed via the [ExtraPayloads.FromChainConfig] and
|
||||
// [ExtraPayloads.FromRules] methods of the accessor returned by RegisterExtras.
|
||||
// Where stated in the interface definitions, they will also be used as hooks to
|
||||
// alter Ethereum behaviour; if this isn't desired then they can embed
|
||||
// [NOOPHooks] to satisfy either interface.
|
||||
func RegisterExtras[C ChainConfigHooks, R RulesHooks](e Extras[C, R]) ExtraPayloads[C, R] {
|
||||
if registeredExtras != nil {
|
||||
panic("re-registration of Extras")
|
||||
}
|
||||
mustBeStructOrPointerToOne[C]()
|
||||
mustBeStructOrPointerToOne[R]()
|
||||
|
||||
getter := e.getter()
|
||||
payloads := e.payloads()
|
||||
registeredExtras = &extraConstructors{
|
||||
newChainConfig: pseudo.NewConstructor[C]().Zero,
|
||||
newRules: pseudo.NewConstructor[R]().Zero,
|
||||
reuseJSONRoot: e.ReuseJSONRoot,
|
||||
newForRules: e.newForRules,
|
||||
getter: getter,
|
||||
payloads: payloads,
|
||||
}
|
||||
return getter
|
||||
return payloads
|
||||
}
|
||||
|
||||
// TestOnlyClearRegisteredExtras clears the [Extras] previously passed to
|
||||
|
|
@ -102,7 +102,7 @@ type extraConstructors struct {
|
|||
newForRules func(_ *ChainConfig, _ *Rules, blockNum *big.Int, isMerge bool, timestamp uint64) *pseudo.Type
|
||||
// use top-level hooksFrom<X>() functions instead of these as they handle
|
||||
// instances where no [Extras] were registered.
|
||||
getter interface {
|
||||
payloads interface {
|
||||
hooksFromChainConfig(*ChainConfig) ChainConfigHooks
|
||||
hooksFromRules(*Rules) RulesHooks
|
||||
}
|
||||
|
|
@ -112,11 +112,11 @@ func (e *Extras[C, R]) newForRules(c *ChainConfig, r *Rules, blockNum *big.Int,
|
|||
if e.NewRules == nil {
|
||||
return registeredExtras.newRules()
|
||||
}
|
||||
rExtra := e.NewRules(c, r, e.getter().FromChainConfig(c), blockNum, isMerge, timestamp)
|
||||
rExtra := e.NewRules(c, r, e.payloads().FromChainConfig(c), blockNum, isMerge, timestamp)
|
||||
return pseudo.From(rExtra).Type
|
||||
}
|
||||
|
||||
func (*Extras[C, R]) getter() (g ExtraPayloadGetter[C, R]) { return }
|
||||
func (*Extras[C, R]) payloads() (g ExtraPayloads[C, R]) { return }
|
||||
|
||||
// mustBeStructOrPointerToOne panics if `T` isn't a struct or a *struct.
|
||||
func mustBeStructOrPointerToOne[T any]() {
|
||||
|
|
@ -140,44 +140,56 @@ func notStructMessage[T any]() string {
|
|||
return fmt.Sprintf("%T is not a struct nor a pointer to a struct", x)
|
||||
}
|
||||
|
||||
// An ExtraPayloadGettter provides strongly typed access to the extra payloads
|
||||
// carried by [ChainConfig] and [Rules] structs. The only valid way to construct
|
||||
// a getter is by a call to [RegisterExtras].
|
||||
type ExtraPayloadGetter[C ChainConfigHooks, R RulesHooks] struct {
|
||||
_ struct{} // make godoc show unexported fields so nobody tries to make their own getter ;)
|
||||
// ExtraPayloads provides strongly typed access to the extra payloads carried by
|
||||
// [ChainConfig] and [Rules] structs. The only valid way to construct an
|
||||
// instance is by a call to [RegisterExtras].
|
||||
type ExtraPayloads[C ChainConfigHooks, R RulesHooks] struct {
|
||||
_ struct{} // make godoc show unexported fields so nobody tries to make their own instance ;)
|
||||
}
|
||||
|
||||
// FromChainConfig returns the ChainConfig's extra payload.
|
||||
func (ExtraPayloadGetter[C, R]) FromChainConfig(c *ChainConfig) C {
|
||||
func (ExtraPayloads[C, R]) FromChainConfig(c *ChainConfig) C {
|
||||
return pseudo.MustNewValue[C](c.extraPayload()).Get()
|
||||
}
|
||||
|
||||
// PointerFromChainConfig returns a pointer to the ChainConfig's extra payload.
|
||||
// This is guaranteed to be non-nil.
|
||||
func (ExtraPayloadGetter[C, R]) PointerFromChainConfig(c *ChainConfig) *C {
|
||||
func (ExtraPayloads[C, R]) PointerFromChainConfig(c *ChainConfig) *C {
|
||||
return pseudo.MustPointerTo[C](c.extraPayload()).Value.Get()
|
||||
}
|
||||
|
||||
// SetOnChainConfig sets the ChainConfig's extra payload. It is equivalent to
|
||||
// `*e.PointerFromChainConfig(cc) = val`.
|
||||
func (e ExtraPayloads[C, R]) SetOnChainConfig(cc *ChainConfig, val C) {
|
||||
*e.PointerFromChainConfig(cc) = val
|
||||
}
|
||||
|
||||
// hooksFromChainConfig is equivalent to FromChainConfig(), but returns an
|
||||
// interface instead of the concrete type implementing it; this allows it to be
|
||||
// used in non-generic code.
|
||||
func (e ExtraPayloadGetter[C, R]) hooksFromChainConfig(c *ChainConfig) ChainConfigHooks {
|
||||
func (e ExtraPayloads[C, R]) hooksFromChainConfig(c *ChainConfig) ChainConfigHooks {
|
||||
return e.FromChainConfig(c)
|
||||
}
|
||||
|
||||
// FromRules returns the Rules' extra payload.
|
||||
func (ExtraPayloadGetter[C, R]) FromRules(r *Rules) R {
|
||||
func (ExtraPayloads[C, R]) FromRules(r *Rules) R {
|
||||
return pseudo.MustNewValue[R](r.extraPayload()).Get()
|
||||
}
|
||||
|
||||
// PointerFromRules returns a pointer to the Rules's extra payload. This is
|
||||
// guaranteed to be non-nil.
|
||||
func (ExtraPayloadGetter[C, R]) PointerFromRules(r *Rules) *R {
|
||||
func (ExtraPayloads[C, R]) PointerFromRules(r *Rules) *R {
|
||||
return pseudo.MustPointerTo[R](r.extraPayload()).Value.Get()
|
||||
}
|
||||
|
||||
// SetOnRules sets the Rules' extra payload. It is equivalent to
|
||||
// `*e.PointerFromRules(r) = val`.
|
||||
func (e ExtraPayloads[C, R]) SetOnRules(r *Rules, val R) {
|
||||
*e.PointerFromRules(r) = val
|
||||
}
|
||||
|
||||
// hooksFromRules is the [RulesHooks] equivalent of hooksFromChainConfig().
|
||||
func (e ExtraPayloadGetter[C, R]) hooksFromRules(r *Rules) RulesHooks {
|
||||
func (e ExtraPayloads[C, R]) hooksFromRules(r *Rules) RulesHooks {
|
||||
return e.FromRules(r)
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +207,7 @@ func (c *ChainConfig) addRulesExtra(r *Rules, blockNum *big.Int, isMerge bool, t
|
|||
// unmarshalling of JSON), a nil value is constructed and returned.
|
||||
func (c *ChainConfig) extraPayload() *pseudo.Type {
|
||||
if registeredExtras == nil {
|
||||
// This will only happen if someone constructs an [ExtraPayloadGetter]
|
||||
// This will only happen if someone constructs an [ExtraPayloads]
|
||||
// directly, without a call to [RegisterExtras].
|
||||
//
|
||||
// See https://google.github.io/styleguide/go/best-practices#when-to-panic
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ func TestModificationOfZeroExtras(t *testing.T) {
|
|||
|
||||
TestOnlyClearRegisteredExtras()
|
||||
t.Cleanup(TestOnlyClearRegisteredExtras)
|
||||
getter := RegisterExtras(Extras[ccExtra, rulesExtra]{})
|
||||
extras := RegisterExtras(Extras[ccExtra, rulesExtra]{})
|
||||
|
||||
config := new(ChainConfig)
|
||||
rules := new(Rules)
|
||||
|
|
@ -143,30 +143,30 @@ func TestModificationOfZeroExtras(t *testing.T) {
|
|||
// closure is demonstrably over the original zero values.
|
||||
assertChainConfigExtra := func(t *testing.T, want ccExtra, msg string) {
|
||||
t.Helper()
|
||||
assert.Equalf(t, want, getter.FromChainConfig(config), "%T: "+msg, &config)
|
||||
assert.Equalf(t, want, extras.FromChainConfig(config), "%T: "+msg, &config)
|
||||
}
|
||||
assertRulesExtra := func(t *testing.T, want rulesExtra, msg string) {
|
||||
t.Helper()
|
||||
assert.Equalf(t, want, getter.FromRules(rules), "%T: "+msg, &rules)
|
||||
assert.Equalf(t, want, extras.FromRules(rules), "%T: "+msg, &rules)
|
||||
}
|
||||
|
||||
assertChainConfigExtra(t, ccExtra{}, "zero value")
|
||||
assertRulesExtra(t, rulesExtra{}, "zero value")
|
||||
|
||||
const answer = 42
|
||||
getter.PointerFromChainConfig(config).X = answer
|
||||
extras.PointerFromChainConfig(config).X = answer
|
||||
assertChainConfigExtra(t, ccExtra{X: answer}, "after setting via pointer field")
|
||||
|
||||
const pi = 314159
|
||||
getter.PointerFromRules(rules).X = pi
|
||||
extras.PointerFromRules(rules).X = pi
|
||||
assertRulesExtra(t, rulesExtra{X: pi}, "after setting via pointer field")
|
||||
|
||||
ccReplace := ccExtra{X: 142857}
|
||||
*getter.PointerFromChainConfig(config) = ccReplace
|
||||
extras.SetOnChainConfig(config, ccReplace)
|
||||
assertChainConfigExtra(t, ccReplace, "after replacement of entire extra via `*pointer = x`")
|
||||
|
||||
rulesReplace := rulesExtra{X: 18101986}
|
||||
*getter.PointerFromRules(rules) = rulesReplace
|
||||
extras.SetOnRules(rules, rulesReplace)
|
||||
assertRulesExtra(t, rulesReplace, "after replacement of entire extra via `*pointer = x`")
|
||||
|
||||
if t.Failed() {
|
||||
|
|
@ -177,15 +177,15 @@ func TestModificationOfZeroExtras(t *testing.T) {
|
|||
ccCopy := *config
|
||||
rCopy := *rules
|
||||
|
||||
assert.Equal(t, getter.FromChainConfig(&ccCopy), ccReplace, "ChainConfig extras copied")
|
||||
assert.Equal(t, getter.FromRules(&rCopy), rulesReplace, "Rules extras copied")
|
||||
assert.Equal(t, extras.FromChainConfig(&ccCopy), ccReplace, "ChainConfig extras copied")
|
||||
assert.Equal(t, extras.FromRules(&rCopy), rulesReplace, "Rules extras copied")
|
||||
|
||||
const seqUp = 123456789
|
||||
getter.PointerFromChainConfig(&ccCopy).X = seqUp
|
||||
extras.PointerFromChainConfig(&ccCopy).X = seqUp
|
||||
assertChainConfigExtra(t, ccExtra{X: seqUp}, "original changed because copy only shallow")
|
||||
|
||||
const seqDown = 987654321
|
||||
getter.PointerFromRules(&rCopy).X = seqDown
|
||||
extras.PointerFromRules(&rCopy).X = seqDown
|
||||
assertRulesExtra(t, rulesExtra{X: seqDown}, "original changed because copy only shallow")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ func initFn() {
|
|||
// This registration makes *all* [params.ChainConfig] and [params.Rules]
|
||||
// instances respect the payload types. They do not need to be modified to
|
||||
// know about `extraparams`.
|
||||
getter = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
||||
payloads = params.RegisterExtras(params.Extras[ChainConfigExtra, RulesExtra]{
|
||||
NewRules: constructRulesExtra,
|
||||
})
|
||||
}
|
||||
|
||||
var getter params.ExtraPayloadGetter[ChainConfigExtra, RulesExtra]
|
||||
var payloads params.ExtraPayloads[ChainConfigExtra, RulesExtra]
|
||||
|
||||
// constructRulesExtra acts as an adjunct to the [params.ChainConfig.Rules]
|
||||
// method. Its primary purpose is to construct the extra payload for the
|
||||
|
|
@ -67,12 +67,12 @@ type RulesExtra struct {
|
|||
|
||||
// FromChainConfig returns the extra payload carried by the ChainConfig.
|
||||
func FromChainConfig(c *params.ChainConfig) ChainConfigExtra {
|
||||
return getter.FromChainConfig(c)
|
||||
return payloads.FromChainConfig(c)
|
||||
}
|
||||
|
||||
// FromRules returns the extra payload carried by the Rules.
|
||||
func FromRules(r *params.Rules) RulesExtra {
|
||||
return getter.FromRules(r)
|
||||
return payloads.FromRules(r)
|
||||
}
|
||||
|
||||
// myForkPrecompiledContracts is analogous to the vm.PrecompiledContracts<Fork>
|
||||
|
|
@ -114,7 +114,7 @@ func (r RulesExtra) CanCreateContract(*libevm.AddressContext, libevm.StateReader
|
|||
|
||||
// This example demonstrates how the rest of this file would be used from a
|
||||
// *different* package.
|
||||
func ExampleExtraPayloadGetter() {
|
||||
func ExampleExtraPayloads() {
|
||||
initFn() // Outside of an example this is unnecessary as the function will be a regular init().
|
||||
|
||||
const forkTime = 530003640
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ type RulesAllowlistHooks interface {
|
|||
// none were registered.
|
||||
func (c *ChainConfig) Hooks() ChainConfigHooks {
|
||||
if e := registeredExtras; e != nil {
|
||||
return e.getter.hooksFromChainConfig(c)
|
||||
return e.payloads.hooksFromChainConfig(c)
|
||||
}
|
||||
return NOOPHooks{}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func (c *ChainConfig) Hooks() ChainConfigHooks {
|
|||
// none were registered.
|
||||
func (r *Rules) Hooks() RulesHooks {
|
||||
if e := registeredExtras; e != nil {
|
||||
return e.getter.hooksFromRules(r)
|
||||
return e.payloads.hooksFromRules(r)
|
||||
}
|
||||
return NOOPHooks{}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue