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

ncli verifyDeposit: a simple helper for inspecting deposit events #3855

Open
wants to merge 1 commit into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 2 additions & 14 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ import
./spec/datatypes/base,
./networking/network_metadata,
./validators/slashing_protection_common,
./conf/eth2_types_confutils_defs,
./filepath

from consensus_object_pools/block_pools_types_light_client
import LightClientDataImportMode

export
uri, nat, enr,
uri, nat, enr, eth2_types_confutils_defs,
defaultEth2TcpPort, enabledLogLevel, ValidIpAddress,
defs, parseCmdArg, completeCmdArg, network_metadata,
network, BlockHashOrNumber,
Expand Down Expand Up @@ -918,13 +919,6 @@ proc createDumpDirs*(config: BeaconNodeConf) =
warn "Could not create dump directory",
path = config.dumpDirOutgoing, err = ioErrorMsg(res.error)

func parseCmdArg*(T: type Eth2Digest, input: string): T
{.raises: [ValueError, Defect].} =
Eth2Digest.fromHex(input)

func completeCmdArg*(T: type Eth2Digest, input: string): seq[string] =
return @[]

func parseCmdArg*(T: type GraffitiBytes, input: string): T
{.raises: [ValueError, Defect].} =
GraffitiBytes.init(input)
Expand All @@ -950,12 +944,6 @@ func parseCmdArg*(T: type PubKey0x, input: string): T
{.raises: [ValueError, Defect].} =
PubKey0x(hexToPaddedByteArray[RawPubKeySize](input))

func parseCmdArg*(T: type ValidatorPubKey, input: string): T
{.raises: [ValueError, Defect].} =
let res = ValidatorPubKey.fromHex(input)
if res.isErr(): raise (ref ValueError)(msg: $res.error())
res.get()

func completeCmdArg*(T: type PubKey0x, input: string): seq[string] =
return @[]

Expand Down
27 changes: 27 additions & 0 deletions beacon_chain/conf/eth2_types_confutils_defs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import
../spec/[crypto, digest]

func parseCmdArg*(T: type Eth2Digest, input: string): T
{.raises: [ValueError, Defect].} =
Eth2Digest.fromHex(input)

func completeCmdArg*(T: type Eth2Digest, input: string): seq[string] =
return @[]

func parseCmdArg*(T: type ValidatorPubKey, input: string): T
{.raises: [ValueError, Defect].} =
let res = ValidatorPubKey.fromHex(input)
if res.isErr(): raise (ref ValueError)(msg: $res.error())
res.get()

func completeCmdArg*(T: type ValidatorPubKey, input: string): seq[string] =
return @[]

func parseCmdArg*(T: type ValidatorSig, input: string): T
{.raises: [ValueError, Defect].} =
let res = ValidatorSig.fromHex(input)
if res.isErr(): raise (ref ValueError)(msg: $res.error())
res.get()

func completeCmdArg*(T: type ValidatorSig, input: string): seq[string] =
return @[]
26 changes: 26 additions & 0 deletions beacon_chain/eth1/deposit_contract_abi.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import
web3, web3/ethtypes

export
web3, ethtypes

type
PubKeyBytes* = DynamicBytes[48, 48]
WithdrawalCredentialsBytes* = DynamicBytes[32, 32]
SignatureBytes* = DynamicBytes[96, 96]
Int64LeBytes* = DynamicBytes[8, 8]

contract(DepositContract):
proc deposit(pubkey: PubKeyBytes,
withdrawalCredentials: WithdrawalCredentialsBytes,
signature: SignatureBytes,
deposit_data_root: FixedBytes[32])

proc get_deposit_root(): FixedBytes[32]
proc get_deposit_count(): Int64LeBytes

proc DepositEvent(pubkey: PubKeyBytes,
withdrawalCredentials: WithdrawalCredentialsBytes,
amount: Int64LeBytes,
signature: SignatureBytes,
index: Int64LeBytes) {.event.}
22 changes: 1 addition & 21 deletions beacon_chain/eth1/eth1_monitor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import
../networking/network_metadata,
../consensus_object_pools/block_pools_types,
".."/[beacon_chain_db, beacon_node_status, beacon_clock],
./deposit_contract_abi,
./merkle_minimal

