Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions beacon_chain/beacon_clock.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,28 @@ proc init*(
T: type BeaconClock,
timeParams: TimeParams,
genesis_time: uint64): Opt[T] =
if not timeParams.isValid:
return Opt.none(BeaconClock)

let
MIN_GENESIS_TIME = GENESIS_SLOT * timeParams.SLOT_DURATION.seconds.uint64
MAX_GENESIS_TIME =
# Since we'll be converting beacon time differences to nanoseconds,
# the time can't be outrageously far from now
getTime().toUnix().uint64 +
100'u64 * 365'u64 * 24'u64 * 60'u64 * 60'u64
if timeParams.SLOT_DURATION notin MIN_SLOT_DURATION .. MAX_SLOT_DURATION or
genesis_time notin MIN_GENESIS_TIME .. MAX_GENESIS_TIME:
Opt.none(BeaconClock)
else:
let
unixGenesis = fromUnix(genesis_time.int64)
# GENESIS_SLOT offsets slot time, but to simplify calculations, we apply
# that offset to genesis instead of applying it at every time conversion
unixGenesisOffset = fromUnix(
(GENESIS_SLOT.int64 * timeParams.SLOT_DURATION).seconds)

Opt.some T(
timeParams: timeParams,
genesis: (unixGenesis - unixGenesisOffset).inSeconds.fromUnix)
if genesis_time notin MIN_GENESIS_TIME .. MAX_GENESIS_TIME:
return Opt.none(BeaconClock)

let
unixGenesis = fromUnix(genesis_time.int64)
# GENESIS_SLOT offsets slot time, but to simplify calculations, we apply
# that offset to genesis instead of applying it at every time conversion
unixGenesisOffset = fromUnix(
(GENESIS_SLOT.int64 * timeParams.SLOT_DURATION).seconds)
Opt.some T(
timeParams: timeParams,
genesis: (unixGenesis - unixGenesisOffset).inSeconds.fromUnix)

func timeParams*(c: BeaconClock): TimeParams =
c.timeParams # Readonly
Expand Down
11 changes: 11 additions & 0 deletions beacon_chain/rpc/rest_config_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,17 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
Base10.toString(cfg.SHARD_COMMITTEE_PERIOD),
ETH1_FOLLOW_DISTANCE:
Base10.toString(cfg.ETH1_FOLLOW_DISTANCE),
PROPOSER_REORG_CUTOFF_BPS:
Base10.toString(cfg.timeParams.PROPOSER_REORG_CUTOFF_BPS),
ATTESTATION_DUE_BPS:
Base10.toString(cfg.timeParams.ATTESTATION_DUE_BPS),
AGGREGATE_DUE_BPS:
Base10.toString(cfg.timeParams.AGGREGATE_DUE_BPS),

SYNC_MESSAGE_DUE_BPS:
Base10.toString(cfg.timeParams.SYNC_MESSAGE_DUE_BPS),
CONTRIBUTION_DUE_BPS:
Base10.toString(cfg.timeParams.CONTRIBUTION_DUE_BPS),

INACTIVITY_SCORE_BIAS:
Base10.toString(cfg.INACTIVITY_SCORE_BIAS),
Expand Down
25 changes: 10 additions & 15 deletions beacon_chain/spec/beacon_time.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ const
GENESIS_SLOT* = Slot(0)
GENESIS_EPOCH* = Epoch(0) # compute_epoch_at_slot(GENESIS_SLOT)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.0/specs/phase0/fork-choice.md#constant
INTERVALS_PER_SLOT* = 3

func FAR_FUTURE_BEACON_TIME(timeParams: TimeParams): BeaconTime =
# Ensure all representable slots are complete
BeaconTime(ns_since_genesis:
Expand Down Expand Up @@ -141,35 +138,33 @@ template `+`*(a: TimeDiff, b: Duration): TimeDiff =
# Offsets from the start of the slot to when the corresponding message should
# be sent

func slotOffset(timeParams: TimeParams, bps: uint16): TimeDiff =
let oneBps = timeParams.SLOT_DURATION.nanoseconds div MAX_BPS.int64
TimeDiff(nanoseconds: bps.int64 * oneBps)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.2/specs/phase0/validator.md#attesting
func attestationSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 div INTERVALS_PER_SLOT)
timeParams.slotOffset(timeParams.ATTESTATION_DUE_BPS)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.2/specs/phase0/validator.md#broadcast-aggregate
func aggregateSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 * 2 div INTERVALS_PER_SLOT)
timeParams.slotOffset(timeParams.AGGREGATE_DUE_BPS)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.10/specs/altair/validator.md#prepare-sync-committee-message
func syncCommitteeMessageSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 div INTERVALS_PER_SLOT)
timeParams.slotOffset(timeParams.SYNC_MESSAGE_DUE_BPS)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.10/specs/altair/validator.md#broadcast-sync-committee-contribution
func syncContributionSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 * 2 div INTERVALS_PER_SLOT)
timeParams.slotOffset(timeParams.CONTRIBUTION_DUE_BPS)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.9/specs/altair/light-client/p2p-interface.md#sync-committee
func lightClientFinalityUpdateSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 div INTERVALS_PER_SLOT)
timeParams.syncCommitteeMessageSlotOffset

