Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MEV block proposal #3883

Merged
merged 11 commits into from
Aug 1, 2022
1 change: 1 addition & 0 deletions beacon_chain/beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type
lightClientPool*: ref LightClientPool
exitPool*: ref ExitPool
eth1Monitor*: Eth1Monitor
payloadBuilderRestClient*: RestClientRef
restServer*: RestServerRef
keymanagerServer*: RestServerRef
keymanagerToken*: Option[string]
Expand Down
12 changes: 12 additions & 0 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,18 @@ type
desc: "Suggested fee recipient"
name: "suggested-fee-recipient" .}: Option[Address]

payloadBuilderEnable* {.
hidden
desc: "Enable external payload builder"
defaultValue: false
name: "payload-builder-enable" .}: bool
Copy link
Contributor

@zah zah Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this -enable suffix on other similar flags (e.g. --rest:on, --keymanager:on, --metrics:on, etc). --light-client-enable is the only existing precedent, but we haven't released this functionality officially yet, so we can fix it as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that macOS and Windows use separate infra-role-beacon-node repos and need separate updating.


payloadBuilderUrl* {.
hidden
desc: "Payload builder URL"
defaultValue: ""
name: "payload-builder-url" .}: string

of BNStartUpCmd.createTestnet:
testnetDepositsFile* {.
desc: "A LaunchPad deposits file for the genesis state validators"
Expand Down
16 changes: 14 additions & 2 deletions beacon_chain/nimbus_beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,17 @@ proc init*(T: type BeaconNode,
max(Moment.init(bellatrixEpochTime, Second),
Moment.now)

let payloadBuilderRestClient =
if config.payloadBuilderEnable:
RestClientRef.new(
config.payloadBuilderUrl,
httpFlags = {HttpClientFlag.NewConnectionAlways}).valueOr:
warn "Payload builder REST client setup failed",
payloadBuilderUrl = config.payloadBuilderUrl
nil
else:
nil

let node = BeaconNode(
nickname: nickname,
graffitiBytes: if config.graffiti.isSome: config.graffiti.get
Expand All @@ -777,6 +788,7 @@ proc init*(T: type BeaconNode,
config: config,
attachedValidators: validatorPool,
eth1Monitor: eth1Monitor,
payloadBuilderRestClient: payloadBuilderRestClient,
restServer: restServer,
keymanagerServer: keymanagerServer,
keymanagerToken: keymanagerToken,
Expand All @@ -798,7 +810,7 @@ proc init*(T: type BeaconNode,

node

func strictVerification(node: BeaconNode, slot: Slot) =
func verifyFinalization(node: BeaconNode, slot: Slot) =
# Epoch must be >= 4 to check finalization
const SETTLING_TIME_OFFSET = 1'u64
let epoch = slot.epoch()
Expand Down Expand Up @@ -1373,7 +1385,7 @@ proc onSlotStart(node: BeaconNode, wallTime: BeaconTime,
wallSlot.epoch.toGaugeValue - finalizedEpoch.toGaugeValue)

if node.config.strictVerification:
strictVerification(node, wallSlot)
verifyFinalization(node, wallSlot)

node.consensusManager[].updateHead(wallSlot)

Expand Down
15 changes: 15 additions & 0 deletions beacon_chain/nimbus_signing_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,21 @@ proc installApiHandlers*(node: SigningNode) =
validator.data.privateKey)
signature = cooked.toValidatorSig().toHex()
signatureResponse(Http200, signature)
of Web3SignerRequestKind.ValidatorRegistration:
let
forkInfo = request.forkInfo.get()
cooked = get_builder_signature(
forkInfo.fork, ValidatorRegistrationV1(
fee_recipient:
ExecutionAddress(data: distinctBase(Eth1Address.fromHex(
request.validatorRegistration.feeRecipient))),
gas_limit: request.validatorRegistration.gasLimit,
timestamp: request.validatorRegistration.timestamp,
pubkey: request.validatorRegistration.pubkey,
),
validator.data.privateKey)
signature = cooked.toValidatorSig().toHex()
signatureResponse(Http200, signature)

proc validate(key: string, value: string): int =
case key
Expand Down
108 changes: 100 additions & 8 deletions beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim
Original file line number Diff line number Diff line change
Expand Up @@ -816,14 +816,10 @@ template unrecognizedFieldWarning =
fieldName, typeName = typetraits.name(typeof value)

## ForkedBeaconBlock
proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
reader: var JsonReader[RestJson],
value: var BlockType) {.raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconBlockFork]
data: Option[JsonString]

for fieldName in readObjectFields(reader):
template prepareForkedBlockReading(
reader: var JsonReader[RestJson], value: untyped,
version: var Option[BeaconBlockFork], data: var Option[JsonString]) =
for fieldName {.inject.} in readObjectFields(reader):
case fieldName
of "version":
if version.isSome():
Expand Down Expand Up @@ -852,6 +848,15 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
if data.isNone():
reader.raiseUnexpectedValue("Field data is missing")

proc readValue*[BlockType: ForkedBeaconBlock](
reader: var JsonReader[RestJson],
value: var BlockType) {.raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconBlockFork]
data: Option[JsonString]

prepareForkedBlockReading(reader, value, version, data)

case version.get():
of BeaconBlockFork.Phase0:
let res =
Expand Down Expand Up @@ -890,6 +895,58 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
reader.raiseUnexpectedValue("Incorrect bellatrix block format")
value = ForkedBeaconBlock.init(res.get()).BlockType

proc readValue*[BlockType: Web3SignerForkedBeaconBlock](
reader: var JsonReader[RestJson],
value: var BlockType) {.raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconBlockFork]
data: Option[JsonString]

prepareForkedBlockReading(reader, value, version, data)

case version.get():
of BeaconBlockFork.Phase0:
let res =
try:
some(RestJson.decode(string(data.get()),
phase0.BeaconBlock,
requireAllFields = true,
allowUnknownFields = true))
except SerializationError:
none[phase0.BeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect phase0 block format")
value = Web3SignerForkedBeaconBlock(
kind: BeaconBlockFork.Phase0,
phase0Data: res.get())
of BeaconBlockFork.Altair:
let res =
try:
some(RestJson.decode(string(data.get()),
altair.BeaconBlock,
requireAllFields = true,
allowUnknownFields = true))
except SerializationError:
none[altair.BeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect altair block format")
value = Web3SignerForkedBeaconBlock(
kind: BeaconBlockFork.Altair,
altairData: res.get())
of BeaconBlockFork.Bellatrix:
let res =
try:
some(RestJson.decode(string(data.get()),
BeaconBlockHeader,
requireAllFields = true,
allowUnknownFields = true))
except SerializationError:
none[BeaconBlockHeader]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect bellatrix block format")
value = Web3SignerForkedBeaconBlock(
kind: BeaconBlockFork.Bellatrix,
bellatrixData: res.get())

proc writeValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
writer: var JsonWriter[RestJson],
Expand Down Expand Up @@ -1438,6 +1495,9 @@ proc writeValue*(writer: var JsonWriter[RestJson],
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)

# https://github.com/ConsenSys/web3signer/blob/41834a927088f1bde7a097e17d19e954d0058e54/core/src/main/resources/openapi-specs/eth2/signing/schemas.yaml#L421-L425 (branch v22.7.0)
# It's the "beacon_block" field even when it's not a block, but a header
writer.writeField("beacon_block", value.beaconBlock)
of Web3SignerRequestKind.Deposit:
writer.writeField("type", "DEPOSIT")
Expand Down Expand Up @@ -1486,6 +1546,15 @@ proc writeValue*(writer: var JsonWriter[RestJson],
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("contribution_and_proof",
value.syncCommitteeContributionAndProof)
of Web3SignerRequestKind.ValidatorRegistration:
# https://consensys.github.io/web3signer/web3signer-eth2.html#operation/ETH2_SIGN
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "VALIDATOR_REGISTRATION")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("validator_registration", value.validatorRegistration)
writer.endRecord()

proc readValue*(reader: var JsonReader[RestJson],
Expand Down Expand Up @@ -1529,6 +1598,8 @@ proc readValue*(reader: var JsonReader[RestJson],
Web3SignerRequestKind.SyncCommitteeSelectionProof
of "SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF":
Web3SignerRequestKind.SyncCommitteeContributionAndProof
of "VALIDATOR_REGISTRATION":
Web3SignerRequestKind.ValidatorRegistration
else:
reader.raiseUnexpectedValue("Unexpected `type` value")
)
Expand Down Expand Up @@ -1622,6 +1693,8 @@ proc readValue*(reader: var JsonReader[RestJson],
forkInfo: forkInfo, signingRoot: signingRoot, blck: data
)
of Web3SignerRequestKind.BlockV2:
# https://github.com/ConsenSys/web3signer/blob/41834a927088f1bde7a097e17d19e954d0058e54/core/src/main/resources/openapi-specs/eth2/signing/schemas.yaml#L421-L425 (branch v22.7.0)
# It's the "beacon_block" field even when it's not a block, but a header
if dataName != "beacon_block":
reader.raiseUnexpectedValue("Field `beacon_block` is missing")
if forkInfo.isNone():
Expand Down Expand Up @@ -1737,6 +1810,25 @@ proc readValue*(reader: var JsonReader[RestJson],
forkInfo: forkInfo, signingRoot: signingRoot,
syncCommitteeContributionAndProof: data
)
of Web3SignerRequestKind.ValidatorRegistration:
if dataName != "validator_registration":
reader.raiseUnexpectedValue(
"Field `validator_registration` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res =
decodeJsonString(Web3SignerValidatorRegistration, data.get())
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `validator_registration` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.ValidatorRegistration,
forkInfo: forkInfo, signingRoot: signingRoot,
validatorRegistration: data
)

## RemoteKeystoreStatus
proc writeValue*(writer: var JsonWriter[RestJson],
Expand Down
36 changes: 35 additions & 1 deletion beacon_chain/spec/eth2_apis/rest_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -483,10 +483,20 @@ type
serializedFieldName: "beacon_block_root".}: Eth2Digest
slot*: Slot

# https://consensys.github.io/web3signer/web3signer-eth2.html#operation/ETH2_SIGN
Web3SignerValidatorRegistration* = object
feeRecipient* {.
serializedFieldName: "fee_recipient".}: string
gasLimit* {.
serializedFieldName: "gas_limit".}: uint64
timestamp*: uint64
pubkey*: ValidatorPubKey

Web3SignerRequestKind* {.pure.} = enum
AggregationSlot, AggregateAndProof, Attestation, Block, BlockV2,
Deposit, RandaoReveal, VoluntaryExit, SyncCommitteeMessage,
SyncCommitteeSelectionProof, SyncCommitteeContributionAndProof
SyncCommitteeSelectionProof, SyncCommitteeContributionAndProof,
ValidatorRegistration

Web3SignerRequest* = object
signingRoot*: Option[Eth2Digest]
Expand Down Expand Up @@ -525,6 +535,10 @@ type
of Web3SignerRequestKind.SyncCommitteeContributionAndProof:
syncCommitteeContributionAndProof* {.
serializedFieldName: "contribution_and_proof".}: ContributionAndProof
of Web3SignerRequestKind.ValidatorRegistration:
validatorRegistration* {.
serializedFieldName: "validator_registration".}:
Web3SignerValidatorRegistration

GetBlockResponse* = DataEnclosedObject[phase0.SignedBeaconBlock]
GetStateResponse* = DataEnclosedObject[phase0.BeaconState]
Expand Down Expand Up @@ -771,6 +785,26 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
syncCommitteeContributionAndProof: data
)

from stew/byteutils import to0xHex

func init*(t: typedesc[Web3SignerRequest], fork: Fork,
genesis_validators_root: Eth2Digest,
data: ValidatorRegistrationV1,
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
): Web3SignerRequest =
Web3SignerRequest(
kind: Web3SignerRequestKind.ValidatorRegistration,
forkInfo: some(Web3SignerForkInfo(
fork: fork, genesis_validators_root: genesis_validators_root
)),
signingRoot: signingRoot,
validatorRegistration: Web3SignerValidatorRegistration(
feeRecipient: data.fee_recipient.data.to0xHex,
gasLimit: data.gas_limit,
timestamp: data.timestamp,
pubkey: data.pubkey)
)

func init*(t: typedesc[RestSyncCommitteeMessage],
slot: Slot,
beacon_block_root: Eth2Digest,
Expand Down
16 changes: 10 additions & 6 deletions beacon_chain/spec/forks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import
chronicles,
../extras,
"."/[block_id, eth2_merkleization, eth2_ssz_serialization, presets],
./datatypes/[phase0, altair, bellatrix]
./datatypes/[phase0, altair, bellatrix],
./mev/bellatrix_mev

export
extras, block_id, phase0, altair, bellatrix, eth2_merkleization,
Expand Down Expand Up @@ -107,7 +108,11 @@ type
of BeaconBlockFork.Altair: altairData*: altair.BeaconBlock
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock

Web3SignerForkedBeaconBlock* {.borrow: `.`} = distinct ForkedBeaconBlock
Web3SignerForkedBeaconBlock* = object
case kind*: BeaconBlockFork
of BeaconBlockFork.Phase0: phase0Data*: phase0.BeaconBlock
of BeaconBlockFork.Altair: altairData*: altair.BeaconBlock
of BeaconBlockFork.Bellatrix: bellatrixData*: BeaconBlockHeader

ForkedTrustedBeaconBlock* = object
case kind*: BeaconBlockFork
Expand Down Expand Up @@ -449,11 +454,10 @@ template withBlck*(
func proposer_index*(x: ForkedBeaconBlock): uint64 =
withBlck(x): blck.proposer_index

func hash_tree_root*(x: ForkedBeaconBlock): Eth2Digest =
func hash_tree_root*(x: ForkedBeaconBlock | Web3SignerForkedBeaconBlock):
Eth2Digest =
withBlck(x): hash_tree_root(blck)

func hash_tree_root*(x: Web3SignerForkedBeaconBlock): Eth2Digest {.borrow.}

template getForkedBlockField*(
x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
Expand Down Expand Up @@ -519,7 +523,7 @@ template withStateAndBlck*(
body

func toBeaconBlockHeader*(
blck: SomeForkyBeaconBlock): BeaconBlockHeader =
blck: SomeForkyBeaconBlock | BlindedBeaconBlock): BeaconBlockHeader =
## Reduce a given `BeaconBlock` to its `BeaconBlockHeader`.
BeaconBlockHeader(
slot: blck.slot,
Expand Down
4 changes: 2 additions & 2 deletions beacon_chain/spec/mev/bellatrix_mev.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type
signature*: ValidatorSig

# https://github.com/ethereum/builder-specs/blob/v0.2.0/specs/builder.md#builderbid
BuilderBid = object
BuilderBid* = object
header*: ExecutionPayloadHeader
value*: UInt256
pubkey*: ValidatorPubKey
Expand Down Expand Up @@ -64,5 +64,5 @@ const
DOMAIN_APPLICATION_BUILDER* = DomainType([byte 0x00, 0x00, 0x00, 0x01])

# https://github.com/ethereum/builder-specs/blob/v0.2.0/specs/validator.md#constants
EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION* = 1.Epoch
EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION* = 1
BUILDER_PROPOSAL_DELAY_TOLERANCE* = 1.seconds
1 change: 0 additions & 1 deletion beacon_chain/spec/mev/rest_bellatrix_mev_calls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ proc submitBlindedBlock*(body: SignedBlindedBeaconBlock
proc checkBuilderStatus*(): RestPlainResponse {.
rest, endpoint: "/eth/v1/builder/status",
meth: MethodGet.}
## https://github.com/ethereum/builder-specs/blob/v0.1.0/apis/builder/status.yaml
## https://github.com/ethereum/builder-specs/blob/v0.2.0/apis/builder/status.yaml
Loading