Skip to content

Instantly share code, notes, and snippets.

@arnetheduck
Created March 21, 2019 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arnetheduck/652a6823e5cec510f8572895d850bbee to your computer and use it in GitHub Desktop.
Save arnetheduck/652a6823e5cec510f8572895d850bbee to your computer and use it in GitHub Desktop.
starting point, beacon clock
import
chronos,
spec/[datatypes]
type
ChronosTime* = uint64
## Unix epoch timestamp in millisecond resolution
# TODO fetch from chronos and make distinct
ChronosClock* = object
## The chronos clock follows unix time but measures time in milliseconds
## genesis for the chronos clock is constant and the same as normal unix.
## It is currently broken, in the sense that it should be using a monotonic
## clock, since
BeaconClock* = object
genesis: ChronosTime
## The beacon clock represents time as it passes on a beacon chain. Beacon
## time is locked to unix time, starting at a particular offset set during
## beacon chain instantiation.
##
## Time on the beacon chain determines what actions should be taken and
## which blocks are valid - in particular, blocks are not valid if they
## come from the future as seen from the local clock.
##
## https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beacon-chain-processing
##
# TODO replace time in chronos with a proper unit type, then this code can
# follow:
# https://github.com/status-im/nim-chronos/issues/15
# TODO consider NTP and network-adjusted timestamps as outlined here:
# https://ethresear.ch/t/network-adjusted-timestamps/4187
const
chronosPerSecond* = 1000'u64
chronosPerSlot* = chronosPerSecond * SECONDS_PER_SLOT ## Chronos time units per slot
func now*(T: type ChronosClock): ChronosTime = chronos.fastEpochTime()
func init*(T: type BeaconClock, state: BeaconState): T =
## Initialize time from a beacon state. The genesis time of a beacon state is
## constant throughout its lifetime, so the state from any slot will do,
## including the genesis state.
let
ctGenesis = ChronosTime(state.genesis_time * chronosPerSecond)
# GENESIS_SLOT offsets slot time, but to simplify calculations, we apply that
# offset to genesis instead of applying it at every time conversion
ctGenesisSlotOffset = GENESIS_SLOT * chronosPerSlot
doAssert ctGenesis > ctGenesisSlotOffset,
"Genesis underflow, fix BeaconClock"
T(genesis: ctGenesis - ctGenesisSlotOffset)
func toSlot*(c: BeaconClock, t: ChronosTime): Slot =
doAssert t > c.genesis,
"Cannot represent time before genesis, fix BeaconClock"
Slot((t - c.genesis) div chronosPerSlot)
func toChronosTime*(c: BeaconClock, s: Slot): ChronosTime =
ChronosTime(s.uint64 * chronosPerSlot + c.genesis)
func now*(c: BeaconClock): Slot =
## Current time, in slots - this may end up being less than GENESIS_SLOT(!)
toSlot(c, ChronosClock.now())
func slotStart*(c: BeaconClock, slot: Slot): ChronosTime =
c.toChronosTime(slot)
func slotMiddle*(c: BeaconClock, slot: Slot): ChronosTime =
c.toChronosTime(slot) + (chronosPerSlot div 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment