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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

lock.gno

2.47 Kb · 78 lines
 1package arena
 2
 3import (
 4	"chain/runtime"
 5	"strconv"
 6	"time"
 7)
 8
 9// guard binds the session that signed the transaction to match id, held in m, saving the
10// caller's record only when its locks change.
11func guard(fromUser bool, caller address, m record, id int) {
12	session, expires, ok := signingSession(fromUser)
13	if !ok {
14		return
15	}
16	if caller != m.challenger && caller != m.acceptor {
17		panic("not a player")
18	}
19	p := loadPlayer(caller)
20	if p.lock(session, expires, id, false, time.Now().Unix()) {
21		savePlayer(caller, p)
22	}
23}
24
25// join adds match id to the caller's record and binds the session that signed the
26// transaction to it, refused when that session is bound to a match already.
27func join(fromUser bool, caller address, id int) {
28	p := loadPlayer(caller)
29	if session, expires, ok := signingSession(fromUser); ok {
30		p.lock(session, expires, id, true, time.Now().Unix())
31	}
32	p.add(id)
33	savePlayer(caller, p)
34}
35
36// signingSession returns the signing session key and its expiry when fromUser: a session
37// signs the whole transaction, so a call through another realm is left unchecked.
38func signingSession(fromUser bool) (address, int64, bool) {
39	if !fromUser {
40		return "", 0, false
41	}
42	session, expires, _, ok := runtime.GetSessionInfo()
43	return session, expires, ok
44}
45
46// lock binds session to match id in p's locks, panicking when it is refused, and reports
47// whether the locks changed.
48func (p *playerRecord) lock(session address, expires int64, id int, opening bool, now int64) bool {
49	locks, changed, refusal := lockSession(p.locks, session, expires, id, opening, now)
50	if refusal != "" {
51		panic(refusal)
52	}
53	p.locks = locks
54	return changed
55}
56
57// lockSession binds session to match id, refused when bound to another, or any when opening.
58// It drops expired locks and any lock its key holds under another expiry (Unix seconds, 0 never).
59func lockSession(locks []sessionLock, session address, expires int64, id int, opening bool, now int64) (kept []sessionLock, changed bool, refusal string) {
60	for _, l := range locks {
61		expired := l.expires != 0 && l.expires <= now
62		stale := l.session == session && l.expires != expires
63		if !expired && !stale {
64			kept = append(kept, l)
65		}
66	}
67	changed = len(kept) != len(locks)
68	for _, l := range kept {
69		if l.session != session {
70			continue
71		}
72		if opening || l.id != id {
73			return kept, changed, "session locked to match " + strconv.Itoa(l.id)
74		}
75		return kept, changed, ""
76	}
77	return append(kept, sessionLock{session: session, id: id, expires: expires}), true, ""
78}