@@ -5,13 +5,11 @@ import (
55 "errors"
66 "fmt"
77 "net/http"
8- "sync"
98 "sync/atomic"
109 "time"
1110
1211 builderApi "github.com/attestantio/go-builder-client/api"
1312 denebApi "github.com/attestantio/go-builder-client/api/deneb"
14- builderSpec "github.com/attestantio/go-builder-client/spec"
1513 eth2ApiV1Bellatrix "github.com/attestantio/go-eth2-client/api/v1/bellatrix"
1614 eth2ApiV1Capella "github.com/attestantio/go-eth2-client/api/v1/capella"
1715 eth2ApiV1Deneb "github.com/attestantio/go-eth2-client/api/v1/deneb"
@@ -22,7 +20,6 @@ import (
2220 "github.com/flashbots/mev-boost/config"
2321 "github.com/flashbots/mev-boost/server/params"
2422 "github.com/flashbots/mev-boost/server/types"
25- "github.com/google/uuid"
2623 "github.com/sirupsen/logrus"
2724)
2825
@@ -315,178 +312,3 @@ func blockHash[P Payload](payload P) phase0.Hash32 {
315312func bidKey (slot phase0.Slot , blockHash phase0.Hash32 ) string {
316313 return fmt .Sprintf ("%v%v" , slot , blockHash )
317314}
318-
319- // getHeader requests a bid from each relay and returns the most profitable one
320- func (m * BoostService ) getHeader (log * logrus.Entry , ua UserAgent , slot phase0.Slot , pubkey , parentHashHex string ) (bidResp , error ) {
321- // Ensure arguments are valid
322- if len (pubkey ) != 98 {
323- return bidResp {}, errInvalidPubkey
324- }
325- if len (parentHashHex ) != 66 {
326- return bidResp {}, errInvalidHash
327- }
328-
329- // Make sure we have a uid for this slot
330- m .slotUIDLock .Lock ()
331- if m .slotUID .slot < slot {
332- m .slotUID .slot = slot
333- m .slotUID .uid = uuid .New ()
334- }
335- slotUID := m .slotUID .uid
336- m .slotUIDLock .Unlock ()
337- log = log .WithField ("slotUID" , slotUID )
338-
339- // Log how late into the slot the request starts
340- slotStartTimestamp := m .genesisTime + uint64 (slot )* config .SlotTimeSec
341- msIntoSlot := uint64 (time .Now ().UTC ().UnixMilli ()) - slotStartTimestamp * 1000
342- log .WithFields (logrus.Fields {
343- "genesisTime" : m .genesisTime ,
344- "slotTimeSec" : config .SlotTimeSec ,
345- "msIntoSlot" : msIntoSlot ,
346- }).Infof ("getHeader request start - %d milliseconds into slot %d" , msIntoSlot , slot )
347-
348- // Add request headers
349- headers := map [string ]string {
350- HeaderKeySlotUID : slotUID .String (),
351- HeaderStartTimeUnixMS : fmt .Sprintf ("%d" , time .Now ().UTC ().UnixMilli ()),
352- }
353-
354- var (
355- mu sync.Mutex
356- wg sync.WaitGroup
357-
358- // The final response, containing the highest bid (if any)
359- result = bidResp {}
360-
361- // Relays that sent the bid for a specific blockHash
362- relays = make (map [BlockHashHex ][]types.RelayEntry )
363- )
364-
365- // Request a bid from each relay
366- for _ , relay := range m .relays {
367- wg .Add (1 )
368- go func (relay types.RelayEntry ) {
369- defer wg .Done ()
370-
371- // Build the request URL
372- url := relay .GetURI (fmt .Sprintf ("/eth/v1/builder/header/%d/%s/%s" , slot , parentHashHex , pubkey ))
373- log := log .WithField ("url" , url )
374-
375- // Send the get bid request to the relay
376- bid := new (builderSpec.VersionedSignedBuilderBid )
377- code , err := SendHTTPRequest (context .Background (), m .httpClientGetHeader , http .MethodGet , url , ua , headers , nil , bid )
378- if err != nil {
379- log .WithError (err ).Warn ("error making request to relay" )
380- return
381- }
382- if code == http .StatusNoContent {
383- log .Debug ("no-content response" )
384- return
385- }
386-
387- // Skip if bid is empty
388- if bid .IsEmpty () {
389- return
390- }
391-
392- // Getting the bid info will check if there are missing fields in the response
393- bidInfo , err := parseBidInfo (bid )
394- if err != nil {
395- log .WithError (err ).Warn ("error parsing bid info" )
396- return
397- }
398-
399- // Ignore bids with an empty block
400- if bidInfo .blockHash == nilHash {
401- log .Warn ("relay responded with empty block hash" )
402- return
403- }
404-
405- // Add some info about the bid to the logger
406- valueEth := weiBigIntToEthBigFloat (bidInfo .value .ToBig ())
407- log = log .WithFields (logrus.Fields {
408- "blockNumber" : bidInfo .blockNumber ,
409- "blockHash" : bidInfo .blockHash .String (),
410- "txRoot" : bidInfo .txRoot .String (),
411- "value" : valueEth .Text ('f' , 18 ),
412- })
413-
414- // Ensure the bid uses the correct public key
415- if relay .PublicKey .String () != bidInfo .pubkey .String () {
416- log .Errorf ("bid pubkey mismatch. expected: %s - got: %s" , relay .PublicKey .String (), bidInfo .pubkey .String ())
417- return
418- }
419-
420- // Verify the relay signature in the relay response
421- if ! config .SkipRelaySignatureCheck {
422- ok , err := checkRelaySignature (bid , m .builderSigningDomain , relay .PublicKey )
423- if err != nil {
424- log .WithError (err ).Error ("error verifying relay signature" )
425- return
426- }
427- if ! ok {
428- log .Error ("failed to verify relay signature" )
429- return
430- }
431- }
432-
433- // Verify response coherence with proposer's input data
434- if bidInfo .parentHash .String () != parentHashHex {
435- log .WithFields (logrus.Fields {
436- "originalParentHash" : parentHashHex ,
437- "responseParentHash" : bidInfo .parentHash .String (),
438- }).Error ("proposer and relay parent hashes are not the same" )
439- return
440- }
441-
442- // Ignore bids with 0 value
443- isZeroValue := bidInfo .value .IsZero ()
444- isEmptyListTxRoot := bidInfo .txRoot .String () == "0x7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1"
445- if isZeroValue || isEmptyListTxRoot {
446- log .Warn ("ignoring bid with 0 value" )
447- return
448- }
449-
450- log .Debug ("bid received" )
451-
452- // Skip if value is lower than the minimum bid
453- if bidInfo .value .CmpBig (m .relayMinBid .BigInt ()) == - 1 {
454- log .Debug ("ignoring bid below min-bid value" )
455- return
456- }
457-
458- mu .Lock ()
459- defer mu .Unlock ()
460-
461- // Remember which relays delivered which bids (multiple relays might deliver the top bid)
462- relays [BlockHashHex (bidInfo .blockHash .String ())] = append (relays [BlockHashHex (bidInfo .blockHash .String ())], relay )
463-
464- // Compare the bid with already known top bid (if any)
465- if ! result .response .IsEmpty () {
466- valueDiff := bidInfo .value .Cmp (result .bidInfo .value )
467- if valueDiff == - 1 {
468- // The current bid is less profitable than already known one
469- return
470- } else if valueDiff == 0 {
471- // The current bid is equally profitable as already known one
472- // Use hash as tiebreaker
473- previousBidBlockHash := result .bidInfo .blockHash
474- if bidInfo .blockHash .String () >= previousBidBlockHash .String () {
475- return
476- }
477- }
478- }
479-
480- // Use this relay's response as mev-boost response because it's most profitable
481- log .Debug ("new best bid" )
482- result .response = * bid
483- result .bidInfo = bidInfo
484- result .t = time .Now ()
485- }(relay )
486- }
487- wg .Wait ()
488-
489- // Set the winning relays before returning
490- result .relays = relays [BlockHashHex (result .bidInfo .blockHash .String ())]
491- return result , nil
492- }
0 commit comments