Add an option for graffiti customization

This commit is contained in:
Zahary Karadjov 2020-06-29 20:30:19 +03:00 committed by zah
parent 853bd5b799
commit 93b04bc214
16 changed files with 98 additions and 34 deletions

View File

@ -134,9 +134,9 @@ func enrForkIdFromState(state: BeaconState): ENRForkID =
next_fork_version: forkVer,
next_fork_epoch: FAR_FUTURE_EPOCH)
proc init*(
T: type BeaconNode, rng: ref BrHmacDrbgContext,
conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
proc init*(T: type BeaconNode,
rng: ref BrHmacDrbgContext,
conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
let
netKeys = getPersistentNetKeys(rng[], conf)
nickname = if conf.nodeName == "auto": shortForm(netKeys)
@ -237,6 +237,8 @@ proc init*(
var res = BeaconNode(
nickname: nickname,
graffitiBytes: if conf.graffiti.isSome: conf.graffiti.get.GraffitiBytes
else: defaultGraffitiBytes(),
network: network,
netKeys: netKeys,
db: db,
@ -635,11 +637,6 @@ proc currentSlot(node: BeaconNode): Slot =
proc connectedPeersCount(node: BeaconNode): int =
nbc_peers.value.int
func fromJson(n: JsonNode; argName: string; result: var Slot) =
var i: int
fromJson(n, argName, i)
result = Slot(i)
proc installBeaconApiHandlers(rpcServer: RpcServer, node: BeaconNode) =
rpcServer.rpc("getBeaconHead") do () -> Slot:
return node.blockPool.head.blck.slot

View File

@ -32,6 +32,7 @@ type
BeaconNode* = ref object
nickname*: string
graffitiBytes*: GraffitiBytes
network*: Eth2Node
netKeys*: KeyPair
requestManager*: RequestManager

View File

@ -4,8 +4,8 @@ import
os, options,
chronicles, chronicles/options as chroniclesOptions,
confutils, confutils/defs, confutils/std/net,
json_serialization, web3/ethtypes,
network_metadata, spec/[crypto, keystore, digest]
stew/byteutils, json_serialization, web3/ethtypes,
network_metadata, spec/[crypto, keystore, digest, datatypes]
export
defs, enabledLogLevel, parseCmdArg, completeCmdArg,
@ -142,6 +142,11 @@ type
"If you set this to 'auto', a persistent automatically generated ID will be selected for each --data-dir folder"
name: "node-name" }: string
graffiti* {.
desc: "The graffiti value that will appear in proposed blocks. " &
"You can use a 0x-prefixed hex encoded string to specify raw bytes."
name: "graffiti" }: Option[GraffitiBytes]
verifyFinalization* {.
defaultValue: false
desc: "Specify whether to verify finalization occurs on schedule, for testing"
@ -361,6 +366,11 @@ type
defaultValue: VCNoCommand }: VCStartUpCmd
of VCNoCommand:
graffiti* {.
desc: "The graffiti value that will appear in proposed blocks. " &
"You can use a 0x-prefixed hex encoded string to specify raw bytes."
name: "graffiti" }: Option[GraffitiBytes]
rpcPort* {.
defaultValue: defaultEth2RpcPort
desc: "HTTP port of the server to connect to for RPC"
@ -431,6 +441,13 @@ func parseCmdArg*(T: type Eth1BlockHash, input: TaintedString): T
func completeCmdArg*(T: type Eth1BlockHash, input: TaintedString): seq[string] =
return @[]
func parseCmdArg*(T: type GraffitiBytes, input: TaintedString): T
{.raises: [ValueError, Defect].} =
GraffitiBytes.init(string input)
func completeCmdArg*(T: type GraffitiBytes, input: TaintedString): seq[string] =
return @[]
func parseCmdArg*(T: type WalletName, input: TaintedString): T
{.raises: [ValueError, Defect].} =
if input.len == 0:

View File

@ -10,6 +10,7 @@ import
spec/[datatypes, crypto]
proc fromJson*(n: JsonNode, argName: string, result: var ValidatorPubKey) =
n.kind.expect(JString, argName)
result = ValidatorPubKey.fromHex(n.getStr()).tryGet()
proc `%`*(pubkey: ValidatorPubKey): JsonNode =
@ -26,12 +27,14 @@ proc fromJson*(n: JsonNode, argName: string, result: var BitList) =
proc `%`*(bitlist: BitList): JsonNode = %(seq[byte](BitSeq(bitlist)))
proc fromJson*(n: JsonNode, argName: string, result: var ValidatorSig) =
n.kind.expect(JString, argName)
result = ValidatorSig.fromHex(n.getStr()).tryGet()
proc `%`*(value: ValidatorSig): JsonNode =
result = newJString($value)
proc fromJson*(n: JsonNode, argName: string, result: var Version) =
n.kind.expect(JString, argName)
hexToByteArray(n.getStr(), array[4, byte](result))
proc `%`*(value: Version): JsonNode =
@ -46,5 +49,12 @@ genFromJsonForIntType(Epoch)
genFromJsonForIntType(Slot)
genFromJsonForIntType(CommitteeIndex)
template `%`*(value: GraffitiBytes): JsonNode =
%($value)
proc fromJson*(n: JsonNode, argName: string, value: var GraffitiBytes) =
n.kind.expect(JString, argName)
value = GraffitiBytes.init n.getStr()
proc `%`*(value: CommitteeIndex): JsonNode =
result = newJInt(value.int)

View File

@ -25,7 +25,7 @@ import
macros, hashes, json, strutils, tables, typetraits,
stew/[byteutils], chronicles,
json_serialization/types as jsonTypes,
../ssz/types as sszTypes, ./crypto, ./digest, ./presets
../version, ../ssz/types as sszTypes, ./crypto, ./digest, ./presets
export
sszTypes, presets
@ -257,11 +257,13 @@ type
object_root*: Eth2Digest
domain*: Domain
GraffitiBytes* = distinct array[32, byte]
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#beaconblockbody
BeaconBlockBody* = object
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
graffiti*: Eth2Digest # TODO make that raw bytes
graffiti*: GraffitiBytes
# Operations
proposer_slashings*: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
@ -273,7 +275,7 @@ type
TrustedBeaconBlockBody* = object
randao_reveal*: TrustedSig
eth1_data*: Eth1Data
graffiti*: Eth2Digest # TODO make that raw bytes
graffiti*: GraffitiBytes
# Operations
proposer_slashings*: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
@ -676,6 +678,41 @@ import json_serialization
export json_serialization
export writeValue, readValue
func `$`*(value: GraffitiBytes): string =
strip(string.fromBytes(distinctBase value), chars = Whitespace + {'\0'})
func init*(T: type GraffitiBytes, input: string): GraffitiBytes
{.raises: [ValueError, Defect].} =
if input.len > 2 and input[0] == '0' and input[1] == 'x':
if input.len > sizeof(GraffitiBytes) * 2 + 2:
raise newException(ValueError, "The graffiti bytes should be less than 32")
elif input.len mod 2 != 0:
raise newException(ValueError, "The graffiti hex string should have an even length")
hexToByteArray(string input, distinctBase(result))
else:
if input.len > 32:
raise newException(ValueError, "The graffiti value should be 32 characters or less")
distinctBase(result)[0 ..< input.len] = toBytes(input)
func defaultGraffitiBytes*(): GraffitiBytes =
let graffityBytes = toBytes("Nimbus " & fullVersionStr)
distinctBase(result)[0 ..< graffityBytes.len] = graffityBytes
proc writeValue*(w: var JsonWriter, value: GraffitiBytes)
{.raises: [IOError, Defect].} =
w.writeValue $value
template `==`*(lhs, rhs: GraffitiBytes): bool =
distinctBase(lhs) == distinctBase(rhs)
proc readValue*(r: var JsonReader, T: type GraffitiBytes): T
{.raises: [IOError, SerializationError, Defect].} =
try:
init(GraffitiBytes, r.readValue(string))
except ValueError as err:
r.raiseUnexpectedValue err.msg
static:
# Sanity checks - these types should be trivial enough to copy with memcpy
doAssert supportsCopyMem(Validator)

View File

@ -10,7 +10,7 @@ import
# calls that return a bool are actually without a return type in the main REST API
# spec but nim-json-rpc requires that all RPC calls have a return type.
proc get_v1_validator_block(slot: Slot, graffiti: Eth2Digest, randao_reveal: ValidatorSig): BeaconBlock
proc get_v1_validator_block(slot: Slot, graffiti: GraffitiBytes, randao_reveal: ValidatorSig): BeaconBlock
proc post_v1_validator_block(body: SignedBeaconBlock): bool

View File

@ -273,7 +273,7 @@ proc makeBeaconBlock*(
parent_root: Eth2Digest,
randao_reveal: ValidatorSig,
eth1_data: Eth1Data,
graffiti: Eth2Digest,
graffiti: GraffitiBytes,
attestations: seq[Attestation],
deposits: seq[Deposit],
rollback: RollbackHashedProc,

View File

@ -41,6 +41,11 @@ func fromSszBytes*(T: type Eth2Digest, data: openarray[byte]): T {.raisesssz.} =
raiseIncorrectSize T
copyMem(result.data.addr, unsafeAddr data[0], sizeof(result.data))
func fromSszBytes*(T: type GraffitiBytes, data: openarray[byte]): T {.raisesssz.} =
if data.len != sizeof(result):
raiseIncorrectSize T
copyMem(result.addr, unsafeAddr data[0], sizeof(result))
template fromSszBytes*(T: type Slot, bytes: openarray[byte]): Slot =
Slot fromSszBytes(uint64, bytes)

View File

@ -15,5 +15,5 @@ template toSszType*(x: auto): auto =
when x is Slot|Epoch|ValidatorIndex: uint64(x)
elif x is Eth2Digest: x.data
elif x is BlsCurveType: toRaw(x)
elif x is ForkDigest|Version: distinctBase(x)
elif x is ForkDigest|Version|GraffitiBytes: distinctBase(x)
else: x

View File

@ -300,10 +300,9 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) =
return state
rpcServer.rpc("get_v1_validator_block") do (
slot: Slot, graffiti: Eth2Digest, randao_reveal: ValidatorSig) -> BeaconBlock:
slot: Slot, graffiti: GraffitiBytes, randao_reveal: ValidatorSig) -> BeaconBlock:
debug "get_v1_validator_block", slot = slot
let head = node.doChecksAndGetCurrentHead(slot)
let proposer = node.blockPool.getProposer(head, slot)
if proposer.isNone():
raise newException(CatchableError, "could not retrieve block for slot: " & $slot)

View File

@ -17,7 +17,7 @@ import
# Local modules
spec/[datatypes, digest, crypto, helpers, network],
conf, time,
conf, time, version,
eth2_network, eth2_discovery, validator_pool, beacon_node_types,
nimbus_binary_common,
version, ssz/merkleization,
@ -36,6 +36,7 @@ createRpcSigs(RpcClient, sourceDir / "spec" / "eth2_apis" / "beacon_callsigs.nim
type
ValidatorClient = ref object
config: ValidatorClientConf
graffitiBytes: GraffitiBytes
client: RpcHttpClient
beaconClock: BeaconClock
attachedValidators: ValidatorPool
@ -136,10 +137,8 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
let randao_reveal = validator.genRandaoReveal(
vc.fork, vc.beaconGenesis.genesis_validators_root, slot)
var graffiti: Eth2Digest
graffiti.data[0..<5] = toBytes("quack")
var newBlock = SignedBeaconBlock(
message: await vc.client.get_v1_validator_block(slot, graffiti, randao_reveal)
message: await vc.client.get_v1_validator_block(slot, vc.graffitiBytes, randao_reveal)
)
let blockRoot = hash_tree_root(newBlock.message)
@ -212,8 +211,9 @@ programMain:
var vc = ValidatorClient(
config: config,
client: newRpcHttpClient()
)
client: newRpcHttpClient(),
graffitiBytes: if config.graffiti.isSome: config.graffiti.get.GraffitiBytes
else: defaultGraffitiBytes())
# load all the validators from the data dir into memory
for curr in vc.config.validatorKeys:

View File

@ -10,7 +10,7 @@ import
os, tables, strutils,
# Nimble packages
stew/[byteutils, objects], stew/shims/macros,
stew/[objects], stew/shims/macros,
chronos, metrics, json_rpc/[rpcserver, jsonmarshal],
chronicles,
json_serialization/std/[options, sets, net], serialization/errors,
@ -160,7 +160,7 @@ type
proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
val_info: ValidatorInfoForMakeBeaconBlock,
validator_index: ValidatorIndex,
graffiti: Eth2Digest,
graffiti: GraffitiBytes,
head: BlockRef,
slot: Slot):
tuple[message: Option[BeaconBlock], fork: Fork, genesis_validators_root: Eth2Digest] =
@ -271,11 +271,8 @@ proc proposeBlock(node: BeaconNode,
cat = "fastforward"
return head
var graffiti: Eth2Digest
graffiti.data[0..<5] = toBytes("quack")
let valInfo = ValidatorInfoForMakeBeaconBlock(kind: viValidator, validator: validator)
let beaconBlockTuple = makeBeaconBlockForHeadAndSlot(node, valInfo, validator_index, graffiti, head, slot)
let beaconBlockTuple = makeBeaconBlockForHeadAndSlot(node, valInfo, validator_index, node.graffitiBytes, head, slot)
if not beaconBlockTuple.message.isSome():
return head # already logged elsewhere!
var

View File

@ -37,3 +37,4 @@ func shortNimBanner*(): string =
tmp[0] & " (" & gitHash & ")"
else:
tmp[0]

View File

@ -114,7 +114,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
head.root,
privKey.genRandaoReveal(state.fork, state.genesis_validators_root, slot),
eth1data,
Eth2Digest(),
default(GraffitiBytes),
attPool.getAttestationsForBlock(state),
@[],
noRollback,

View File

@ -204,7 +204,7 @@ suiteReport "Attestation pool processing" & preset():
let
b11 = makeTestBlock(state.data, blockPool[].tail.root, cache,
graffiti = Eth2Digest(data: [1'u8, 0, 0, 0 ,0 ,0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
graffiti = GraffitiBytes [1'u8, 0, 0, 0 ,0 ,0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
)
b11Root = hash_tree_root(b11.message)
b11Add = blockpool[].addRawBlock(b11Root, b11) do (validBlock: BlockRef):

View File

@ -91,7 +91,7 @@ proc addTestBlock*(
eth1_data = Eth1Data(),
attestations = newSeq[Attestation](),
deposits = newSeq[Deposit](),
graffiti = Eth2Digest(),
graffiti = default(GraffitiBytes),
flags: set[UpdateFlag] = {}): SignedBeaconBlock =
# Create and add a block to state - state will advance by one slot!
advance_slot(state, flags, cache)
@ -140,7 +140,7 @@ proc makeTestBlock*(
eth1_data = Eth1Data(),
attestations = newSeq[Attestation](),
deposits = newSeq[Deposit](),
graffiti = Eth2Digest(),
graffiti = default(GraffitiBytes),
flags: set[UpdateFlag] = {}): SignedBeaconBlock =
# Create a block for `state.slot + 1` - like a block proposer would do!
# It's a bit awkward - in order to produce a block for N+1, we need to