236 lines
6.7 KiB
Nim
236 lines
6.7 KiB
Nim
import
|
|
macros, strutils, parseutils, tables,
|
|
stew/endians2
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
export
|
|
toBytesBE
|
|
|
|
type
|
|
Slot* = distinct uint64
|
|
Epoch* = distinct uint64
|
|
Version* = distinct array[4, byte]
|
|
|
|
PresetValue* {.pure.} = enum
|
|
BASE_REWARD_FACTOR
|
|
BLS_WITHDRAWAL_PREFIX
|
|
CHURN_LIMIT_QUOTIENT
|
|
DEPOSIT_CONTRACT_ADDRESS
|
|
DOMAIN_AGGREGATE_AND_PROOF
|
|
DOMAIN_BEACON_ATTESTER
|
|
DOMAIN_BEACON_PROPOSER
|
|
DOMAIN_DEPOSIT
|
|
DOMAIN_RANDAO
|
|
DOMAIN_SELECTION_PROOF
|
|
DOMAIN_VOLUNTARY_EXIT
|
|
EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE
|
|
EFFECTIVE_BALANCE_INCREMENT
|
|
EJECTION_BALANCE
|
|
EPOCHS_PER_ETH1_VOTING_PERIOD
|
|
EPOCHS_PER_HISTORICAL_VECTOR
|
|
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION
|
|
EPOCHS_PER_SLASHINGS_VECTOR
|
|
ETH1_FOLLOW_DISTANCE
|
|
GENESIS_FORK_VERSION
|
|
GENESIS_DELAY
|
|
HISTORICAL_ROOTS_LIMIT
|
|
HYSTERESIS_DOWNWARD_MULTIPLIER
|
|
HYSTERESIS_QUOTIENT
|
|
HYSTERESIS_UPWARD_MULTIPLIER
|
|
INACTIVITY_PENALTY_QUOTIENT
|
|
MAX_ATTESTATIONS
|
|
MAX_ATTESTER_SLASHINGS
|
|
MAX_COMMITTEES_PER_SLOT
|
|
MAX_DEPOSITS
|
|
MAX_EFFECTIVE_BALANCE
|
|
MAX_EPOCHS_PER_CROSSLINK
|
|
MAX_PROPOSER_SLASHINGS
|
|
MAX_SEED_LOOKAHEAD
|
|
MAX_VALIDATORS_PER_COMMITTEE
|
|
MAX_VOLUNTARY_EXITS
|
|
MIN_ATTESTATION_INCLUSION_DELAY
|
|
MIN_DEPOSIT_AMOUNT
|
|
MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
|
|
MIN_GENESIS_TIME
|
|
MIN_PER_EPOCH_CHURN_LIMIT
|
|
MIN_SEED_LOOKAHEAD
|
|
MIN_SLASHING_PENALTY_QUOTIENT
|
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
PROPOSER_REWARD_QUOTIENT
|
|
RANDOM_SUBNETS_PER_VALIDATOR
|
|
SAFE_SLOTS_TO_UPDATE_JUSTIFIED
|
|
SECONDS_PER_ETH1_BLOCK
|
|
SECONDS_PER_SLOT
|
|
SHARD_COMMITTEE_PERIOD
|
|
SHUFFLE_ROUND_COUNT
|
|
SLOTS_PER_EPOCH
|
|
SLOTS_PER_HISTORICAL_ROOT
|
|
TARGET_AGGREGATORS_PER_COMMITTEE
|
|
TARGET_COMMITTEE_SIZE
|
|
VALIDATOR_REGISTRY_LIMIT
|
|
WHISTLEBLOWER_REWARD_QUOTIENT
|
|
|
|
RuntimePreset* = object
|
|
GENESIS_FORK_VERSION*: Version
|
|
GENESIS_DELAY*: uint64
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT*: uint64
|
|
MIN_GENESIS_TIME*: uint64
|
|
|
|
PresetFile* = object
|
|
values*: Table[PresetValue, TaintedString]
|
|
missingValues*: set[PresetValue]
|
|
|
|
PresetFileError* = object of CatchableError
|
|
|
|
const
|
|
const_preset* {.strdefine.} = "mainnet"
|
|
|
|
runtimeValues* = {
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT,
|
|
MIN_GENESIS_TIME,
|
|
GENESIS_FORK_VERSION,
|
|
GENESIS_DELAY,
|
|
}
|
|
|
|
# These constants cannot really be overriden in a preset.
|
|
# If we encounter them, we'll just ignore the preset value.
|
|
ignoredValues* = {
|
|
# The deposit contract address is loaded through a dedicated
|
|
# metadata file. It would break the property we are exploiting
|
|
# right now that all preset values can be parsed as uint64
|
|
DEPOSIT_CONTRACT_ADDRESS,
|
|
|
|
# These are defined as an enum in datatypes.nim:
|
|
DOMAIN_BEACON_PROPOSER,
|
|
DOMAIN_BEACON_ATTESTER,
|
|
DOMAIN_RANDAO,
|
|
DOMAIN_DEPOSIT,
|
|
DOMAIN_VOLUNTARY_EXIT,
|
|
DOMAIN_SELECTION_PROOF,
|
|
DOMAIN_AGGREGATE_AND_PROOF,
|
|
}
|
|
|
|
presetValueTypes* = {
|
|
BLS_WITHDRAWAL_PREFIX: "byte",
|
|
GENESIS_FORK_VERSION: "Version",
|
|
}.toTable
|
|
|
|
func parse*(T: type uint64, input: string): T
|
|
{.raises: [ValueError, Defect].} =
|
|
var res: BiggestUInt
|
|
if input.len > 2 and input[0] == '0' and input[1] == 'x':
|
|
if parseHex(input, res) != input.len:
|
|
raise newException(ValueError, "The constant value should be a valid hex integer")
|
|
else:
|
|
if parseBiggestUInt(input, res) != input.len:
|
|
raise newException(ValueError, "The constant value should be a valid unsigned integer")
|
|
|
|
result = uint64(res)
|
|
|
|
template parse*(T: type byte, input: string): T =
|
|
byte parse(uint64, input)
|
|
|
|
template parse*(T: type int, input: string): T =
|
|
# TODO: remove this
|
|
int parse(uint64, input)
|
|
|
|
proc parse*(T: type Version, input: string): T
|
|
{.raises: [ValueError, Defect].} =
|
|
Version toBytesBE(uint32 parse(uint64, input))
|
|
|
|
template parse*(T: type Slot, input: string): T =
|
|
Slot parse(uint64, input)
|
|
|
|
template getType*(presetValue: PresetValue): string =
|
|
presetValueTypes.getOrDefault(presetValue, "uint64")
|
|
|
|
template toUInt64*(v: Version): uint64 =
|
|
fromBytesBE(uint64, array[4, byte](v))
|
|
|
|
template entireSet(T: type enum): untyped =
|
|
{low(T) .. high(T)}
|
|
|
|
proc readPresetFile*(path: string): PresetFile
|
|
{.raises: [IOError, PresetFileError, Defect].} =
|
|
var
|
|
lineNum = 0
|
|
presetValues = ignoredValues
|
|
|
|
template lineinfo: string =
|
|
try: "$1($2) " % [path, $lineNum]
|
|
except ValueError: path
|
|
|
|
template fail(msg) =
|
|
raise newException(PresetFileError, lineinfo() & msg)
|
|
|
|
for line in splitLines(readFile(path)):
|
|
inc lineNum
|
|
if line.len == 0 or line[0] == '#': continue
|
|
|
|
var lineParts = line.split(":")
|
|
if lineParts.len != 2:
|
|
fail "Invalid syntax: A preset file should include only assignments in the form 'ConstName: Value'"
|
|
|
|
let value = try: parseEnum[PresetValue](lineParts[0])
|
|
except ValueError: fail "Unrecognized constant in a preset: " & lineParts[0]
|
|
|
|
if value in ignoredValues: continue
|
|
presetValues.incl value
|
|
result.values.add value, lineParts[1].strip
|
|
|
|
result.missingValues = PresetValue.entireSet - presetValues
|
|
|
|
const
|
|
mainnetRuntimePreset* = RuntimePreset(
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384,
|
|
MIN_GENESIS_TIME: 1578009600,
|
|
GENESIS_FORK_VERSION: Version [byte 0, 0, 0, 0],
|
|
GENESIS_DELAY: 172800)
|
|
|
|
minimalRuntimePreset* = RuntimePreset(
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64,
|
|
MIN_GENESIS_TIME: 1578009600,
|
|
GENESIS_FORK_VERSION: Version [byte 0, 0, 0, 1],
|
|
GENESIS_DELAY: 300)
|
|
|
|
when const_preset == "mainnet":
|
|
template defaultRuntimePreset*: auto = mainnetRuntimePreset
|
|
import ./presets/v0_12_1/mainnet
|
|
export mainnet
|
|
|
|
elif const_preset == "minimal":
|
|
template defaultRuntimePreset*: auto = minimalRuntimePreset
|
|
import ./presets/v0_12_1/minimal
|
|
export minimal
|
|
|
|
else:
|
|
macro createConstantsFromPreset*(path: static string): untyped =
|
|
result = newStmtList()
|
|
|
|
let preset = try: readPresetFile(path)
|
|
except CatchableError as err:
|
|
error err.msg # TODO: This should be marked as noReturn
|
|
return
|
|
|
|
for name, value in preset.values:
|
|
var value = string value
|
|
if presetValueTypes.hasKey(name):
|
|
let typ = presetValueTypes[name]
|
|
value = typ & "(" & value & ")"
|
|
|
|
result.add parseStmt("const $1* {.intdefine.} = $2" % [$name, value])
|
|
|
|
if preset.missingValues.card > 0:
|
|
warning "Missing constants in preset: " & $preset.missingValues
|
|
|
|
createConstantsFromPreset const_preset
|
|
|
|
const defaultRuntimePreset* = RuntimePreset(
|
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: MIN_GENESIS_ACTIVE_VALIDATOR_COUNT,
|
|
MIN_GENESIS_TIME: MIN_GENESIS_TIME,
|
|
GENESIS_FORK_VERSION: GENESIS_FORK_VERSION,
|
|
GENESIS_DELAY: GENESIS_DELAY)
|
|
|