Skip to content

Commit 4e02e4b

Browse files
committed
add conversion functions
1 parent fe73df7 commit 4e02e4b

File tree

4 files changed

+233
-1
lines changed

4 files changed

+233
-1
lines changed

common/types.go

+86
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
var (
2222
ErrUnknownNetwork = errors.New("unknown network")
2323
ErrEmptyPayload = errors.New("empty payload")
24+
ErrEmptyPayloadHeader = errors.New("empty payload header")
25+
ErrEmptyPayloadMessage = errors.New("empty payload message")
2426
ErrVersionNotSupported = errors.New("version is not supported")
2527

2628
EthNetworkHolesky = "holesky"
@@ -418,6 +420,15 @@ type BlockSubmissionInfo struct {
418420
ExcessBlobGas uint64
419421
}
420422

423+
type HeaderSubmissionInfo struct {
424+
BidTrace *builderApiV1.BidTrace
425+
Signature phase0.BLSSignature
426+
Timestamp uint64
427+
PrevRandao phase0.Hash32
428+
TransactionsRoot phase0.Root
429+
WithdrawalsRoot phase0.Root
430+
}
431+
421432
// VersionedSubmitHeaderOptimistic is a versioned signed header to construct the builder bid.
422433
type VersionedSubmitHeaderOptimistic struct {
423434
Version spec.DataVersion
@@ -467,6 +478,12 @@ func (h *VersionedSubmitHeaderOptimistic) UnmarshalJSON(data []byte) error {
467478
func (h *VersionedSubmitHeaderOptimistic) BidTrace() (*builderApiV1.BidTrace, error) {
468479
switch h.Version { //nolint:exhaustive
469480
case spec.DataVersionDeneb:
481+
if h.Deneb == nil {
482+
return nil, ErrEmptyPayload
483+
}
484+
if h.Deneb.Message == nil {
485+
return nil, ErrEmptyPayloadMessage
486+
}
470487
return h.Deneb.Message, nil
471488
default:
472489
return nil, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
@@ -476,6 +493,12 @@ func (h *VersionedSubmitHeaderOptimistic) BidTrace() (*builderApiV1.BidTrace, er
476493
func (h *VersionedSubmitHeaderOptimistic) ExecutionPayloadBlockHash() (phase0.Hash32, error) {
477494
switch h.Version { //nolint:exhaustive
478495
case spec.DataVersionDeneb:
496+
if h.Deneb == nil {
497+
return phase0.Hash32{}, ErrEmptyPayload
498+
}
499+
if h.Deneb.ExecutionPayloadHeader == nil {
500+
return phase0.Hash32{}, ErrEmptyPayloadHeader
501+
}
479502
return h.Deneb.ExecutionPayloadHeader.BlockHash, nil
480503
default:
481504
return phase0.Hash32{}, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
@@ -485,12 +508,75 @@ func (h *VersionedSubmitHeaderOptimistic) ExecutionPayloadBlockHash() (phase0.Ha
485508
func (h *VersionedSubmitHeaderOptimistic) Signature() (phase0.BLSSignature, error) {
486509
switch h.Version { //nolint:exhaustive
487510
case spec.DataVersionDeneb:
511+
if h.Deneb == nil {
512+
return phase0.BLSSignature{}, ErrEmptyPayload
513+
}
488514
return h.Deneb.Signature, nil
489515
default:
490516
return phase0.BLSSignature{}, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
491517
}
492518
}
493519

520+
func (h *VersionedSubmitHeaderOptimistic) Timestamp() (uint64, error) {
521+
switch h.Version { //nolint:exhaustive
522+
case spec.DataVersionDeneb:
523+
if h.Deneb == nil {
524+
return 0, ErrEmptyPayload
525+
}
526+
if h.Deneb.ExecutionPayloadHeader == nil {
527+
return 0, ErrEmptyPayloadHeader
528+
}
529+
return h.Deneb.ExecutionPayloadHeader.Timestamp, nil
530+
default:
531+
return 0, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
532+
}
533+
}
534+
535+
func (h *VersionedSubmitHeaderOptimistic) PrevRandao() (phase0.Hash32, error) {
536+
switch h.Version { //nolint:exhaustive
537+
case spec.DataVersionDeneb:
538+
if h.Deneb == nil {
539+
return phase0.Hash32{}, ErrEmptyPayload
540+
}
541+
if h.Deneb.ExecutionPayloadHeader == nil {
542+
return phase0.Hash32{}, ErrEmptyPayloadHeader
543+
}
544+
return h.Deneb.ExecutionPayloadHeader.PrevRandao, nil
545+
default:
546+
return phase0.Hash32{}, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
547+
}
548+
}
549+
550+
func (h *VersionedSubmitHeaderOptimistic) TransactionsRoot() (phase0.Root, error) {
551+
switch h.Version { //nolint:exhaustive
552+
case spec.DataVersionDeneb:
553+
if h.Deneb == nil {
554+
return phase0.Root{}, ErrEmptyPayload
555+
}
556+
if h.Deneb.ExecutionPayloadHeader == nil {
557+
return phase0.Root{}, ErrEmptyPayloadHeader
558+
}
559+
return h.Deneb.ExecutionPayloadHeader.TransactionsRoot, nil
560+
default:
561+
return phase0.Root{}, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
562+
}
563+
}
564+
565+
func (h *VersionedSubmitHeaderOptimistic) WithdrawalsRoot() (phase0.Root, error) {
566+
switch h.Version { //nolint:exhaustive
567+
case spec.DataVersionDeneb:
568+
if h.Deneb == nil {
569+
return phase0.Root{}, ErrEmptyPayload
570+
}
571+
if h.Deneb.ExecutionPayloadHeader == nil {
572+
return phase0.Root{}, ErrEmptyPayloadHeader
573+
}
574+
return h.Deneb.ExecutionPayloadHeader.WithdrawalsRoot, nil
575+
default:
576+
return phase0.Root{}, fmt.Errorf("%w: %s", ErrVersionNotSupported, h.Version)
577+
}
578+
}
579+
494580
/*
495581
DenebSubmitHeaderOptimistic is request from the builder to submit a Deneb header. At minimum
496582
without blobs, it is 956 bytes. With the current maximum of 6 blobs this adds another 288

common/types_spec.go

+37
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,43 @@ func BuildGetPayloadResponse(payload *VersionedSubmitBlockRequest) (*builderApi.
102102
return nil, ErrEmptyPayload
103103
}
104104

105+
func BuildGetHeaderResponseOptimistic(payload *VersionedSubmitHeaderOptimistic, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*builderSpec.VersionedSignedBuilderBid, error) {
106+
if payload == nil {
107+
return nil, ErrMissingRequest
108+
}
109+
110+
if sk == nil {
111+
return nil, ErrMissingSecretKey
112+
}
113+
114+
switch payload.Version {
115+
case spec.DataVersionDeneb:
116+
builderBid := builderApiDeneb.BuilderBid{
117+
Header: payload.Deneb.ExecutionPayloadHeader,
118+
BlobKZGCommitments: payload.Deneb.BlobKZGCommitments,
119+
Value: payload.Deneb.Message.Value,
120+
Pubkey: *pubkey,
121+
}
122+
123+
sig, err := ssz.SignMessage(&builderBid, domain, sk)
124+
if err != nil {
125+
return nil, err
126+
}
127+
128+
return &builderSpec.VersionedSignedBuilderBid{
129+
Version: spec.DataVersionDeneb,
130+
Deneb: &builderApiDeneb.SignedBuilderBid{
131+
Message: &builderBid,
132+
Signature: sig,
133+
},
134+
}, nil
135+
case spec.DataVersionUnknown, spec.DataVersionPhase0, spec.DataVersionAltair, spec.DataVersionBellatrix, spec.DataVersionCapella:
136+
return nil, ErrInvalidVersion
137+
default:
138+
return nil, ErrEmptyPayload
139+
}
140+
}
141+
105142
func BuilderBlockRequestToSignedBuilderBid(payload *VersionedSubmitBlockRequest, header *builderApi.VersionedExecutionPayloadHeader, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*builderSpec.VersionedSignedBuilderBid, error) {
106143
value, err := payload.Value()
107144
if err != nil {

common/utils.go

+35
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,41 @@ func GetBlockSubmissionInfo(submission *VersionedSubmitBlockRequest) (*BlockSubm
256256
}, nil
257257
}
258258

259+
func GetHeaderSubmissionInfo(submission *VersionedSubmitHeaderOptimistic) (*HeaderSubmissionInfo, error) {
260+
bidTrace, err := submission.BidTrace()
261+
if err != nil {
262+
return nil, err
263+
}
264+
signature, err := submission.Signature()
265+
if err != nil {
266+
return nil, err
267+
}
268+
timestamp, err := submission.Timestamp()
269+
if err != nil {
270+
return nil, err
271+
}
272+
prevRandao, err := submission.PrevRandao()
273+
if err != nil {
274+
return nil, err
275+
}
276+
transactionsRoot, err := submission.TransactionsRoot()
277+
if err != nil {
278+
return nil, err
279+
}
280+
withdrawalsRoot, err := submission.WithdrawalsRoot()
281+
if err != nil {
282+
return nil, err
283+
}
284+
return &HeaderSubmissionInfo{
285+
BidTrace: bidTrace,
286+
Signature: signature,
287+
Timestamp: timestamp,
288+
PrevRandao: prevRandao,
289+
TransactionsRoot: transactionsRoot,
290+
WithdrawalsRoot: withdrawalsRoot,
291+
}, nil
292+
}
293+
259294
func GetBlockSubmissionExecutionPayload(submission *VersionedSubmitBlockRequest) (*builderApi.VersionedSubmitBlindedBlockResponse, error) {
260295
switch submission.Version {
261296
case spec.DataVersionCapella:

common/utils_test.go

+75-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/attestantio/go-eth2-client/spec"
1515
"github.com/attestantio/go-eth2-client/spec/bellatrix"
1616
"github.com/attestantio/go-eth2-client/spec/capella"
17+
"github.com/attestantio/go-eth2-client/spec/deneb"
1718
"github.com/ethereum/go-ethereum/common"
1819
boostTypes "github.com/flashbots/go-boost-utils/types"
1920
"github.com/stretchr/testify/require"
@@ -114,7 +115,7 @@ func TestGetBlockSubmissionInfo(t *testing.T) {
114115
err string
115116
}{
116117
{
117-
name: "valid builderApiCapella",
118+
name: "valid capella",
118119
payload: &VersionedSubmitBlockRequest{
119120
VersionedSubmitBlockRequest: builderSpec.VersionedSubmitBlockRequest{
120121
Version: spec.DataVersionCapella,
@@ -192,3 +193,76 @@ func TestGetBlockSubmissionInfo(t *testing.T) {
192193
})
193194
}
194195
}
196+
197+
func TestGetHeaderSubmissionInfo(t *testing.T) {
198+
cases := []struct {
199+
name string
200+
payload *VersionedSubmitHeaderOptimistic
201+
expected *HeaderSubmissionInfo
202+
err string
203+
}{
204+
{
205+
name: "valid deneb",
206+
payload: &VersionedSubmitHeaderOptimistic{
207+
Version: spec.DataVersionDeneb,
208+
Deneb: &DenebSubmitHeaderOptimistic{
209+
Message: &builderApiV1.BidTrace{},
210+
ExecutionPayloadHeader: &deneb.ExecutionPayloadHeader{},
211+
},
212+
},
213+
expected: &HeaderSubmissionInfo{
214+
BidTrace: &builderApiV1.BidTrace{},
215+
},
216+
},
217+
{
218+
name: "unsupported version",
219+
payload: &VersionedSubmitHeaderOptimistic{
220+
Version: spec.DataVersionCapella,
221+
},
222+
expected: nil,
223+
err: "version is not supported: capella",
224+
},
225+
{
226+
name: "missing data",
227+
payload: &VersionedSubmitHeaderOptimistic{
228+
Version: spec.DataVersionDeneb,
229+
},
230+
expected: nil,
231+
err: "empty payload",
232+
},
233+
{
234+
name: "missing message",
235+
payload: &VersionedSubmitHeaderOptimistic{
236+
Version: spec.DataVersionDeneb,
237+
Deneb: &DenebSubmitHeaderOptimistic{
238+
ExecutionPayloadHeader: &deneb.ExecutionPayloadHeader{},
239+
},
240+
},
241+
expected: nil,
242+
err: "empty payload message",
243+
},
244+
{
245+
name: "missing execution payload",
246+
payload: &VersionedSubmitHeaderOptimistic{
247+
Version: spec.DataVersionDeneb,
248+
Deneb: &DenebSubmitHeaderOptimistic{
249+
Message: &builderApiV1.BidTrace{},
250+
},
251+
},
252+
expected: nil,
253+
err: "empty payload header",
254+
},
255+
}
256+
257+
for _, tc := range cases {
258+
t.Run(tc.name, func(t *testing.T) {
259+
submission, err := GetHeaderSubmissionInfo(tc.payload)
260+
require.Equal(t, tc.expected, submission)
261+
if tc.err == "" {
262+
require.NoError(t, err)
263+
} else {
264+
require.Equal(t, tc.err, err.Error())
265+
}
266+
})
267+
}
268+
}

0 commit comments

Comments
 (0)