banner
zach

zach

github
twitter
medium

Flasbots Builderの詳細解説 (1)初期化

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 // 信標チェーンクライアント、イベントをリッスンしてペイロードを構築
  	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("DBに接続できませんでした", "err", err)
			ds = flashbotsextra.NilDbService{}
		}
	} else {
		log.Info("db dsnが提供されていないため、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または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 の設定で、固定の時間間隔で通常は 12 秒です。すべてのアクティブなバリデーターは一定のルールに従って異なる 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 で、定期的なリクエストを取得するために使用されます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。