# https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.3/specs/altair/light-client/p2p-interface.md#sync-committee
func lightClientOptimisticUpdateSlotOffset*(timeParams: TimeParams): TimeDiff =
TimeDiff(nanoseconds:
timeParams.SLOT_DURATION.nanoseconds.int64 div INTERVALS_PER_SLOT)
timeParams.syncCommitteeMessageSlotOffset

func toFloatSeconds*(t: TimeDiff): float =
float(t.nanoseconds) / 1_000_000_000.0
Expand Down
137 changes: 103 additions & 34 deletions beacon_chain/spec/presets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,34 @@ const
MAX_SUPPORTED_BLOBS_PER_BLOCK*: uint64 = 9 # revisit getShortMap(Blobs) if >9
MAX_SUPPORTED_REQUEST_BLOB_SIDECARS*: uint64 = 1152

# https://github.com/ethereum/consensus-specs/blob/v1.6.0-beta.0/specs/phase0/validator.md#time-parameters
ATTESTATION_DUE_BPS: uint64 = 3333
AGGREGATE_DUE_BPS: uint64 = 6667

# https://github.com/ethereum/consensus-specs/blob/v1.6.0-beta.0/specs/altair/validator.md#time-parameters
SYNC_MESSAGE_DUE_BPS: uint64 = 3333
CONTRIBUTION_DUE_BPS: uint64 = 6667

# https://github.com/ethereum/consensus-specs/blob/v1.6.0-beta.0/specs/phase0/fork-choice.md#time-parameters
PROPOSER_REORG_CUTOFF_BPS: uint64 = 1667
type TimeParams* = object
SLOT_DURATION*: Duration
PROPOSER_REORG_CUTOFF_BPS*: uint16
ATTESTATION_DUE_BPS*: uint16
AGGREGATE_DUE_BPS*: uint16
SYNC_MESSAGE_DUE_BPS*: uint16
CONTRIBUTION_DUE_BPS*: uint16

const
MIN_SLOT_DURATION* = seconds(1)
MAX_SLOT_DURATION* = seconds(Duration.high.seconds)
MAX_BPS* = 10_000'u16

func isValid*(timeParams: TimeParams): bool =
# /!\ Keep in sync with `readRuntimeConfig`
timeParams.SLOT_DURATION in
MIN_SLOT_DURATION .. MAX_SLOT_DURATION and
timeParams.PROPOSER_REORG_CUTOFF_BPS in
0'u16 ..< MAX_BPS and
timeParams.ATTESTATION_DUE_BPS in
timeParams.PROPOSER_REORG_CUTOFF_BPS ..< MAX_BPS and
timeParams.AGGREGATE_DUE_BPS in
timeParams.ATTESTATION_DUE_BPS ..< MAX_BPS and
timeParams.SYNC_MESSAGE_DUE_BPS ==
timeParams.ATTESTATION_DUE_BPS and
timeParams.CONTRIBUTION_DUE_BPS ==
timeParams.AGGREGATE_DUE_BPS
type
TimeParams* = object
SLOT_DURATION*: Duration

Version* = distinct array[4, byte]

Eth1Address* = eth.Address
Expand Down Expand Up @@ -253,7 +266,21 @@ when const_preset == "mainnet":
# ---------------------------------------------------------------
timeParams: TimeParams(
# 12000 milliseconds
SLOT_DURATION: milliseconds(12000)),
SLOT_DURATION: milliseconds(12000),

# 1667 basis points, ~17% of SLOT_DURATION_MS
PROPOSER_REORG_CUTOFF_BPS: 1667,
# 3333 basis points, ~33% of SLOT_DURATION_MS
ATTESTATION_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
AGGREGATE_DUE_BPS: 6667,

# Altair
# 3333 basis points, ~33% of SLOT_DURATION_MS
SYNC_MESSAGE_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
CONTRIBUTION_DUE_BPS: 6667),

# 14 (estimate from Eth1 mainnet)
SECONDS_PER_ETH1_BLOCK: 14,
# 2**8 (= 256) epochs ~27 hours
Expand Down Expand Up @@ -421,7 +448,21 @@ elif const_preset == "gnosis":
# ---------------------------------------------------------------
timeParams: TimeParams(
# 5 seconds
SLOT_DURATION: milliseconds(5000)),
SLOT_DURATION: milliseconds(5000),

# 1667 basis points, ~17% of SLOT_DURATION_MS
PROPOSER_REORG_CUTOFF_BPS: 1667,
# 3333 basis points, ~33% of SLOT_DURATION_MS
ATTESTATION_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
AGGREGATE_DUE_BPS: 6667,

# Altair
# 3333 basis points, ~33% of SLOT_DURATION_MS
SYNC_MESSAGE_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
CONTRIBUTION_DUE_BPS: 6667),

