-
Notifications
You must be signed in to change notification settings - Fork 141
Add SSE subscription to builder #53
Changes from 3 commits
27c13dd
0bd6488
18c472d
ab0434c
f51d92f
fd689ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,11 +10,22 @@ import ( | |
| "sync" | ||
| "time" | ||
|
|
||
| "github.com/attestantio/go-eth2-client/spec/capella" | ||
| "github.com/ethereum/go-ethereum/common" | ||
| "github.com/ethereum/go-ethereum/common/hexutil" | ||
| "github.com/ethereum/go-ethereum/core/types" | ||
| "github.com/ethereum/go-ethereum/log" | ||
| "github.com/r3labs/sse" | ||
| ) | ||
|
|
||
| type IBeaconClient interface { | ||
| isValidator(pubkey PubkeyHex) bool | ||
| getProposerForNextSlot(requestedSlot uint64) (PubkeyHex, error) | ||
| SubscribeToPayloadAttributesEvents(payloadAttrC chan types.BuilderPayloadAttributes) | ||
| Start() error | ||
| Stop() | ||
| } | ||
|
|
||
| type testBeaconClient struct { | ||
| validator *ValidatorPrivateData | ||
| slot uint64 | ||
|
|
@@ -30,10 +41,29 @@ func (b *testBeaconClient) isValidator(pubkey PubkeyHex) bool { | |
| func (b *testBeaconClient) getProposerForNextSlot(requestedSlot uint64) (PubkeyHex, error) { | ||
| return PubkeyHex(hexutil.Encode(b.validator.Pk)), nil | ||
| } | ||
| func (b *testBeaconClient) Start() error { | ||
| return nil | ||
|
|
||
| func (b *testBeaconClient) SubscribeToPayloadAttributesEvents(payloadAttrC chan types.BuilderPayloadAttributes) { | ||
| } | ||
|
|
||
| func (b *testBeaconClient) Start() error { return nil } | ||
|
|
||
| type NilBeaconClient struct{} | ||
|
|
||
| func (b *NilBeaconClient) isValidator(pubkey PubkeyHex) bool { | ||
| return false | ||
| } | ||
|
|
||
| func (b *NilBeaconClient) getProposerForNextSlot(requestedSlot uint64) (PubkeyHex, error) { | ||
| return PubkeyHex(""), nil | ||
| } | ||
|
|
||
| func (b *NilBeaconClient) SubscribeToPayloadAttributesEvents(payloadAttrC chan types.BuilderPayloadAttributes) { | ||
| } | ||
|
|
||
| func (b *NilBeaconClient) Start() error { return nil } | ||
|
|
||
| func (b *NilBeaconClient) Stop() {} | ||
|
|
||
| type BeaconClient struct { | ||
| endpoint string | ||
| slotsInEpoch uint64 | ||
|
|
@@ -256,3 +286,59 @@ func fetchBeacon(url string, dst any) error { | |
| log.Info("fetched", "url", url, "res", dst) | ||
| return nil | ||
| } | ||
|
|
||
| // SubscribeToPayloadAttributesEvents subscribes to payload attributes events to validate fields such as prevrandao and withdrawals | ||
| func (b *BeaconClient) SubscribeToPayloadAttributesEvents(payloadAttrC chan types.BuilderPayloadAttributes) { | ||
| payloadAttributesResp := &struct { | ||
| Version string `json:"version"` | ||
| Data struct { | ||
| ProposalSlot uint64 `json:"proposal_slot,string"` | ||
| ParentBlockHash common.Hash `json:"parent_block_hash"` | ||
| PayloadAttributes struct { | ||
| Timestamp uint64 `json:"timestamp,string"` | ||
| PrevRandao common.Hash `json:"prev_randao"` | ||
| SuggestedFeeRecipient common.Address `json:"suggested_fee_recipient"` | ||
| Withdrawals []*capella.Withdrawal `json:"withdrawals"` | ||
| } `json:"payload_attributes"` | ||
| } `json:"data"` | ||
| }{} | ||
|
|
||
| eventsURL := fmt.Sprintf("%s/eth/v1/events?topics=payload_attributes", b.endpoint) | ||
| log.Info("subscribing to payload_attributes events") | ||
|
|
||
| for { | ||
| client := sse.NewClient(eventsURL) | ||
| err := client.SubscribeRaw(func(msg *sse.Event) { | ||
|
||
| err := json.Unmarshal(msg.Data, &payloadAttributesResp) | ||
avalonche marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| log.Error("could not unmarshal payload_attributes event", "err", err) | ||
| } else { | ||
| // convert capella.Withdrawal to types.Withdrawal | ||
| withdrawals := make([]*types.Withdrawal, len(payloadAttributesResp.Data.PayloadAttributes.Withdrawals)) | ||
| for i, w := range payloadAttributesResp.Data.PayloadAttributes.Withdrawals { | ||
| withdrawals[i] = &types.Withdrawal{ | ||
| Index: uint64(w.Index), | ||
| Validator: uint64(w.ValidatorIndex), | ||
| Address: common.Address(w.Address), | ||
| Amount: uint64(w.Amount), | ||
| } | ||
| } | ||
|
|
||
| data := types.BuilderPayloadAttributes{ | ||
| Slot: payloadAttributesResp.Data.ProposalSlot, | ||
| HeadHash: payloadAttributesResp.Data.ParentBlockHash, | ||
| Timestamp: hexutil.Uint64(payloadAttributesResp.Data.PayloadAttributes.Timestamp), | ||
| Random: payloadAttributesResp.Data.PayloadAttributes.PrevRandao, | ||
| SuggestedFeeRecipient: payloadAttributesResp.Data.PayloadAttributes.SuggestedFeeRecipient, | ||
| Withdrawals: withdrawals, | ||
| } | ||
| payloadAttrC <- data | ||
| } | ||
| }) | ||
| if err != nil { | ||
| log.Error("failed to subscribe to payload_attributes events", "err", err) | ||
| time.Sleep(1 * time.Second) | ||
| } | ||
| log.Warn("beaconclient SubscribeRaw ended, reconnecting") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -120,7 +120,12 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { | |
| copy(bellatrixForkVersion[:], bellatrixForkVersionBytes[:4]) | ||
| proposerSigningDomain := boostTypes.ComputeDomain(boostTypes.DomainTypeBeaconProposer, bellatrixForkVersion, genesisValidatorsRoot) | ||
|
|
||
| beaconClient := NewBeaconClient(cfg.BeaconEndpoint, cfg.SlotsInEpoch, cfg.SecondsInSlot) | ||
| var beaconClient IBeaconClient | ||
| if cfg.BeaconEndpoint != "" { | ||
|
||
| beaconClient = NewBeaconClient(cfg.BeaconEndpoint, cfg.SlotsInEpoch, cfg.SecondsInSlot) | ||
| } else { | ||
| beaconClient = &NilBeaconClient{} | ||
| } | ||
|
|
||
| var localRelay *LocalRelay | ||
| if cfg.EnableLocalRelay { | ||
|
|
@@ -196,7 +201,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { | |
| return errors.New("incorrect builder API secret key provided") | ||
| } | ||
|
|
||
| builderBackend := NewBuilder(builderSk, ds, relay, builderSigningDomain, ethereumService, cfg.DryRun, validator) | ||
| builderBackend := NewBuilder(builderSk, ds, relay, builderSigningDomain, ethereumService, cfg.DryRun, validator, beaconClient) | ||
| builderService := NewService(cfg.ListenAddr, localRelay, builderBackend) | ||
|
|
||
| stack.RegisterAPIs([]rpc.API{ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got to be put somewhere as a regular structure :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will add in attestant types!