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
- If localRelay is not empty, initialize the routes
- 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 beaconClientslotsInEpoch
: Default is 32secondsInSlot
: 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.