@@ -3,20 +3,28 @@ package builder
33import (
44 "context"
55 "errors"
6+ "math/big"
67 _ "os"
78 "sync"
89 "time"
910
11+ "github.com/attestantio/go-eth2-client/spec/bellatrix"
12+ "github.com/attestantio/go-eth2-client/spec/capella"
13+ "github.com/attestantio/go-eth2-client/spec/phase0"
1014 "github.com/ethereum/go-ethereum/common"
1115 blockvalidation "github.com/ethereum/go-ethereum/eth/block-validation"
16+ "github.com/holiman/uint256"
1217 "golang.org/x/time/rate"
1318
19+ "github.com/ethereum/go-ethereum/beacon/engine"
1420 "github.com/ethereum/go-ethereum/common/hexutil"
15- "github.com/ethereum/go-ethereum/core/beacon"
1621 "github.com/ethereum/go-ethereum/core/types"
1722 "github.com/ethereum/go-ethereum/flashbotsextra"
1823 "github.com/ethereum/go-ethereum/log"
1924
25+ capellaapi "github.com/attestantio/go-builder-client/api/capella"
26+ apiv1 "github.com/attestantio/go-builder-client/api/v1"
27+
2028 "github.com/flashbots/go-boost-utils/bls"
2129 boostTypes "github.com/flashbots/go-boost-utils/types"
2230)
@@ -38,6 +46,7 @@ type IBeaconClient interface {
3846
3947type IRelay interface {
4048 SubmitBlock (msg * boostTypes.BuilderSubmitBlockRequest , vd ValidatorData ) error
49+ SubmitBlockCapella (msg * capellaapi.SubmitBlockRequest , vd ValidatorData ) error
4150 GetValidatorForSlot (nextSlot uint64 ) (ValidatorData , error )
4251 Start () error
4352 Stop ()
@@ -99,16 +108,32 @@ func (b *Builder) Stop() error {
99108 return nil
100109}
101110
102- func (b * Builder ) onSealedBlock (block * types.Block , ordersClosedAt time.Time , sealedAt time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle , proposerPubkey boostTypes.PublicKey , vd ValidatorData , attrs * types.BuilderPayloadAttributes ) error {
103- executableData := beacon .BlockToExecutableData (block )
104- payload , err := executableDataToExecutionPayload (executableData )
111+ func (b * Builder ) onSealedBlock (block * types.Block , blockValue * big.Int , ordersClosedAt time.Time , sealedAt time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle , proposerPubkey boostTypes.PublicKey , vd ValidatorData , attrs * types.BuilderPayloadAttributes ) error {
112+ if b .eth .Config ().IsShanghai (block .Time ()) {
113+ if err := b .submitCapellaBlock (block , blockValue , ordersClosedAt , sealedAt , commitedBundles , allBundles , proposerPubkey , vd , attrs ); err != nil {
114+ return err
115+ }
116+ } else {
117+ if err := b .submitBellatrixBlock (block , blockValue , ordersClosedAt , sealedAt , commitedBundles , allBundles , proposerPubkey , vd , attrs ); err != nil {
118+ return err
119+ }
120+ }
121+
122+ log .Info ("submitted block" , "slot" , attrs .Slot , "value" , blockValue .String (), "parent" , block .ParentHash , "hash" , block .Hash (), "#commitedBundles" , len (commitedBundles ))
123+
124+ return nil
125+ }
126+
127+ func (b * Builder ) submitBellatrixBlock (block * types.Block , blockValue * big.Int , ordersClosedAt time.Time , sealedAt time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle , proposerPubkey boostTypes.PublicKey , vd ValidatorData , attrs * types.BuilderPayloadAttributes ) error {
128+ executableData := engine .BlockToExecutableData (block , blockValue )
129+ payload , err := executableDataToExecutionPayload (executableData .ExecutionPayload )
105130 if err != nil {
106131 log .Error ("could not format execution payload" , "err" , err )
107132 return err
108133 }
109134
110135 value := new (boostTypes.U256Str )
111- err = value .FromBig (block . Profit )
136+ err = value .FromBig (blockValue )
112137 if err != nil {
113138 log .Error ("could not set block value" , "err" , err )
114139 return err
@@ -121,8 +146,8 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
121146 BuilderPubkey : b .builderPublicKey ,
122147 ProposerPubkey : proposerPubkey ,
123148 ProposerFeeRecipient : vd .FeeRecipient ,
124- GasLimit : executableData .GasLimit ,
125- GasUsed : executableData .GasUsed ,
149+ GasLimit : executableData .ExecutionPayload . GasLimit ,
150+ GasUsed : executableData .ExecutionPayload . GasUsed ,
126151 Value : * value ,
127152 }
128153
@@ -144,7 +169,7 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
144169 log .Error ("could not validate block" , "err" , err )
145170 }
146171 } else {
147- go b .ds .ConsumeBuiltBlock (block , ordersClosedAt , sealedAt , commitedBundles , allBundles , & blockBidMsg )
172+ go b .ds .ConsumeBuiltBlock (block , blockValue , ordersClosedAt , sealedAt , commitedBundles , allBundles , & blockBidMsg )
148173 err = b .relay .SubmitBlock (& blockSubmitReq , vd )
149174 if err != nil {
150175 log .Error ("could not submit block" , "err" , err , "#commitedBundles" , len (commitedBundles ))
@@ -157,6 +182,56 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
157182 return nil
158183}
159184
185+ func (b * Builder ) submitCapellaBlock (block * types.Block , blockValue * big.Int , ordersClosedAt time.Time , sealedAt time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle , proposerPubkey boostTypes.PublicKey , vd ValidatorData , attrs * types.BuilderPayloadAttributes ) error {
186+ executableData := engine .BlockToExecutableData (block , blockValue )
187+ payload , err := executableDataToCapellaExecutionPayload (executableData .ExecutionPayload )
188+ if err != nil {
189+ log .Error ("could not format execution payload" , "err" , err )
190+ return err
191+ }
192+
193+ value := new (boostTypes.U256Str )
194+ err = value .FromBig (blockValue )
195+ if err != nil {
196+ log .Error ("could not set block value" , "err" , err )
197+ return err
198+ }
199+
200+ blockBidMsg := apiv1.BidTrace {
201+ Slot : attrs .Slot ,
202+ ParentHash : payload .ParentHash ,
203+ BlockHash : payload .BlockHash ,
204+ BuilderPubkey : phase0 .BLSPubKey (b .builderPublicKey ),
205+ ProposerPubkey : phase0 .BLSPubKey (proposerPubkey ),
206+ ProposerFeeRecipient : bellatrix .ExecutionAddress (vd .FeeRecipient ),
207+ GasLimit : executableData .ExecutionPayload .GasLimit ,
208+ GasUsed : executableData .ExecutionPayload .GasUsed ,
209+ Value : uint256 .NewInt (value .BigInt ().Uint64 ()),
210+ }
211+
212+ boostBidTrace := convertBidTrace (blockBidMsg )
213+
214+ signature , err := boostTypes .SignMessage (& blockBidMsg , b .builderSigningDomain , b .builderSecretKey )
215+ if err != nil {
216+ log .Error ("could not sign builder bid" , "err" , err )
217+ return err
218+ }
219+
220+ blockSubmitReq := capellaapi.SubmitBlockRequest {
221+ Signature : phase0 .BLSSignature (signature ),
222+ Message : & blockBidMsg ,
223+ ExecutionPayload : payload ,
224+ }
225+
226+ go b .ds .ConsumeBuiltBlock (block , blockValue , ordersClosedAt , sealedAt , commitedBundles , allBundles , & boostBidTrace )
227+ err = b .relay .SubmitBlockCapella (& blockSubmitReq , vd )
228+ if err != nil {
229+ log .Error ("could not submit block" , "err" , err , "#commitedBundles" , len (commitedBundles ))
230+ return err
231+ }
232+ return nil
233+ }
234+
160235func (b * Builder ) OnPayloadAttribute (attrs * types.BuilderPayloadAttributes ) error {
161236 if attrs == nil {
162237 return nil
@@ -203,7 +278,7 @@ func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) erro
203278 }
204279
205280 for _ , currentAttrs := range b .slotAttrs {
206- if * attrs == currentAttrs {
281+ if attrs . Equal ( & currentAttrs ) {
207282 log .Debug ("ignoring known payload attribute" , "slot" , attrs .Slot , "hash" , attrs .HeadHash )
208283 return nil
209284 }
@@ -216,6 +291,7 @@ func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) erro
216291
217292type blockQueueEntry struct {
218293 block * types.Block
294+ blockValue * big.Int
219295 ordersCloseTime time.Time
220296 sealedAt time.Time
221297 commitedBundles []types.SimulatedBundle
@@ -246,7 +322,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
246322 submitBestBlock := func () {
247323 queueMu .Lock ()
248324 if queueBestEntry .block .Hash () != queueLastSubmittedHash {
249- err := b .onSealedBlock (queueBestEntry .block , queueBestEntry .ordersCloseTime , queueBestEntry .sealedAt , queueBestEntry .commitedBundles , queueBestEntry .allBundles , proposerPubkey , vd , attrs )
325+ err := b .onSealedBlock (queueBestEntry .block , queueBestEntry .blockValue , queueBestEntry . ordersCloseTime , queueBestEntry .sealedAt , queueBestEntry .commitedBundles , queueBestEntry .allBundles , proposerPubkey , vd , attrs )
250326
251327 if err != nil {
252328 log .Error ("could not run sealed block hook" , "err" , err )
@@ -261,7 +337,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
261337 go runResubmitLoop (ctx , b .limiter , queueSignal , submitBestBlock )
262338
263339 // Populates queue with submissions that increase block profit
264- blockHook := func (block * types.Block , ordersCloseTime time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle ) {
340+ blockHook := func (block * types.Block , blockValue * big. Int , ordersCloseTime time.Time , commitedBundles []types.SimulatedBundle , allBundles []types.SimulatedBundle ) {
265341 if ctx .Err () != nil {
266342 return
267343 }
@@ -273,6 +349,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
273349 if block .Hash () != queueLastSubmittedHash {
274350 queueBestEntry = blockQueueEntry {
275351 block : block ,
352+ blockValue : new (big.Int ).Set (blockValue ),
276353 ordersCloseTime : ordersCloseTime ,
277354 sealedAt : sealedAt ,
278355 commitedBundles : commitedBundles ,
@@ -296,7 +373,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
296373 })
297374}
298375
299- func executableDataToExecutionPayload (data * beacon. ExecutableDataV1 ) (* boostTypes.ExecutionPayload , error ) {
376+ func executableDataToExecutionPayload (data * engine. ExecutableData ) (* boostTypes.ExecutionPayload , error ) {
300377 transactionData := make ([]hexutil.Bytes , len (data .Transactions ))
301378 for i , tx := range data .Transactions {
302379 transactionData [i ] = hexutil .Bytes (tx )
@@ -325,3 +402,58 @@ func executableDataToExecutionPayload(data *beacon.ExecutableDataV1) (*boostType
325402 Transactions : transactionData ,
326403 }, nil
327404}
405+
406+ func executableDataToCapellaExecutionPayload (data * engine.ExecutableData ) (* capella.ExecutionPayload , error ) {
407+ transactionData := make ([]bellatrix.Transaction , len (data .Transactions ))
408+ for i , tx := range data .Transactions {
409+ transactionData [i ] = bellatrix .Transaction (tx )
410+ }
411+
412+ withdrawalData := make ([]* capella.Withdrawal , len (data .Withdrawals ))
413+ for i , wd := range data .Withdrawals {
414+ withdrawalData [i ] = & capella.Withdrawal {
415+ Index : capella .WithdrawalIndex (wd .Index ),
416+ ValidatorIndex : phase0 .ValidatorIndex (wd .Validator ),
417+ Address : bellatrix .ExecutionAddress (wd .Address ),
418+ Amount : phase0 .Gwei (wd .Amount ),
419+ }
420+ }
421+
422+ baseFeePerGas := new (boostTypes.U256Str )
423+ err := baseFeePerGas .FromBig (data .BaseFeePerGas )
424+ if err != nil {
425+ return nil , err
426+ }
427+
428+ return & capella.ExecutionPayload {
429+ ParentHash : [32 ]byte (data .ParentHash ),
430+ FeeRecipient : [20 ]byte (data .FeeRecipient ),
431+ StateRoot : [32 ]byte (data .StateRoot ),
432+ ReceiptsRoot : [32 ]byte (data .ReceiptsRoot ),
433+ LogsBloom : boostTypes .Bloom (types .BytesToBloom (data .LogsBloom )),
434+ PrevRandao : [32 ]byte (data .Random ),
435+ BlockNumber : data .Number ,
436+ GasLimit : data .GasLimit ,
437+ GasUsed : data .GasUsed ,
438+ Timestamp : data .Timestamp ,
439+ ExtraData : data .ExtraData ,
440+ BaseFeePerGas : * baseFeePerGas ,
441+ BlockHash : [32 ]byte (data .BlockHash ),
442+ Transactions : transactionData ,
443+ Withdrawals : withdrawalData ,
444+ }, nil
445+ }
446+
447+ func convertBidTrace (bidTrace apiv1.BidTrace ) boostTypes.BidTrace {
448+ return boostTypes.BidTrace {
449+ Slot : bidTrace .Slot ,
450+ ParentHash : boostTypes .Hash (bidTrace .ParentHash ),
451+ BlockHash : boostTypes .Hash (bidTrace .BlockHash ),
452+ BuilderPubkey : boostTypes .PublicKey (bidTrace .BuilderPubkey ),
453+ ProposerPubkey : boostTypes .PublicKey (bidTrace .ProposerPubkey ),
454+ ProposerFeeRecipient : boostTypes .Address (bidTrace .ProposerFeeRecipient ),
455+ GasLimit : bidTrace .GasLimit ,
456+ GasUsed : bidTrace .GasUsed ,
457+ Value : boostTypes .IntToU256 (bidTrace .Value .Uint64 ()),
458+ }
459+ }
0 commit comments