Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

testclock.gno

3.55 Kb · 147 lines
  1package kourt
  2import (
  3	"time"
  4	runtime "chain/runtime"
  5	unsafe "chain/runtime/unsafe"
  6)
  7const (
  8	maxAdvanceStep  = int64(10 * 365 * 86400)
  9	maxAdvanceTotal = int64(100 * 365 * 86400)
 10	maxHeightStep  = 2 * periodBlocks
 11	maxHeightTotal = 10 * periodBlocks
 12	maxBase = int64(4102444800)
 13)
 14var (
 15	tcDeployer address
 16	tcArmed    bool
 17	tcSealed   bool
 18	tcSkew     int64
 19	tcBase     int64
 20	tcFloor    int64
 21	tcEverArmed bool
 22	tcPeakSkew  int64
 23	tcHeightSkew int64
 24	tcHeightPeak int64
 25	tcHeightBase  int64
 26	tcHeightFloor int64
 27)
 28func init() { tcDeployer = unsafe.OriginCaller() }
 29func mustDeployer(cur realm) {
 30	if !cur.IsCurrent() {
 31		panic(errStaleRealm)
 32	}
 33	if cur.Previous().Address() != tcDeployer {
 34		panic("kourtv2: only the deployer may drive the test clock")
 35	}
 36}
 37func EnableTestClock(cur realm) {
 38	mustDeployer(cur)
 39	if tcSealed {
 40		panic("kourtv2: the test clock is sealed; this realm is not a test chain")
 41	}
 42	if tcArmed {
 43		panic("kourtv2: the test clock is already armed")
 44	}
 45	if CourtCount() > 2 {
 46		panic("kourtv2: this realm already has courts; the test clock cannot be armed")
 47	}
 48	m := mustCourt(metaSlug)
 49	if m.nextID > 1 || m.coin.TotalSupply() > 0 {
 50		panic("kourtv2: this realm has been used; the test clock cannot be armed")
 51	}
 52	tcArmed = true
 53	tcBase = time.Now().Unix()
 54	if tcBase > maxBase {
 55		panic("kourtv2: this chain's own clock reads past 2100; check its genesis time")
 56	}
 57	tcFloor = tcBase
 58	tcHeightBase = runtime.ChainHeight()
 59	tcHeightFloor = tcHeightBase
 60}
 61func EnableTestClockAt(cur realm, base int64) {
 62	mustDeployer(cur)
 63	if base <= 0 {
 64		panic("kourtv2: the test clock's base must be a positive instant")
 65	}
 66	if base > maxBase {
 67		panic("kourtv2: the test clock's base must be an instant before 2100")
 68	}
 69	EnableTestClock(cur)
 70	tcBase = base
 71	if base > tcFloor {
 72		tcFloor = base
 73	}
 74}
 75func AdvanceTestClock(cur realm, secs int64) {
 76	mustDeployer(cur)
 77	if !tcArmed {
 78		panic("kourtv2: the test clock is not armed")
 79	}
 80	if secs <= 0 || secs > maxAdvanceStep {
 81		panic("kourtv2: the test clock moves forward, by at most ten years a step")
 82	}
 83	if tcSkew > maxAdvanceTotal-secs {
 84		panic("kourtv2: the test clock has advanced as far as it may")
 85	}
 86	tcSkew += secs
 87	if tcSkew > tcPeakSkew {
 88		tcPeakSkew = tcSkew
 89	}
 90	if n := tcBase + tcSkew; n > tcFloor {
 91		tcFloor = n
 92	}
 93}
 94func AdvanceTestHeight(cur realm, n int64) {
 95	mustDeployer(cur)
 96	if !tcArmed {
 97		panic("kourtv2: the test clock is not armed")
 98	}
 99	if n <= 0 || n > maxHeightStep {
100		panic("kourtv2: the test height moves forward, by at most two emission periods a step")
101	}
102	if tcHeightSkew > maxHeightTotal-n {
103		panic("kourtv2: the test height has advanced as far as it may")
104	}
105	tcHeightSkew += n
106	if tcHeightSkew > tcHeightPeak {
107		tcHeightPeak = tcHeightSkew
108	}
109	if h := tcHeightBase + tcHeightSkew; h > tcHeightFloor {
110		tcHeightFloor = h
111	}
112}
113func TestHeightSkew() int64 { return tcHeightSkew }
114func TestHeightPeakSkew() int64 { return tcHeightPeak }
115func SealTestClock(cur realm) {
116	mustDeployer(cur)
117	if !tcArmed {
118		panic("kourtv2: the test clock was never armed; there is nothing to seal")
119	}
120	sealTestClock()
121}
122func sealTestClock() {
123	tcSealed = true
124	tcArmed = false
125	tcSkew = 0
126	tcBase = 0
127	tcHeightSkew = 0
128}
129func TestClockActive() bool { return tcArmed }
130func TestClockFabricated() bool { return tcEverArmed }
131func TestClockSkew() int64 { return tcSkew }
132func TestClockPeakSkew() int64 { return tcPeakSkew }
133func tcNow() int64 {
134	var n int64
135	if tcArmed {
136		n = tcBase + tcSkew
137	} else {
138		n = time.Now().Unix()
139		if n < tcFloor {
140			n = tcFloor
141		}
142	}
143	if n <= 0 {
144		panic("kourtv2: the clock read a non-positive instant")
145	}
146	return n
147}