# 14 (estimate from Eth1 mainnet)
SECONDS_PER_ETH1_BLOCK: 5,
# 2**8 (= 256) epochs ~27 hours
Expand Down Expand Up @@ -588,7 +629,21 @@ elif const_preset == "minimal":
# ---------------------------------------------------------------
timeParams: TimeParams(
# [customized] 6000 milliseconds
SLOT_DURATION: milliseconds(6000)),
SLOT_DURATION: milliseconds(6000),

# 1667 basis points, ~17% of SLOT_DURATION_MS
PROPOSER_REORG_CUTOFF_BPS: 1667,
# 3333 basis points, ~33% of SLOT_DURATION_MS
ATTESTATION_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
AGGREGATE_DUE_BPS: 6667,

# Altair
# 3333 basis points, ~33% of SLOT_DURATION_MS
SYNC_MESSAGE_DUE_BPS: 3333,
# 6667 basis points, ~67% of SLOT_DURATION_MS
CONTRIBUTION_DUE_BPS: 6667),

# 14 (estimate from Eth1 mainnet)
SECONDS_PER_ETH1_BLOCK: 14,
# 2**8 (= 256) epochs
Expand Down Expand Up @@ -694,27 +749,28 @@ const IsMainnetSupported*: bool =
const IsGnosisSupported*: bool =
const_preset == "gnosis"

const
MIN_SLOT_DURATION* = seconds(1)
MAX_SLOT_DURATION* = seconds(Duration.high.seconds)

const SLOTS_PER_SYNC_COMMITTEE_PERIOD* =
SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD

# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#configuration
func safeMinEpochsForBlockRequests*(cfg: RuntimeConfig): uint64 =
cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + cfg.CHURN_LIMIT_QUOTIENT div 2

func parse(T: type uint64, input: string): T {.raises: [ValueError].} =
func parse[T: uint16 | uint64](
_: typedesc[T], input: string): T {.raises: [ValueError].} =
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")
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")

uint64(res)
raise newException(
ValueError, "The constant value should be a valid unsigned integer")
when T.high < BiggestUInt.high:
if res > T.high.BiggestUInt:
raise newException(ValueError, "The constant value is too large")
res.T

template parse(T: type byte, input: string): T =
byte parse(uint64, input)
Expand Down Expand Up @@ -963,12 +1019,6 @@ proc readRuntimeConfig*(
checkCompatibility PROPOSER_SCORE_BOOST
checkCompatibility REORG_PARENT_WEIGHT_THRESHOLD

checkCompatibility ATTESTATION_DUE_BPS
checkCompatibility AGGREGATE_DUE_BPS
checkCompatibility SYNC_MESSAGE_DUE_BPS
checkCompatibility CONTRIBUTION_DUE_BPS
checkCompatibility PROPOSER_REORG_CUTOFF_BPS

template assignValue(name: static string, field: untyped): untyped =
when name == "SLOT_DURATION":
if values.hasKey("SLOT_DURATION_MS"):
Expand Down Expand Up @@ -1037,9 +1087,28 @@ proc readRuntimeConfig*(
except ValueError:
raise (ref PresetFileError)(msg: "Unable to parse " & name)

checkParsedValue(
"SLOT_DURATION_MS", cfg.timeParams.SLOT_DURATION.milliseconds,
MIN_SLOT_DURATION.milliseconds .. MAX_SLOT_DURATION.milliseconds, `in`)
block: # /!\ Keep in sync with `isValid`
checkParsedValue(
"SLOT_DURATION_MS", cfg.timeParams.SLOT_DURATION.milliseconds,
MIN_SLOT_DURATION.milliseconds .. MAX_SLOT_DURATION.milliseconds, `in`)

checkParsedValue(
"PROPOSER_REORG_CUTOFF_BPS", cfg.timeParams.PROPOSER_REORG_CUTOFF_BPS,
0'u16 ..< MAX_BPS, `in`)
checkParsedValue(
"ATTESTATION_DUE_BPS", cfg.timeParams.ATTESTATION_DUE_BPS,
cfg.timeParams.PROPOSER_REORG_CUTOFF_BPS ..< MAX_BPS, `in`)
checkParsedValue(
"AGGREGATE_DUE_BPS", cfg.timeParams.AGGREGATE_DUE_BPS,
cfg.timeParams.ATTESTATION_DUE_BPS ..< MAX_BPS, `in`)

checkParsedValue(
"SYNC_MESSAGE_DUE_BPS", cfg.timeParams.SYNC_MESSAGE_DUE_BPS,
cfg.timeParams.ATTESTATION_DUE_BPS)
checkParsedValue(
"CONTRIBUTION_DUE_BPS", cfg.timeParams.CONTRIBUTION_DUE_BPS,
cfg.timeParams.AGGREGATE_DUE_BPS)
doAssert cfg.timeParams.isValid

# Requires initialized `cfg`
checkCompatibility cfg.timeParams.SLOT_DURATION.seconds.uint64,
Expand Down
Loading
Loading