@@ -74,11 +74,10 @@ func RegisterExtras[
7474 // The [ExtraPayloads] that we returns is based on [HPtr,BPtr,SA], not
7575 // [H,B,SA] so our constructors MUST match that. This guarantees that calls to
7676 // the [HeaderHooks] and [BodyHooks] methods will never be performed on a nil pointer.
77- newHeader : pseudo .NewConstructor [H ]().NewPointer , // i.e. non-nil HPtr
78- newBody : pseudo .NewConstructor [B ]().NewPointer , // i.e. non-nil BPtr
79- newStateAccount : pseudo .NewConstructor [SA ]().Zero ,
80- cloneStateAccount : extra .cloneStateAccount ,
81- hooks : extra ,
77+ newHeader : pseudo .NewConstructor [H ]().NewPointer , // i.e. non-nil HPtr
78+ newBody : pseudo .NewConstructor [B ]().NewPointer , // i.e. non-nil BPtr
79+ newStateAccount : pseudo .NewConstructor [SA ]().Zero ,
80+ hooks : extra ,
8281 })
8382 return extra
8483}
@@ -96,23 +95,65 @@ func TestOnlyClearRegisteredExtras() {
9695var registeredExtras register.AtMostOnce [* extraConstructors ]
9796
9897type extraConstructors struct {
99- stateAccountType string
100- newHeader func () * pseudo.Type
101- newBody func () * pseudo.Type
102- newStateAccount func () * pseudo.Type
103- cloneStateAccount func (* StateAccountExtra ) * StateAccountExtra
104- hooks interface {
98+ stateAccountType string
99+ newHeader func () * pseudo.Type
100+ newBody func () * pseudo.Type
101+ newStateAccount func () * pseudo.Type
102+ hooks interface {
105103 hooksFromHeader (* Header ) HeaderHooks
106104 hooksFromBody (* Body ) BodyHooks
105+ cloneStateAccount (* StateAccountExtra ) * StateAccountExtra
107106 }
108107}
109108
109+ func extraPayloadOrSetDefault (field * * pseudo.Type , construct func (* extraConstructors ) * pseudo.Type ) * pseudo.Type {
110+ r := registeredExtras
111+ if ! r .Registered () {
112+ // See params.ChainConfig.extraPayload() for panic rationale.
113+ panic ("<T>.extraPayload() called before RegisterExtras()" )
114+ }
115+ if * field == nil {
116+ * field = construct (r .Get ())
117+ }
118+ return * field
119+ }
120+
121+ func (h * Header ) extraPayload () * pseudo.Type {
122+ return extraPayloadOrSetDefault (& h .extra , func (c * extraConstructors ) * pseudo.Type {
123+ return c .newHeader ()
124+ })
125+ }
126+
127+ func (b * Body ) extraPayload () * pseudo.Type {
128+ return extraPayloadOrSetDefault (& b .extra , func (c * extraConstructors ) * pseudo.Type {
129+ return c .newBody ()
130+ })
131+ }
132+
133+ // hooks returns the [Header]'s registered [HeaderHooks], if any, otherwise a
134+ // [NOOPHeaderHooks] suitable for running default behaviour.
135+ func (h * Header ) hooks () HeaderHooks {
136+ if r := registeredExtras ; r .Registered () {
137+ return r .Get ().hooks .hooksFromHeader (h )
138+ }
139+ return new (NOOPHeaderHooks )
140+ }
141+
142+ // hooks returns the [Body]'s registered [BodyHooks], if any, otherwise a
143+ // [NOOPBodyHooks] suitable for running default behaviour.
144+ func (b * Body ) hooks () BodyHooks {
145+ if r := registeredExtras ; r .Registered () {
146+ return r .Get ().hooks .hooksFromBody (b )
147+ }
148+ return NOOPBodyHooks {}
149+ }
150+
110151func (e * StateAccountExtra ) clone () * StateAccountExtra {
111152 switch r := registeredExtras ; {
112153 case ! r .Registered (), e == nil :
113154 return nil
114155 default :
115- return r .Get ().cloneStateAccount (e )
156+ return r .Get ().hooks . cloneStateAccount (e )
116157 }
117158}
118159
@@ -125,6 +166,9 @@ type ExtraPayloads[HPtr HeaderHooks, BPtr BodyHooks, SA any] struct {
125166 StateAccount pseudo.Accessor [StateOrSlimAccount , SA ] // Also provides [SlimAccount] access.
126167}
127168
169+ func (e ExtraPayloads [HPtr , BPtr , SA ]) hooksFromHeader (h * Header ) HeaderHooks { return e .Header .Get (h ) }
170+ func (e ExtraPayloads [HPtr , BPtr , SA ]) hooksFromBody (b * Body ) BodyHooks { return e .Body .Get (b ) }
171+
128172func (ExtraPayloads [HPtr , BPtr , SA ]) cloneStateAccount (s * StateAccountExtra ) * StateAccountExtra {
129173 v := pseudo.MustNewValue [SA ](s .t )
130174 return & StateAccountExtra {
0 commit comments