from std/times import getTime, inSeconds, initTime, `-`
Expand All @@ -32,27 +33,6 @@ export
logScope:
topics = "eth1"

type
PubKeyBytes = DynamicBytes[48, 48]
WithdrawalCredentialsBytes = DynamicBytes[32, 32]
SignatureBytes = DynamicBytes[96, 96]
Int64LeBytes = DynamicBytes[8, 8]

contract(DepositContract):
proc deposit(pubkey: PubKeyBytes,
withdrawalCredentials: WithdrawalCredentialsBytes,
signature: SignatureBytes,
deposit_data_root: FixedBytes[32])

proc get_deposit_root(): FixedBytes[32]
proc get_deposit_count(): Int64LeBytes

proc DepositEvent(pubkey: PubKeyBytes,
withdrawalCredentials: WithdrawalCredentialsBytes,
amount: Int64LeBytes,
signature: SignatureBytes,
index: Int64LeBytes) {.event.}

const
web3Timeouts = 60.seconds
hasDepositRootChecks = defined(has_deposit_root_checks)
Expand Down
104 changes: 91 additions & 13 deletions ncli/ncli.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import
../beacon_chain/spec/eth2_apis/eth2_rest_serialization,
../beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
../beacon_chain/spec/[
eth2_ssz_serialization, forks, helpers, state_transition],
../beacon_chain/networking/network_metadata
eth2_ssz_serialization, forks, helpers, state_transition, signatures],
../beacon_chain/networking/network_metadata,
../beacon_chain/conf/eth2_types_confutils_defs,
../beacon_chain/eth1/deposit_contract_abi
Copy link
Member

Choose a reason for hiding this comment

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

this import is quite unfortunate: it brings in the entirerty of web3 which transitively imports lots and lots of completely irrelevant stuff just to get access to a trivial byte converter


type
Cmd* = enum
hashTreeRoot = "Compute hash tree root of SSZ object"
pretty = "Pretty-print SSZ object"
transition = "Run state transition function"
slots = "Apply empty slots"
verifyDeposit = "Verify deposit"

NcliConf* = object
eth2Network* {.
Expand All @@ -28,29 +31,29 @@ type
of hashTreeRoot:
htrKind* {.
argument
desc: "kind of SSZ object: attester_slashing, attestation, signed_block, block, block_body, block_header, deposit, deposit_data, eth1_data, state, proposer_slashing, or voluntary_exit"}: string
desc: "kind of SSZ object: attester_slashing, attestation, signed_block, block, block_body, block_header, deposit, deposit_data, eth1_data, state, proposer_slashing, or voluntary_exit" .}: string

htrFile* {.
argument
desc: "filename of SSZ or JSON-encoded object of which to compute hash tree root"}: string
desc: "filename of SSZ or JSON-encoded object of which to compute hash tree root" .}: string

of pretty:
prettyKind* {.
argument
desc: "kind of SSZ object: attester_slashing, attestation, signed_block, block, block_body, block_header, deposit, deposit_data, eth1_data, state, proposer_slashing, or voluntary_exit"}: string
desc: "kind of SSZ object: attester_slashing, attestation, signed_block, block, block_body, block_header, deposit, deposit_data, eth1_data, state, proposer_slashing, or voluntary_exit" .}: string

prettyFile* {.
argument
desc: "filename of SSZ or JSON-encoded object to pretty-print"}: string
desc: "filename of SSZ or JSON-encoded object to pretty-print" .}: string

of transition:
preState* {.
argument
desc: "State to which to apply specified block"}: string
desc: "State to which to apply specified block" .}: string

blck* {.
argument
desc: "Block to apply to preState"}: string
desc: "Block to apply to preState" .}: string

