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.57 Kb · 148 lines
  1package kourtv3
  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("kourtv3: only the deployer may drive the test clock")
 35	}
 36}
 37func EnableTestClock(cur realm) {
 38	mustDeployer(cur)
 39	if tcSealed {
 40		panic("kourtv3: the test clock is sealed; this realm is not a test chain")
 41	}
 42	if tcArmed {
 43		panic("kourtv3: the test clock is already armed")
 44	}
 45	if CourtCount() > 1 {
 46		panic("kourtv3: 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("kourtv3: this realm has been used; the test clock cannot be armed")
 51	}
 52	tcArmed = true
 53	tcEverArmed = true
 54	tcBase = time.Now().Unix()
 55	if tcBase > maxBase {
 56		panic("kourtv3: this chain's own clock reads past 2100; check its genesis time")
 57	}
 58	tcFloor = tcBase
 59	tcHeightBase = runtime.ChainHeight()
 60	tcHeightFloor = tcHeightBase
 61}
 62func EnableTestClockAt(cur realm, base int64) {
 63	mustDeployer(cur)
 64	if base <= 0 {
 65		panic("kourtv3: the test clock's base must be a positive instant")
 66	}
 67	if base > maxBase {
 68		panic("kourtv3: the test clock's base must be an instant before 2100")
 69	}
 70	EnableTestClock(cur)
 71	tcBase = base
 72	if base > tcFloor {
 73		tcFloor = base
 74	}
 75}
 76func AdvanceTestClock(cur realm, secs int64) {
 77	mustDeployer(cur)
 78	if !tcArmed {
 79		panic("kourtv3: the test clock is not armed")
 80	}
 81	if secs <= 0 || secs > maxAdvanceStep {
 82		panic("kourtv3: the test clock moves forward, by at most ten years a step")
 83	}
 84	if tcSkew > maxAdvanceTotal-secs {
 85		panic("kourtv3: the test clock has advanced as far as it may")
 86	}
 87	tcSkew += secs
 88	if tcSkew > tcPeakSkew {
 89		tcPeakSkew = tcSkew
 90	}
 91	if n := tcBase + tcSkew; n > tcFloor {
 92		tcFloor = n
 93	}
 94}
 95func AdvanceTestHeight(cur realm, n int64) {
 96	mustDeployer(cur)
 97	if !tcArmed {
 98		panic("kourtv3: the test clock is not armed")
 99	}
100	if n <= 0 || n > maxHeightStep {
101		panic("kourtv3: the test height moves forward, by at most two emission periods a step")
102	}
103	if tcHeightSkew > maxHeightTotal-n {
104		panic("kourtv3: the test height has advanced as far as it may")
105	}
106	tcHeightSkew += n
107	if tcHeightSkew > tcHeightPeak {
108		tcHeightPeak = tcHeightSkew
109	}
110	if h := tcHeightBase + tcHeightSkew; h > tcHeightFloor {
111		tcHeightFloor = h
112	}
113}
114func TestHeightSkew() int64 { return tcHeightSkew }
115func TestHeightPeakSkew() int64 { return tcHeightPeak }
116func SealTestClock(cur realm) {
117	mustDeployer(cur)
118	if !tcArmed {
119		panic("kourtv3: the test clock was never armed; there is nothing to seal")
120	}
121	sealTestClock()
122}
123func sealTestClock() {
124	tcSealed = true
125	tcArmed = false
126	tcSkew = 0
127	tcBase = 0
128	tcHeightSkew = 0
129}
130func TestClockActive() bool { return tcArmed }
131func TestClockFabricated() bool { return tcEverArmed }
132func TestClockSkew() int64 { return tcSkew }
133func TestClockPeakSkew() int64 { return tcPeakSkew }
134func tcNow() int64 {
135	var n int64
136	if tcArmed {
137		n = tcBase + tcSkew
138	} else {
139		n = time.Now().Unix()
140		if n < tcFloor {
141			n = tcFloor
142		}
143	}
144	if n <= 0 {
145		panic("kourtv3: the clock read a non-positive instant")
146	}
147	return n
148}