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.

supersede.gno

3.24 Kb · 133 lines
  1package kourtv3
  2import (
  3	"strconv"
  4	"strings"
  5	bptree "gno.land/p/nt/bptree/v0"
  6)
  7const (
  8	maxSupIn = 8
  9	maxSupInPerAuthor = 2
 10)
 11type supEdge struct {
 12	to     uint64
 13	author address
 14	at     int64
 15}
 16func ensureSup(c *Court) {
 17	if c.supOf == nil {
 18		c.supOf = bptree.NewBPTree32()
 19	}
 20	if c.supBy == nil {
 21		c.supBy = bptree.NewBPTree32()
 22	}
 23}
 24func supersedeOrdered(from, to *claimState) bool {
 25	if from.openedAtTime != 0 && to.openedAtTime != 0 {
 26		return from.openedAtTime >= to.openedAtTime+deadClaimSecs
 27	}
 28	return from.openedAt >= to.openedAt+deadClaimTimeout
 29}
 30func SupersedeClaim(cur realm, courtSlug string, from, to uint64) {
 31	if !cur.IsCurrent() {
 32		panic(errStaleRealm)
 33	}
 34	who := cur.Previous().Address()
 35	c := mustCourt(courtSlug)
 36	if from == to {
 37		panic("kourtv3: a claim cannot supersede itself")
 38	}
 39	f := mustClaim(c, from)
 40	t := mustClaim(c, to)
 41	if f.author != who {
 42		cm := ensureMod(c)
 43		if !cm.members.Has(who.String()) {
 44			panic("kourtv3: only the re-filing claim's author or a court moderator may record it")
 45		}
 46		requireActiveMod(cm, who)
 47	}
 48	if !t.closed {
 49		panic("kourtv3: only a claim that died unanswered can be superseded")
 50	}
 51	if !supersedeOrdered(f, t) {
 52		panic("kourtv3: a re-filing must come after the claim it re-files could have died")
 53	}
 54	ensureSup(c)
 55	if c.supOf.Get(beClaimKey(from)) != nil {
 56		panic("kourtv3: that claim already re-files one; remove that edge first")
 57	}
 58	inN, mine := 0, 0
 59	p := beClaimKey(to)
 60	c.supBy.Iterate(p, "", func(key string, v any) bool {
 61		if !strings.HasPrefix(key, p) {
 62			return true
 63		}
 64		inN++
 65		if e, ok := v.(*supEdge); ok && e.author == who {
 66			mine++
 67		}
 68		return false
 69	})
 70	if inN >= maxSupIn {
 71		panic("kourtv3: that claim has already been re-filed " + strconv.Itoa(maxSupIn) + " times")
 72	}
 73	if mine >= maxSupInPerAuthor {
 74		panic("kourtv3: you already record " + strconv.Itoa(maxSupInPerAuthor) +
 75			" re-filings of that claim")
 76	}
 77	e := &supEdge{to: to, author: who, at: heightNow()}
 78	c.supOf.Set(beClaimKey(from), e)
 79	c.supBy.Set(beClaimKey(to)+beClaimKey(from), e)
 80}
 81func RemoveSupersede(cur realm, courtSlug string, from uint64) {
 82	if !cur.IsCurrent() {
 83		panic(errStaleRealm)
 84	}
 85	who := cur.Previous().Address()
 86	c := mustCourt(courtSlug)
 87	if c.supOf == nil {
 88		panic("kourtv3: that claim re-files nothing")
 89	}
 90	v := c.supOf.Get(beClaimKey(from))
 91	if v == nil {
 92		panic("kourtv3: that claim re-files nothing")
 93	}
 94	e := v.(*supEdge)
 95	requireEdgeRemover(c, e.author, who)
 96	c.supOf.Remove(beClaimKey(from))
 97	c.supBy.Remove(beClaimKey(e.to) + beClaimKey(from))
 98}
 99func ClaimSupersedes(courtSlug string, claimID uint64) string {
100	c := mustCourt(courtSlug)
101	mustClaim(c, claimID)
102	var b strings.Builder
103	b.WriteString("of:")
104	if c.supOf != nil {
105		if v := c.supOf.Get(beClaimKey(claimID)); v != nil {
106			e := v.(*supEdge)
107			if !assocTextGone(c, e.to) {
108				b.WriteString(strconv.FormatUint(e.to, 10))
109			}
110		}
111	}
112	b.WriteString(";by:")
113	if c.supBy != nil {
114		p := beClaimKey(claimID)
115		n := 0
116		c.supBy.Iterate(p, "", func(key string, v any) bool {
117			if !strings.HasPrefix(key, p) {
118				return true
119			}
120			other := claimIDFromKey(key[8:])
121			if assocTextGone(c, other) {
122				return false
123			}
124			if n > 0 {
125				b.WriteString(",")
126			}
127			b.WriteString(strconv.FormatUint(other, 10))
128			n++
129			return false
130		})
131	}
132	return b.String()
133}