period/period_test.go
92 lines
1package period23import (4"crypto/sha256"5"encoding/binary"6"math/big"7"testing"8"time"910"peoplecoin/params"11)1213func TestPeriodAndPhase(t *testing.T) {14sp := params.SlotsPerPeriod15cases := []struct{ slot, period, phase uint64 }{16{0, 0, 0}, {10079, 0, 0}, {10080, 0, 1}, {20159, 0, 1}, {20160, 0, 2},17{30239, 0, 2}, {30240, 0, 3}, {sp - 1, 0, 3}, {sp, 1, 0}, {7*sp + 25000, 7, 2},18}19for _, c := range cases {20if Of(c.slot) != c.period || Phase(c.slot) != c.phase {21t.Errorf("slot %d: period %d phase %d, want %d %d", c.slot, Of(c.slot), Phase(c.slot), c.period, c.phase)22}23}24if Start(3) != 3*sp || End(3) != 4*sp || !IsBoundary(4*sp) || IsBoundary(4*sp+1) {25t.Fatal("start/end/boundary")26}27if Number(5*sp+9) != 5 {28t.Fatal("number")29}30if params.SlotsPerPhase*params.NumPhases != sp {31t.Fatal("phases do not tile the period")32}33}3435func TestEventOffset(t *testing.T) {36seen := map[uint64]int{}37for p := uint32(0); p < 500; p++ {38o := EventOffset(p)39if o >= 24 {40t.Fatalf("offset %d out of range", o)41}42if o != EventOffset(p) {43t.Fatal("not deterministic")44}45seen[o]++46}47// All 24 hours occur over 500 periods, each roughly 500/24 times.48if len(seen) != 24 {49t.Fatalf("only %d of 24 hours occur", len(seen))50}51for hr, n := range seen {52if n < 8 || n > 40 {53t.Fatalf("hour %d occurs %d times of ~21", hr, n)54}55}56// The definition: the digest as a big-endian integer, mod 24.57var b [4]byte58binary.BigEndian.PutUint32(b[:], 7)59h := sha256.Sum256(b[:])60want := new(big.Int).Mod(new(big.Int).SetBytes(h[:]), big.NewInt(24)).Uint64()61if EventOffset(7) != want {62t.Fatal("definition")63}64t.Logf("EventOffset(0..3) = %d %d %d %d hours", EventOffset(0), EventOffset(1), EventOffset(2), EventOffset(3))65}6667func TestEventSlot(t *testing.T) {68// Genesis Saturday 2027-01-02 07:00 UTC; a tip clock as state.State keeps it.69g := time.Date(2027, 1, 2, 7, 0, 0, 0, time.UTC)70timeOf := func(slot uint64) time.Time { return g.Add(time.Duration(slot) * time.Minute) }71for p := uint64(0); p < 200; p++ {72es := EventSlot(p)73if es < Start(p) || es-Start(p) != EventOffset(uint32(p))*60 || es-Start(p) > 23*60 {74t.Fatalf("period %d: event slot %d", p, es)75}76if Phase(es) != PhaseEvent || Phase(es+EventSlots) != PhaseEvent {77t.Fatalf("period %d: event outside phase 0", p)78}79// Every period starts Saturday 07:00; the event is on the hour,80// Saturday 07:00 through Sunday 06:00.81ps := timeOf(Start(p))82if ps.Weekday() != time.Saturday || ps.Hour() != 7 || ps.Minute() != 0 {83t.Fatalf("period %d starts %v", p, ps)84}85et := timeOf(es)86if et.Minute() != 0 || (et.Weekday() != time.Saturday && et.Weekday() != time.Sunday) {87t.Fatalf("period %d: event at %v", p, et)88}89}90t.Logf("period 0 event at %v", timeOf(EventSlot(0)))91}