xChar
·a year ago

image

初始化

Flashbots Builder是在geth基础之上进行开发的,因此大体架构与geth保持一致。Builder核心结构定义在builder/builder.go文件中,Builder对外被封装到BuilderService中,对外提供http服务。从外至内,先分析BuilderService,再到Builder和其内部组成。

BuilderService

  • 封装了IBuilder接口和httpServer
  • NewService 参数:传入监听的地址,localRelay配置,builder实例
    • localRelay不为空,则初始化路由
      • 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:启动Http服务,启动builder
  • Stop:关闭Http服务,关闭builder

Builder

首先看NewBuilder的参数BuilderArgs ,对应字段的注释已经添加

type BuilderArgs struct {
  	sk                            *bls.SecretKey // 运行builder的私钥
  	ds                            flashbotsextra.IDatabaseService // 本地的数据库服务
  	relay                         IRelay // relay接口
  	builderSigningDomain          phase0.Domain // 用于提交区块时签名的域名
  	builderBlockResubmitInterval  time.Duration // 间隔一段时间重复提交区块
  	discardRevertibleTxOnErr      bool // 无用
  	eth                           IEthereumService // eth实例,用于构建区块
  	dryRun                        bool // 是否需要向relay提交区块
  	ignoreLatePayloadAttributes   bool // 用于在监听事件时过滤
  	validator                     *blockvalidation.BlockValidationAPI // dryRun时用于提交验证
  	beaconClient                  IBeaconClient // 信标链client,用于监听事件构建payload
  	submissionOffsetFromEndOfSlot time.Duration  // 提交区块的等待时间
  
  	limiter *rate.Limiter // 用作限流
}

可以看到builder的核心组成包括ds, relay, eth和beaconClient,其他的参数在后面应用到时会做进一步的解释。

Relay

首先Relay出现在两处(BuilderService和Builder),且有两种类型(localRelay和remoteRelay)

  • 在BuilderService中已经有的是localRelay,如果localRelay不为空,便会在BuilderService中的http服务注册相应的路由
  • 在Builder中有Relay,如果没有配置remoteReplayEndpoint,就用localRelay,否则是remoteRelay

由此可见,每个builder不一定要自己跑一个relay服务,但是一定会连接到相应的relay服务

Relay的接口定义如下所示:

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

先回到前面初始化DatabaseService的地方,在初始化时会判断是否配置postgres连接,如果没有的话会初始化一个默认的dbService,否则就建立db连接

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{}
	}

IDatabaseService的接口定义如下:对于默认的NilDbService,都返回的空

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)
}

在具体实现中,主要记录的是blocks bundles表等信息,用于记录本地builder的构建区块和bundle信息,也用做查询和替换用,在后面会介绍到

Eth

这里定义的是结构是EthereumService,是对eth实例的封装,eth实例也就是熟悉的geth中的eth实例,在前面被初始化,这里抽象成IEthereumService接口,对外提供以下四个方法

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

BeaconClient

beaconClient是用来与信标链节点通信的,在初始化部分,根据配置BeaconEndpoints,选择是NewBeaconClient or NewMultiBeaconClient

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 包括三个核心的字段:

  • endpoint :建立beaconClient的连接
  • slotsInEpoch :默认32
  • secondsInSlot: 默认12

slot是eth2.0中的配置,是一个固定的时间段,通常是12s,所有的活跃验证者按照一定规则轮流担当不同slot时的proposer,每个slot对应打包一个区块

epoch是更大的时间周期,由多个连续的slot组成,通常为32个slot

对外提供以下几种方法:

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

重点的方法就是 SubscribeToPayloadAttributesEvents 用来获取定阅的请求

Loading comments...