banner
zach

zach

github
twitter
medium

Flasbots Builder Explanation (1) Initialization

Initialize

Flashbots Builder is developed based on geth, so the overall architecture is consistent with geth. The core structure of Builder is defined in the builder/builder.go file, and Builder is encapsulated into BuilderService to provide HTTP services externally. From the outside to the inside, analyze BuilderService first, then Builder and its internal components.

BuilderService

  • Encapsulates the IBuilder interface and httpServer
  • NewService parameters: pass in the listening address, localRelay configuration, and builder instance
    • If localRelay is not empty, initialize the routes
      • GET: /
      • GET: /eth/v1/builder/status
      • POST: /eth/v1/builder/validators
      • GET: /eth/v1/builder/header/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}
      • POST: /eth/v1/builder/blinded_blocks
  • Start: Start the HTTP service and start the builder
  • Stop: Stop the HTTP service and stop the builder

Builder

First, let's look at the BuilderArgs parameter of NewBuilder, and the comments for each field have been added.

type BuilderArgs struct {
    sk                            *bls.SecretKey // The private key for running the builder
    ds                            flashbotsextra.IDatabaseService // Local database service
    relay                         IRelay // Relay interface
    builderSigningDomain          phase0.Domain // The domain used for signing when submitting blocks
    builderBlockResubmitInterval  time.Duration // The interval for resubmitting blocks
    discardRevertibleTxOnErr      bool // Not used
    eth                           IEthereumService // eth instance used for building blocks
    dryRun                        bool // Whether to submit blocks to the relay
    ignoreLatePayloadAttributes   bool // Used to filter when listening for events
    validator                     *blockvalidation.BlockValidationAPI // Used for validation when dryRun is enabled
    beaconClient                  IBeaconClient // Beacon chain client used for listening to events and building payloads
    submissionOffsetFromEndOfSlot time.Duration  // The waiting time for submitting blocks

    limiter *rate.Limiter // Used for rate limiting
}

It can be seen that the core components of the builder include ds, relay, eth, and beaconClient. Other parameters will be further explained when they are applied later.

Relay

First, the Relay appears in two places (BuilderService and Builder), and there are two types (localRelay and remoteRelay).

  • In BuilderService, localRelay is already available. If localRelay is not empty, the corresponding routes will be registered in the http service of BuilderService.
  • In Builder, there is Relay. If remoteReplayEndpoint is not configured, localRelay will be used; otherwise, remoteRelay will be used.

Therefore, each builder does not necessarily need to run its own relay service, but it will definitely connect to the corresponding relay service.

The interface definition of Relay is as follows:

type IRelay interface {
    SubmitBlock(msg *bellatrixapi.SubmitBlockRequest, vd ValidatorData) error
    SubmitBlockCapella(msg *capellaapi.SubmitBlockRequest, vd ValidatorData) error
    GetValidatorForSlot(nextSlot uint64) (ValidatorData, error)
    Config() RelayConfig
    Start() error
    Stop()
}

DatabaseService

Let's go back to the place where DatabaseService is initialized. When initializing, it checks whether the postgres connection is configured. If not, it initializes a default dbService; otherwise, it establishes a db connection.

var ds flashbotsextra.IDatabaseService
    dbDSN := os.Getenv("FLASHBOTS_POSTGRES_DSN")
    if dbDSN != "" {
        ds, err = flashbotsextra.NewDatabaseService(dbDSN)
        if err != nil {
            log.Error("could not connect to the DB", "err", err)
            ds = flashbotsextra.NilDbService{}
        }
    } else {
        log.Info("db dsn is not provided, starting nil db svc")
        ds = flashbotsextra.NilDbService{}
    }

The interface definition of IDatabaseService is as follows: for the default NilDbService, it returns empty values.

type IDatabaseService interface {
    ConsumeBuiltBlock(block *types.Block, blockValue *big.Int, OrdersClosedAt time.Time, sealedAt time.Time,
        commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle,
        usedSbundles []types.UsedSBundle,
        bidTrace *apiv1.BidTrace)
    GetPriorityBundles(ctx context.Context, blockNum int64, isHighPrio bool) ([]DbBundle, error)
    GetLatestUuidBundles(ctx context.Context, blockNum int64) ([]types.LatestUuidBundle, error)
}

In the specific implementation, it mainly records information such as blocks and bundles in the database, which is used to record the built blocks and bundle information of the local builder, as well as for querying and replacement. This will be introduced later.

Eth

The structure defined here is EthereumService, which is an encapsulation of the eth instance. The eth instance is the familiar eth instance in geth, which is initialized earlier and abstracted into the IEthereumService interface to provide the following four methods externally.

type IEthereumService interface {
    BuildBlock(attrs *types.BuilderPayloadAttributes, sealedBlockCallback miner.BlockHookFn) error
    GetBlockByHash(hash common.Hash) *types.Block
    Config() *params.ChainConfig
    Synced() bool
}

BeaconClient

beaconClient is used to communicate with the beacon chain node. In the initialization part, depending on the configuration BeaconEndpoints, either NewBeaconClient or NewMultiBeaconClient is selected.

var beaconClient IBeaconClient
    if len(cfg.BeaconEndpoints) == 0 {
        beaconClient = &NilBeaconClient{}
    } else if len(cfg.BeaconEndpoints) == 1 {
        beaconClient = NewBeaconClient(cfg.BeaconEndpoints[0], cfg.SlotsInEpoch, cfg.SecondsInSlot)
    } else {
        beaconClient = NewMultiBeaconClient(cfg.BeaconEndpoints, cfg.SlotsInEpoch, cfg.SecondsInSlot)
    }

BeaconClient includes three core fields:

  • endpoint: Establishes the connection for beaconClient
  • slotsInEpoch: Default is 32
  • secondsInSlot: Default is 12

Slot is a fixed time period in eth2.0, usually 12s. Active validators take turns to act as proposers for different slots according to certain rules, and each slot corresponds to packing a block.

Epoch is a larger time period composed of multiple consecutive slots, usually consisting of 32 slots.

It provides the following methods externally:

type IBeaconClient interface {
    isValidator(pubkey PubkeyHex) bool
    getProposerForNextSlot(requestedSlot uint64) (PubkeyHex, error)
    SubscribeToPayloadAttributesEvents(payloadAttrC chan types.BuilderPayloadAttributes)
    Start() error
    Stop()
}

The key method is SubscribeToPayloadAttributesEvents, which is used to subscribe to the requested events.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.