Skip to content

Commit 2c78e50

Browse files
james-prysmrkapka
andauthored
Builder: Electra (#14344)
* removing skip from test * builder wip * removing todo, it's probably ok * adding more TODOs * adding fromProtoElectra * using lightclient s branch and updating values * minor fixes * rolling back dependency changes * go mod tidy * adding space back in * updating builder changes based on execution request changes * update ssz * changelog * updating based on execution request changes * fixing validation * adding builder test for electra * gaz * attempting to fix test * fixing ssz * fixing build and handling develop changes * gaz * fixing unfinished function * fixing test * fixing important missed regression * removing unneeded validations * missed linting * gofmt * fixing fulu test * fixing changelog * Update bid.go Co-authored-by: Radosław Kapka <[email protected]> * Update bid.go Co-authored-by: Radosław Kapka <[email protected]> * Update types.go Co-authored-by: Radosław Kapka <[email protected]> * Update types.go Co-authored-by: Radosław Kapka <[email protected]> * Update james-prysm_builder-electra.md Co-authored-by: Radosław Kapka <[email protected]> * Update testing/middleware/builder/builder.go Co-authored-by: Radosław Kapka <[email protected]> * addressing review feedback and updating e2e * fixing parsing bid version * reversing incorrect check * improving tests and updating more code based on review feedback * gofmt * fixing unit tests * more feedback from terence * gofmt * Update api/client/builder/types.go Co-authored-by: Radosław Kapka <[email protected]> * Update beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go Co-authored-by: Radosław Kapka <[email protected]> * Update beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go Co-authored-by: Radosław Kapka <[email protected]> * Update beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go Co-authored-by: Radosław Kapka <[email protected]> * Update beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go Co-authored-by: Radosław Kapka <[email protected]> * Update api/client/builder/types.go Co-authored-by: Radosław Kapka <[email protected]> * addressing nitpicks * gofmt * radek feedback * improves error --------- Co-authored-by: Radosław Kapka <[email protected]>
1 parent c8cb0f3 commit 2c78e50

File tree

21 files changed

+2027
-827
lines changed

21 files changed

+2027
-827
lines changed

api/client/builder/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ go_library(
1313
deps = [
1414
"//api:go_default_library",
1515
"//api/client:go_default_library",
16+
"//api/server:go_default_library",
1617
"//api/server/structs:go_default_library",
1718
"//config/fieldparams:go_default_library",
1819
"//config/params:go_default_library",
@@ -27,6 +28,7 @@ go_library(
2728
"//proto/engine/v1:go_default_library",
2829
"//proto/prysm/v1alpha1:go_default_library",
2930
"//runtime/version:go_default_library",
31+
"@com_github_ethereum_go_ethereum//common:go_default_library",
3032
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
3133
"@com_github_pkg_errors//:go_default_library",
3234
"@com_github_prysmaticlabs_fastssz//:go_default_library",

api/client/builder/bid.go

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package builder
22

33
import (
4-
"github.com/pkg/errors"
54
ssz "github.com/prysmaticlabs/fastssz"
65
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
76
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
87
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
98
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
9+
v1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
1010
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
1111
"github.com/prysmaticlabs/prysm/v5/runtime/version"
1212
)
@@ -22,7 +22,6 @@ type SignedBid interface {
2222
// Bid is an interface describing the method set of a builder bid.
2323
type Bid interface {
2424
Header() (interfaces.ExecutionData, error)
25-
BlobKzgCommitments() ([][]byte, error)
2625
Value() primitives.Wei
2726
Pubkey() []byte
2827
Version() int
@@ -31,6 +30,18 @@ type Bid interface {
3130
HashTreeRootWith(hh *ssz.Hasher) error
3231
}
3332

33+
// BidDeneb is an interface that exposes newly added kzg commitments on top of builder bid
34+
type BidDeneb interface {
35+
Bid
36+
BlobKzgCommitments() [][]byte
37+
}
38+
39+
// BidElectra is an interface that exposes the newly added execution requests on top of the builder bid
40+
type BidElectra interface {
41+
BidDeneb
42+
ExecutionRequests() *v1.ExecutionRequests
43+
}
44+
3445
type signedBuilderBid struct {
3546
p *ethpb.SignedBuilderBid
3647
}
@@ -115,11 +126,6 @@ func (b builderBid) Header() (interfaces.ExecutionData, error) {
115126
return blocks.WrappedExecutionPayloadHeader(b.p.Header)
116127
}
117128

118-
// BlobKzgCommitments --
119-
func (b builderBid) BlobKzgCommitments() ([][]byte, error) {
120-
return [][]byte{}, errors.New("blob kzg commitments not available before Deneb")
121-
}
122-
123129
// Version --
124130
func (b builderBid) Version() int {
125131
return version.Bellatrix
@@ -169,11 +175,6 @@ func (b builderBidCapella) Header() (interfaces.ExecutionData, error) {
169175
return blocks.WrappedExecutionPayloadHeaderCapella(b.p.Header)
170176
}
171177

172-
// BlobKzgCommitments --
173-
func (b builderBidCapella) BlobKzgCommitments() ([][]byte, error) {
174-
return [][]byte{}, errors.New("blob kzg commitments not available before Deneb")
175-
}
176-
177178
// Version --
178179
func (b builderBidCapella) Version() int {
179180
return version.Capella
@@ -254,8 +255,8 @@ func (b builderBidDeneb) Header() (interfaces.ExecutionData, error) {
254255
}
255256

256257
// BlobKzgCommitments --
257-
func (b builderBidDeneb) BlobKzgCommitments() ([][]byte, error) {
258-
return b.p.BlobKzgCommitments, nil
258+
func (b builderBidDeneb) BlobKzgCommitments() [][]byte {
259+
return b.p.BlobKzgCommitments
259260
}
260261

261262
type signedBuilderBidDeneb struct {
@@ -290,3 +291,95 @@ func (b signedBuilderBidDeneb) Version() int {
290291
func (b signedBuilderBidDeneb) IsNil() bool {
291292
return b.p == nil
292293
}
294+
295+
type builderBidElectra struct {
296+
p *ethpb.BuilderBidElectra
297+
}
298+
299+
// WrappedBuilderBidElectra is a constructor which wraps a protobuf bid into an interface.
300+
func WrappedBuilderBidElectra(p *ethpb.BuilderBidElectra) (Bid, error) {
301+
w := builderBidElectra{p: p}
302+
if w.IsNil() {
303+
return nil, consensus_types.ErrNilObjectWrapped
304+
}
305+
return w, nil
306+
}
307+
308+
// Version --
309+
func (b builderBidElectra) Version() int {
310+
return version.Electra
311+
}
312+
313+
// Value --
314+
func (b builderBidElectra) Value() primitives.Wei {
315+
return primitives.LittleEndianBytesToWei(b.p.Value)
316+
}
317+
318+
// Pubkey --
319+
func (b builderBidElectra) Pubkey() []byte {
320+
return b.p.Pubkey
321+
}
322+
323+
// IsNil --
324+
func (b builderBidElectra) IsNil() bool {
325+
return b.p == nil
326+
}
327+
328+
// HashTreeRoot --
329+
func (b builderBidElectra) HashTreeRoot() ([32]byte, error) {
330+
return b.p.HashTreeRoot()
331+
}
332+
333+
// HashTreeRootWith --
334+
func (b builderBidElectra) HashTreeRootWith(hh *ssz.Hasher) error {
335+
return b.p.HashTreeRootWith(hh)
336+
}
337+
338+
// Header --
339+
func (b builderBidElectra) Header() (interfaces.ExecutionData, error) {
340+
// We have to convert big endian to little endian because the value is coming from the execution layer.
341+
return blocks.WrappedExecutionPayloadHeaderDeneb(b.p.Header)
342+
}
343+
344+
// ExecutionRequests --
345+
func (b builderBidElectra) ExecutionRequests() *v1.ExecutionRequests {
346+
return b.p.ExecutionRequests // does not copy
347+
}
348+
349+
// BlobKzgCommitments --
350+
func (b builderBidElectra) BlobKzgCommitments() [][]byte {
351+
return b.p.BlobKzgCommitments
352+
}
353+
354+
type signedBuilderBidElectra struct {
355+
p *ethpb.SignedBuilderBidElectra
356+
}
357+
358+
// WrappedSignedBuilderBidElectra is a constructor which wraps a protobuf signed bit into an interface.
359+
func WrappedSignedBuilderBidElectra(p *ethpb.SignedBuilderBidElectra) (SignedBid, error) {
360+
w := signedBuilderBidElectra{p: p}
361+
if w.IsNil() {
362+
return nil, consensus_types.ErrNilObjectWrapped
363+
}
364+
return w, nil
365+
}
366+
367+
// Message --
368+
func (b signedBuilderBidElectra) Message() (Bid, error) {
369+
return WrappedBuilderBidElectra(b.p.Message)
370+
}
371+
372+
// Signature --
373+
func (b signedBuilderBidElectra) Signature() []byte {
374+
return b.p.Signature
375+
}
376+
377+
// Version --
378+
func (b signedBuilderBidElectra) Version() int {
379+
return version.Electra
380+
}
381+
382+
// IsNil --
383+
func (b signedBuilderBidElectra) IsNil() bool {
384+
return b.p == nil
385+
}

api/client/builder/client.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,23 @@ func (c *Client) GetHeader(ctx context.Context, slot primitives.Slot, parentHash
219219
if err := json.Unmarshal(hb, v); err != nil {
220220
return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey)
221221
}
222-
switch strings.ToLower(v.Version) {
223-
case strings.ToLower(version.String(version.Deneb)):
222+
223+
ver, err := version.FromString(strings.ToLower(v.Version))
224+
if err != nil {
225+
return nil, errors.Wrap(err, fmt.Sprintf("unsupported header version %s", strings.ToLower(v.Version)))
226+
}
227+
if ver >= version.Electra {
228+
hr := &ExecHeaderResponseElectra{}
229+
if err := json.Unmarshal(hb, hr); err != nil {
230+
return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey)
231+
}
232+
p, err := hr.ToProto()
233+
if err != nil {
234+
return nil, errors.Wrapf(err, "could not extract proto message from header")
235+
}
236+
return WrappedSignedBuilderBidElectra(p)
237+
}
238+
if ver >= version.Deneb {
224239
hr := &ExecHeaderResponseDeneb{}
225240
if err := json.Unmarshal(hb, hr); err != nil {
226241
return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey)
@@ -230,7 +245,8 @@ func (c *Client) GetHeader(ctx context.Context, slot primitives.Slot, parentHash
230245
return nil, errors.Wrapf(err, "could not extract proto message from header")
231246
}
232247
return WrappedSignedBuilderBidDeneb(p)
233-
case strings.ToLower(version.String(version.Capella)):
248+
}
249+
if ver >= version.Capella {
234250
hr := &ExecHeaderResponseCapella{}
235251
if err := json.Unmarshal(hb, hr); err != nil {
236252
return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey)
@@ -240,7 +256,8 @@ func (c *Client) GetHeader(ctx context.Context, slot primitives.Slot, parentHash
240256
return nil, errors.Wrapf(err, "could not extract proto message from header")
241257
}
242258
return WrappedSignedBuilderBidCapella(p)
243-
case strings.ToLower(version.String(version.Bellatrix)):
259+
}
260+
if ver >= version.Bellatrix {
244261
hr := &ExecHeaderResponse{}
245262
if err := json.Unmarshal(hb, hr); err != nil {
246263
return nil, errors.Wrapf(err, "error unmarshaling the builder GetHeader response, using slot=%d, parentHash=%#x, pubkey=%#x", slot, parentHash, pubkey)
@@ -250,9 +267,8 @@ func (c *Client) GetHeader(ctx context.Context, slot primitives.Slot, parentHash
250267
return nil, errors.Wrap(err, "could not extract proto message from header")
251268
}
252269
return WrappedSignedBuilderBid(p)
253-
default:
254-
return nil, fmt.Errorf("unsupported header version %s", strings.ToLower(v.Version))
255270
}
271+
return nil, fmt.Errorf("unsupported header version %s", strings.ToLower(v.Version))
256272
}
257273

258274
// RegisterValidator encodes the SignedValidatorRegistrationV1 message to json (including hex-encoding the byte

api/client/builder/client_test.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,9 @@ func TestClient_GetHeader(t *testing.T) {
266266
require.NoError(t, err)
267267
require.Equal(t, 0, value.Int.Cmp(primitives.WeiToBigInt(bid.Value())))
268268
require.Equal(t, bidStr, primitives.WeiToBigInt(bid.Value()).String())
269-
270-
kcgCommitments, err := bid.BlobKzgCommitments()
271-
require.NoError(t, err)
269+
dbid, ok := bid.(builderBidDeneb)
270+
require.Equal(t, true, ok)
271+
kcgCommitments := dbid.BlobKzgCommitments()
272272
require.Equal(t, len(kcgCommitments) > 0, true)
273273
for i := range kcgCommitments {
274274
require.Equal(t, len(kcgCommitments[i]) == 48, true)
@@ -292,6 +292,50 @@ func TestClient_GetHeader(t *testing.T) {
292292
_, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey))
293293
require.ErrorContains(t, "could not extract proto message from header: too many blob commitments: 7", err)
294294
})
295+
t.Run("electra", func(t *testing.T) {
296+
hc := &http.Client{
297+
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {
298+
require.Equal(t, expectedPath, r.URL.Path)
299+
return &http.Response{
300+
StatusCode: http.StatusOK,
301+
Body: io.NopCloser(bytes.NewBufferString(testExampleHeaderResponseElectra)),
302+
Request: r.Clone(ctx),
303+
}, nil
304+
}),
305+
}
306+
c := &Client{
307+
hc: hc,
308+
baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"},
309+
}
310+
h, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey))
311+
require.NoError(t, err)
312+
expectedWithdrawalsRoot := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2")
313+
bid, err := h.Message()
314+
require.NoError(t, err)
315+
bidHeader, err := bid.Header()
316+
require.NoError(t, err)
317+
withdrawalsRoot, err := bidHeader.WithdrawalsRoot()
318+
require.NoError(t, err)
319+
require.Equal(t, true, bytes.Equal(expectedWithdrawalsRoot, withdrawalsRoot))
320+
321+
bidStr := "652312848583266388373324160190187140051835877600158453279131187530910662656"
322+
value, err := stringToUint256(bidStr)
323+
require.NoError(t, err)
324+
require.Equal(t, 0, value.Int.Cmp(primitives.WeiToBigInt(bid.Value())))
325+
require.Equal(t, bidStr, primitives.WeiToBigInt(bid.Value()).String())
326+
ebid, ok := bid.(builderBidElectra)
327+
require.Equal(t, true, ok)
328+
kcgCommitments := ebid.BlobKzgCommitments()
329+
require.Equal(t, len(kcgCommitments) > 0, true)
330+
for i := range kcgCommitments {
331+
require.Equal(t, len(kcgCommitments[i]) == 48, true)
332+
}
333+
requests := ebid.ExecutionRequests()
334+
require.Equal(t, 1, len(requests.Deposits))
335+
require.Equal(t, 1, len(requests.Withdrawals))
336+
require.Equal(t, 1, len(requests.Consolidations))
337+
338+
})
295339
t.Run("unsupported version", func(t *testing.T) {
296340
hc := &http.Client{
297341
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {

0 commit comments

Comments
 (0)