refactor BN engine/builder block selection to work as REST block v3 backend

This commit is contained in:
tersec 2023-08-23 17:05:30 +00:00
parent 93d82e2892
commit 87777cf158
No known key found for this signature in database
GPG Key ID: 3D7A11A0156519DC
1 changed files with 54 additions and 34 deletions

View File

@ -97,6 +97,11 @@ type
blobsBundleOpt: Opt[BlobsBundle]], string] blobsBundleOpt: Opt[BlobsBundle]], string]
BlindedBlockResult[SBBB] = BlindedBlockResult[SBBB] =
Result[tuple[blindedBlckPart: SBBB, blockValue: UInt256], string] Result[tuple[blindedBlckPart: SBBB, blockValue: UInt256], string]
BlockProposalBidFutures[SBBB] = object
engineBidAvailable: bool
engineBlockFut: Future[ForkedBlockResult]
builderBidAvailable: bool
payloadBuilderBidFut: Future[BlindedBlockResult[SBBB]]
proc getValidator*(validators: auto, proc getValidator*(validators: auto,
pubkey: ValidatorPubKey): Opt[ValidatorAndIndex] = pubkey: ValidatorPubKey): Opt[ValidatorAndIndex] =
@ -800,22 +805,13 @@ proc makeBlindedBeaconBlockForHeadAndSlot*[
else: else:
return err("Attempt to create pre-Bellatrix blinded block") return err("Attempt to create pre-Bellatrix blinded block")
proc proposeBlockAux( proc collectBidFutures(
SBBB: typedesc, EPS: typedesc, node: BeaconNode, SBBB: typedesc, EPS: typedesc, node: BeaconNode,
validator: AttachedValidator, validator_index: ValidatorIndex, payloadBuilderClient: RestClientRef, validator: AttachedValidator,
head: BlockRef, slot: Slot, randao: ValidatorSig, fork: Fork, validator_index: ValidatorIndex, head: BlockRef, slot: Slot,
genesis_validators_root: Eth2Digest, randao: ValidatorSig): Future[BlockProposalBidFutures[SBBB]] {.async.} =
localBlockValueBoost: uint8): Future[BlockRef] {.async.} =
# Collect bids
var payloadBuilderClient: RestClientRef
let payloadBuilderClientMaybe = node.getPayloadBuilderClient(
validator_index.distinctBase)
if payloadBuilderClientMaybe.isOk:
payloadBuilderClient = payloadBuilderClientMaybe.get
let usePayloadBuilder = let usePayloadBuilder =
if payloadBuilderClientMaybe.isOk: if not payloadBuilderClient.isNil:
withState(node.dag.headState): withState(node.dag.headState):
# Head slot, not proposal slot, matters here # Head slot, not proposal slot, matters here
# TODO it might make some sense to allow use of builder API if local # TODO it might make some sense to allow use of builder API if local
@ -886,26 +882,50 @@ proc proposeBlockAux(
err = engineBlockFut.error.msg err = engineBlockFut.error.msg
false false
template builderBetterBid(builderValue: UInt256, engineValue: Wei): bool = return BlockProposalBidFutures[SBBB](
# Scale down to ensure no overflows; if lower few bits would have been engineBidAvailable: engineBidAvailable,
# otherwise decisive, was close enough not to matter. Calibrate to let engineBlockFut: engineBlockFut,
# uint8-range percentages avoid overflowing. builderBidAvailable: builderBidAvailable,
const scalingBits = 10 payloadBuilderBidFut: payloadBuilderBidFut)
static: doAssert 1 shl scalingBits >
high(typeof(localBlockValueBoost)).uint16 + 100 func builderBetterBid(
let localBlockValueBoost: uint8, builderValue: UInt256, engineValue: Wei): bool =
scaledBuilderValue = (builderValue shr scalingBits) * 100 # Scale down to ensure no overflows; if lower few bits would have been
scaledEngineValue = engineValue shr scalingBits # otherwise decisive, was close enough not to matter. Calibrate to let
scaledBuilderValue > # uint8-range percentages avoid overflowing.
scaledEngineValue * (localBlockValueBoost.uint16 + 100).u256 const scalingBits = 10
static: doAssert 1 shl scalingBits >
high(typeof(localBlockValueBoost)).uint16 + 100
let
scaledBuilderValue = (builderValue shr scalingBits) * 100
scaledEngineValue = engineValue shr scalingBits
scaledBuilderValue >
scaledEngineValue * (localBlockValueBoost.uint16 + 100).u256
proc proposeBlockAux(
SBBB: typedesc, EPS: typedesc, node: BeaconNode,
validator: AttachedValidator, validator_index: ValidatorIndex,
head: BlockRef, slot: Slot, randao: ValidatorSig, fork: Fork,
genesis_validators_root: Eth2Digest,
localBlockValueBoost: uint8): Future[BlockRef] {.async.} =
var payloadBuilderClient: RestClientRef
let payloadBuilderClientMaybe = node.getPayloadBuilderClient(
validator_index.distinctBase)
if payloadBuilderClientMaybe.isOk:
payloadBuilderClient = payloadBuilderClientMaybe.get
let collectedBids = await collectBidFutures(
SBBB, EPS, node, payloadBuilderClient, validator, validator_index, head,
slot, randao)
let useBuilderBlock = let useBuilderBlock =
if builderBidAvailable: if collectedBids.builderBidAvailable:
(not engineBidAvailable) or builderBetterBid( (not collectedBids.engineBidAvailable) or builderBetterBid(
payloadBuilderBidFut.read.get().blockValue, localBlockValueBoost,
engineBlockFut.read.get().blockValue) collectedBids.payloadBuilderBidFut.read.get().blockValue,
collectedBids.engineBlockFut.read.get().blockValue)
else: else:
if not engineBidAvailable: if not collectedBids.engineBidAvailable:
return head # errors logged in router return head # errors logged in router
false false
@ -913,7 +933,7 @@ proc proposeBlockAux(
let let
blindedBlock = (await blindedBlockCheckSlashingAndSign( blindedBlock = (await blindedBlockCheckSlashingAndSign(
node, slot, validator, validator_index, node, slot, validator, validator_index,
payloadBuilderBidFut.read.get.blindedBlckPart)).valueOr: collectedBids.payloadBuilderBidFut.read.get.blindedBlckPart)).valueOr:
return head return head
# Before proposeBlockMEV, can fall back to EL; after, cannot without # Before proposeBlockMEV, can fall back to EL; after, cannot without
# risking slashing. # risking slashing.
@ -929,7 +949,7 @@ proc proposeBlockAux(
beacon_block_builder_missed_without_fallback.inc() beacon_block_builder_missed_without_fallback.inc()
return head return head
var forkedBlck = engineBlockFut.read.get().blck var forkedBlck = collectedBids.engineBlockFut.read.get().blck
withBlck(forkedBlck): withBlck(forkedBlck):
let let
@ -944,7 +964,7 @@ proc proposeBlockAux(
let blobSidecarsOpt = let blobSidecarsOpt =
when blck is deneb.BeaconBlock: when blck is deneb.BeaconBlock:
var sidecars: seq[BlobSidecar] var sidecars: seq[BlobSidecar]
let bundle = engineBlockFut.read.get().blobsBundleOpt.get() let bundle = collectedBids.engineBlockFut.read.get().blobsBundleOpt.get
let (blobs, kzgs, proofs) = (bundle.blobs, bundle.kzgs, bundle.proofs) let (blobs, kzgs, proofs) = (bundle.blobs, bundle.kzgs, bundle.proofs)
for i in 0..<blobs.len: for i in 0..<blobs.len:
var sidecar = BlobSidecar( var sidecar = BlobSidecar(