Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
qdm12 committed Jan 17, 2025
1 parent 4f41ef3 commit 1541e34
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 11 deletions.
8 changes: 7 additions & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ type Body struct {
Transactions []*Transaction
Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"`

extra *pseudo.Type // See [RegisterExtras]
}

// Block represents an Ethereum block.
Expand Down Expand Up @@ -342,7 +344,11 @@ func (b *Block) encodeRLP(w io.Writer) error {
// Body returns the non-header content of the block.
// Note the returned data is not an independent copy.
func (b *Block) Body() *Body {
return &Body{b.transactions, b.uncles, b.withdrawals}
return &Body{
Transactions: b.transactions,
Uncles: b.uncles,
Withdrawals: b.withdrawals,
}
}

// Accessors for body data. These do not return a copy because the content
Expand Down
65 changes: 63 additions & 2 deletions core/types/block.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (h *Header) hooks() HeaderHooks {
return new(NOOPHeaderHooks)
}

func (e ExtraPayloads[HPtr, BlockExtraPtr, SA]) hooksFromHeader(h *Header) HeaderHooks {
func (e ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA]) hooksFromHeader(h *Header) HeaderHooks {
return e.Header.Get(h)
}

Expand Down Expand Up @@ -125,7 +125,7 @@ func (b *Block) hooks() BlockHooks {
return new(NOOPBlockHooks)
}

func (e ExtraPayloads[HPtr, BlockExtraPtr, SA]) hooksFromBlock(b *Block) BlockHooks {
func (e ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA]) hooksFromBlock(b *Block) BlockHooks {
return e.Block.Get(b)
}

Expand Down Expand Up @@ -181,3 +181,64 @@ func (b *Block) SetUncles(uncles []*Header) {
func (b *Block) SetTransactions(transactions Transactions) {
b.transactions = transactions
}

// BodyHooks are required for all types registered with [RegisterExtras] for
// [Body] payloads.
type BodyHooks interface {
EncodeRLP(*Body, io.Writer) error
DecodeRLP(*Body, *rlp.Stream) error
}

// hooks returns the Body's registered BodyHooks, if any, otherwise a
// [*NOOPBodyHooks] suitable for running the default behaviour.
func (b *Body) hooks() BodyHooks {
if r := registeredExtras; r.Registered() {
return r.Get().hooks.hooksFromBody(b)
}
return new(NOOPBodyHooks)
}

func (e ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA]) hooksFromBody(b *Body) BodyHooks {
return e.Body.Get(b)
}

var _ interface {
rlp.Encoder
rlp.Decoder
} = (*Body)(nil)

// EncodeRLP implements the [rlp.Encoder] interface.
func (b *Body) EncodeRLP(w io.Writer) error {
return b.hooks().EncodeRLP(b, w)
}

// DecodeRLP implements the [rlp.Decoder] interface.
func (b *Body) DecodeRLP(s *rlp.Stream) error {
return b.hooks().DecodeRLP(b, s)
}

func (b *Body) extraPayload() *pseudo.Type {
r := registeredExtras
if !r.Registered() {
// See params.ChainConfig.extraPayload() for panic rationale.
panic(fmt.Sprintf("%T.extraPayload() called before RegisterExtras()", r))
}
if b.extra == nil {
b.extra = r.Get().newBlock()
}
return b.extra
}

// NOOPBodyHooks implements [BodyHooks] such that they are equivalent to
// no type having been registered.
type NOOPBodyHooks struct{}

var _ BodyHooks = (*NOOPBodyHooks)(nil)

func (*NOOPBodyHooks) EncodeRLP(b *Body, w io.Writer) error {
return rlp.Encode(w, b)
}

func (*NOOPBodyHooks) DecodeRLP(b *Body, s *rlp.Stream) error {
return s.Decode(b)
}
28 changes: 20 additions & 8 deletions core/types/rlp_payload.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ func RegisterExtras[
BlockHooks
*BlockExtra
},
BodyExtra any, BodyExtraPtr interface {
BodyHooks
*BodyExtra
},
SA any,
]() ExtraPayloads[HPtr, BlockExtraPtr, SA] {
extra := ExtraPayloads[HPtr, BlockExtraPtr, SA]{
]() ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA] {
extra := ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA]{
Header: pseudo.NewAccessor[*Header, HPtr](
(*Header).extraPayload,
func(h *Header, t *pseudo.Type) { h.extra = t },
Expand All @@ -61,6 +65,10 @@ func RegisterExtras[
(*Block).extraPayload,
func(b *Block, t *pseudo.Type) { b.extra = t },
),
Body: pseudo.NewAccessor[*Body, BodyExtraPtr](
(*Body).extraPayload,
func(b *Body, t *pseudo.Type) { b.extra = t },
),
StateAccount: pseudo.NewAccessor[StateOrSlimAccount, SA](
func(a StateOrSlimAccount) *pseudo.Type { return a.extra().payload() },
func(a StateOrSlimAccount, t *pseudo.Type) { a.extra().t = t },
Expand All @@ -71,11 +79,12 @@ func RegisterExtras[
var x SA
return fmt.Sprintf("%T", x)
}(),
// The [ExtraPayloads] that we returns is based on [HPtr,BlockExtraPtr,SA], not
// [H,BlockExtra,SA] so our constructors MUST match that. This guarantees that calls to
// the [HeaderHooks] and [BlockHooks] methods will never be performed on a nil pointer.
// The [ExtraPayloads] that we returns is based on [HPtr,BlockExtraPtr,BodyExtraPtr,SA], not
// [H,BlockExtra,BodyExtra,SA] so our constructors MUST match that. This guarantees that calls to
// the [HeaderHooks], [BlockHooks] and [BodyHooks] methods will never be performed on a nil pointer.
newHeader: pseudo.NewConstructor[H]().NewPointer, // i.e. non-nil HPtr
newBlock: pseudo.NewConstructor[BlockExtra]().NewPointer, // i.e. non-nil BlockExtraPtr
newBody: pseudo.NewConstructor[BodyExtra]().NewPointer, // i.e. non-nil BodyExtraPtr
newStateAccount: pseudo.NewConstructor[SA]().Zero,
cloneStateAccount: extra.cloneStateAccount,
hooks: extra,
Expand All @@ -99,11 +108,13 @@ type extraConstructors struct {
stateAccountType string
newHeader func() *pseudo.Type
newBlock func() *pseudo.Type
newBody func() *pseudo.Type
newStateAccount func() *pseudo.Type
cloneStateAccount func(*StateAccountExtra) *StateAccountExtra
hooks interface {
hooksFromHeader(*Header) HeaderHooks
hooksFromBlock(*Block) BlockHooks
hooksFromBody(*Body) BodyHooks
}
}

Expand All @@ -117,15 +128,16 @@ func (e *StateAccountExtra) clone() *StateAccountExtra {
}

// ExtraPayloads provides strongly typed access to the extra payload carried by
// [Header], [Block], [StateAccount], and [SlimAccount] structs. The only valid way to
// [Header], [Block], [Body], [StateAccount], and [SlimAccount] structs. The only valid way to
// construct an instance is by a call to [RegisterExtras].
type ExtraPayloads[HPtr HeaderHooks, BlockExtraPtr BlockHooks, SA any] struct {
type ExtraPayloads[HPtr HeaderHooks, BlockExtraPtr BlockHooks, BodyExtraPtr BodyHooks, SA any] struct {
Header pseudo.Accessor[*Header, HPtr]
Block pseudo.Accessor[*Block, BlockExtraPtr]
Body pseudo.Accessor[*Body, BodyExtraPtr]
StateAccount pseudo.Accessor[StateOrSlimAccount, SA] // Also provides [SlimAccount] access.
}

func (ExtraPayloads[HPtr, BlockExtraPtr, SA]) cloneStateAccount(s *StateAccountExtra) *StateAccountExtra {
func (ExtraPayloads[HPtr, BlockExtraPtr, BodyExtraPtr, SA]) cloneStateAccount(s *StateAccountExtra) *StateAccountExtra {
v := pseudo.MustNewValue[SA](s.t)
return &StateAccountExtra{
t: pseudo.From(v.Get()).Type,
Expand Down

0 comments on commit 1541e34

Please sign in to comment.