Go implementation

peoplecoin

Standard library only. Primitives, the state machine, and the nine operations — no networking, no video, no wallet yet.

period/period.go

76 lines

1// Package period is the calendar of the protocol: four-week periods of
2// 40 320 one-minute slots counted from genesis, split into four weekly
3// phases, and the hour of the monthly event.
4//
5// period = slot / SlotsPerPeriod
6// phase = (slot % SlotsPerPeriod) / SlotsPerPhase
7//
8// Phases are numbered 0–3 here; the specification calls them 1–4:
9//
10// Phase 0 (spec "phase 1") the event; Verify signed here
11// Phases 0–1 Verified, Register, Mix, Vote, Commit
12// Phase 2 (spec "phase 3") Reveal, and with it the UBI
13// Phase 3 (spec "phase 4") pause; the seed and the next pairs are known
14//
15// Genesis is 07:00 UTC on a Saturday, and since a period is exactly four
16// weeks every period begins there. The event is held at the period start
17// plus the period's hour, SHA256(uint32(period)) mod 24, for fifteen
18// minutes. That is a convention about when to show up, not a ledger rule:
19// the ledger only maps slots to phases. Wall-clock time comes from the
20// headers themselves (state.State.TimeOf), never from a remembered genesis
21// constant.
22package period
23
24import (
25 "crypto/sha256"
26 "encoding/binary"
27
28 "peoplecoin/params"
29 "peoplecoin/rng"
30)
31
32// Phase indices.
33const (
34 PhaseEvent uint64 = 0
35 PhaseCollect uint64 = 1
36 PhaseReveal uint64 = 2
37 PhasePause uint64 = 3
38)
39
40// Of returns the period a slot belongs to.
41func Of(slot uint64) uint64 { return slot / params.SlotsPerPeriod }
42
43// Phase returns the phase (0–3) of a slot within its period.
44func Phase(slot uint64) uint64 { return (slot % params.SlotsPerPeriod) / params.SlotsPerPhase }
45
46// Start returns the first slot of a period.
47func Start(period uint64) uint64 { return period * params.SlotsPerPeriod }
48
49// End returns the first slot of the following period.
50func End(period uint64) uint64 { return (period + 1) * params.SlotsPerPeriod }
51
52// IsBoundary reports whether slot is the first of a period.
53func IsBoundary(slot uint64) bool { return slot%params.SlotsPerPeriod == 0 }
54
55// Number is the period as the uint32 that is hashed and signed.
56func Number(slot uint64) uint32 { return uint32(Of(slot)) }
57
58// EventOffset is the event's hour, 0–23, counted from the period start:
59// SHA256(uint32(period)) as a big-endian integer, mod 24. It depends on the
60// period number alone, so it is known from genesis and cannot be moved by
61// anyone.
62func EventOffset(period uint32) uint64 {
63 var b [4]byte
64 binary.BigEndian.PutUint32(b[:], period)
65 return rng.HashMod(sha256.Sum256(b[:]), 24)
66}
67
68// EventSlots is the length of the event in slots.
69const EventSlots uint64 = 15
70
71// EventSlot returns the slot at which the period's event begins. It is
72// always in the first day of phase 0.
73func EventSlot(period uint64) uint64 {
74 return Start(period) + EventOffset(uint32(period))*60
75}