postState* {.
argument
Expand All @@ -59,20 +62,39 @@ type
verifyStateRoot* {.
argument
desc: "Verify state root (default true)"
defaultValue: true}: bool
defaultValue: true .}: bool

of slots:
preState2* {.
argument
desc: "State to which to apply specified block"}: string
desc: "State to which to apply specified block" .}: string

slot* {.
argument
desc: "Block to apply to preState"}: uint64
desc: "Block to apply to preState" .}: uint64

postState2* {.
argument
desc: "Filename of state resulting from applying blck to preState"}: string
desc: "Filename of state resulting from applying blck to preState" .}: string

of verifyDeposit:
pubkey* {.
desc: "The validator's public BLS signing key" .}: Option[ValidatorPubKey]

withdrawalCredentials* {.
desc: "The validator's withdrawal credentials (The prefixed 32 bytes form mandated by the spec)"
name: "withdrawal-credentials" .}: Option[Eth2Digest]

amount* {.
defaultValue: 32000000000
desc: "The deposit amount in gwei" .}: Gwei

signature* {.
desc: "The deposit signature" .}: Option[ValidatorSig]

depositData* {.
argument
desc: "Deposit event data from the official deposit contract in ABI form (hex-encoded)" .}: Option[string]

template saveSSZFile(filename: string, value: ForkedHashedBeaconState) =
case value.kind:
Expand Down Expand Up @@ -168,7 +190,6 @@ proc doSSZ(conf: NcliConf) =
else:
raiseAssert "doSSZ() only implements hashTreeRoot and pretty commands"


case kind
of "attester_slashing": printit(AttesterSlashing)
of "attestation": printit(Attestation)
Expand All @@ -191,6 +212,62 @@ proc doSSZ(conf: NcliConf) =
of "proposer_slashing": printit(ProposerSlashing)
of "voluntary_exit": printit(VoluntaryExit)

template init[N: static int](T: type DynamicBytes[N, N]): T =
T newSeq[byte](N)

proc doVerifyDeposit(conf: NcliConf) =
let cfg = getRuntimeConfig(conf.eth2Network)

let deposit = if conf.depositData.isSome:
let eventBytes = conf.depositData.get.substr(10)
var
pubkey = init deposit_contract_abi.PubKeyBytes
withdrawalCredentials = init WithdrawalCredentialsBytes
amount = init Int64LeBytes
signature = init SignatureBytes
index = init Int64LeBytes

echo eventBytes

try:
var offset = 0
offset += decode(eventBytes, offset, pubkey)
offset += decode(eventBytes, offset, withdrawalCredentials)
offset += decode(eventBytes, offset, amount)
offset += decode(eventBytes, offset, signature)
except CatchableError as err:
echo "Invalid deposit event: ", err.msg
quit 1

DepositData(
pubkey: ValidatorPubKey.init(pubkey.toArray),
withdrawal_credentials: Eth2Digest(data: withdrawalCredentials.toArray),
amount: bytes_to_uint64(amount.toArray),
signature: ValidatorSig.init(signature.toArray))
else:
var missingParams: seq[string]

if conf.pubkey.isNone: missingParams.add "pubkey"
if conf.withdrawalCredentials.isNone: missingParams.add "withdrawal-credentials"
if conf.signature.isNone: missingParams.add "singature"

if missingParams.len > 0:
echo "Please supply the hex-encoded deposit data as an argument or provide all of the following parameters:"
for param in missingParams:
echo " --", param
quit 1

DepositData(
pubkey: conf.pubkey.get,
withdrawal_credentials: conf.withdrawalCredentials.get,
amount: conf.amount,
signature: conf.signature.get)

let status = if verify_deposit_signature(cfg, deposit): "valid"
else: "invalid"

echo "The deposit is ", status

when isMainModule:
let
conf = NcliConf.load()
Expand All @@ -200,3 +277,4 @@ when isMainModule:
of pretty: doSSZ(conf)
of transition: doTransition(conf)
of slots: doSlots(conf)
of verifyDeposit: doVerifyDeposit(conf)