hof.gno

2.63 Kb ยท 136 lines
  1// Package hof is the hall of fame realm.
  2// The Hall of Fame is an exhibition that holds items. Users can add their realms to the Hall of Fame by
  3// importing the Hall of Fame realm and calling hof.Register() from their init function.
  4package hof
  5
  6import (
  7	"std"
  8
  9	"gno.land/p/demo/avl"
 10	"gno.land/p/demo/ownable"
 11	"gno.land/p/demo/pausable"
 12	"gno.land/p/demo/seqid"
 13
 14	"gno.land/r/leon/config"
 15)
 16
 17var (
 18	exhibition *Exhibition
 19
 20	// Safe objects
 21	Ownable  *ownable.Ownable
 22	Pausable *pausable.Pausable
 23)
 24
 25type (
 26	Exhibition struct {
 27		itemCounter seqid.ID
 28		description string
 29		items       *avl.Tree // pkgPath > &Item
 30		itemsSorted *avl.Tree // same data but sorted, storing pointers
 31	}
 32
 33	Item struct {
 34		id       seqid.ID
 35		pkgpath  string
 36		blockNum int64
 37		upvote   *avl.Tree // std.Addr > struct{}{}
 38		downvote *avl.Tree // std.Addr > struct{}{}
 39	}
 40)
 41
 42func init() {
 43	exhibition = &Exhibition{
 44		items:       avl.NewTree(),
 45		itemsSorted: avl.NewTree(),
 46	}
 47
 48	Ownable = ownable.NewWithAddress(config.OwnableMain.Owner()) // OrigSendOwnable?
 49	Pausable = pausable.NewFromOwnable(Ownable)
 50}
 51
 52// Register registers your realm to the Hall of Fame
 53// Should be called from within code
 54func Register() {
 55	if Pausable.IsPaused() {
 56		return
 57	}
 58
 59	submission := std.PreviousRealm()
 60	pkgpath := submission.PkgPath()
 61
 62	// Must be called from code
 63	if submission.IsUser() {
 64		return
 65	}
 66
 67	// Must not yet exist
 68	if exhibition.items.Has(pkgpath) {
 69		return
 70	}
 71
 72	id := exhibition.itemCounter.Next()
 73	i := &Item{
 74		id:       id,
 75		pkgpath:  pkgpath,
 76		blockNum: std.ChainHeight(),
 77		upvote:   avl.NewTree(),
 78		downvote: avl.NewTree(),
 79	}
 80
 81	exhibition.items.Set(pkgpath, i)
 82	exhibition.itemsSorted.Set(id.String(), i)
 83
 84	std.Emit("Registration")
 85}
 86
 87func Upvote(pkgpath string) {
 88	rawItem, ok := exhibition.items.Get(pkgpath)
 89	if !ok {
 90		panic(ErrNoSuchItem)
 91	}
 92
 93	item := rawItem.(*Item)
 94	caller := std.PreviousRealm().Address().String()
 95
 96	if item.upvote.Has(caller) {
 97		panic(ErrDoubleUpvote)
 98	}
 99
100	item.upvote.Set(caller, struct{}{})
101}
102
103func Downvote(pkgpath string) {
104	rawItem, ok := exhibition.items.Get(pkgpath)
105	if !ok {
106		panic(ErrNoSuchItem)
107	}
108
109	item := rawItem.(*Item)
110	caller := std.PreviousRealm().Address().String()
111
112	if item.downvote.Has(caller) {
113		panic(ErrDoubleDownvote)
114	}
115
116	item.downvote.Set(caller, struct{}{})
117}
118
119func Delete(pkgpath string) {
120	if !Ownable.CallerIsOwner() {
121		panic(ownable.ErrUnauthorized)
122	}
123
124	i, ok := exhibition.items.Get(pkgpath)
125	if !ok {
126		panic(ErrNoSuchItem)
127	}
128
129	if _, removed := exhibition.itemsSorted.Remove(i.(*Item).id.String()); !removed {
130		panic(ErrNoSuchItem)
131	}
132
133	if _, removed := exhibition.items.Remove(pkgpath); !removed {
134		panic(ErrNoSuchItem)
135	}
136}