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

feedback_host.gno

4.16 Kb · 91 lines
 1package memba_weighted_host
 2
 3import (
 4	"chain"
 5	"gno.land/p/samcrew/memba_weighted_policy"
 6)
 7
 8type FeedbackState struct {
 9	Owner, PendingOwner address
10	Paused bool
11	MemberCount int
12	MembershipRevision uint64
13	OwnerMember, DAOMember, SuccessorMember, SubjectMember bool
14	OwnerRoles, DAORoles, SuccessorRoles, SubjectRoles string
15	ChannelCount int
16	ChannelExists bool
17	ChannelDescription, ChannelType, ChannelReadRoles, ChannelWriteRoles string
18}
19type feedbackProposal struct { action FeedbackAction; before FeedbackState }
20
21func feedbackCommitment(a FeedbackAction, s FeedbackState) string {
22	return a.Bytes()+"|before|"+feedbackStateJSON(s)
23}
24func (h *Host) validateFeedback(a FeedbackAction, s FeedbackState) {
25	if h.feedbackPolicy==nil { panic("feedback actions are not configured") }
26	a.Bytes()
27	p:=h.feedbackPolicy
28	if !s.Owner.IsValid() || (s.PendingOwner!="" && !s.PendingOwner.IsValid()) || s.MemberCount<1 || !s.OwnerMember || s.ChannelCount<0 || s.ChannelCount>20 {
29		panic("invalid feedback authority pre-state")
30	}
31	if a.Subject()=="" && (s.SubjectMember || s.SubjectRoles!="") { panic("unexpected feedback subject pre-state") }
32	if a.Name()=="" && (s.ChannelExists || s.ChannelDescription!="" || s.ChannelType!="" || s.ChannelReadRoles!="" || s.ChannelWriteRoles!="") { panic("unexpected feedback creation pre-state") }
33	if a.Kind()==FeedbackAcceptOwner {
34		if s.Owner!=p.Successor() || s.PendingOwner!=p.DAO() || s.DAOMember || !s.SuccessorMember || s.OwnerRoles!="admin" || s.SuccessorRoles!="admin" {
35			panic("publisher is not pending feedback handoff or DAO already has membership")
36		}
37		return
38	}
39	if s.Owner!=p.DAO() || !s.DAOMember || s.DAORoles!=s.OwnerRoles { panic("DAO is not feedback owner") }
40	if a.Kind()==FeedbackAbortReturn {
41		if a.Recipient()!=p.Successor() || s.PendingOwner!=p.Successor() { panic("feedback return does not match policy") }
42		return
43	}
44	if s.PendingOwner!="" { panic("feedback authority transfer is pending") }
45	switch a.Kind() {
46	case FeedbackReturnOwner:
47		if a.Recipient()!=p.Successor() || s.SuccessorMember { panic("feedback successor mismatch or preexisting membership") }
48	case FeedbackAddMember, FeedbackRemoveMember, FeedbackSetRoles:
49		if a.Subject()==p.DAO() || a.Subject()==chain.PackageAddress(FeedbackPath) || (a.Subject()==p.Successor() && a.Kind()!=FeedbackRemoveMember) {
50			panic("feedback member action targets protected authority")
51		}
52		if a.Kind()==FeedbackAddMember && s.SubjectMember { panic("feedback member already exists") }
53		if a.Kind()!=FeedbackAddMember && !s.SubjectMember { panic("feedback member does not exist") }
54		if a.Kind()==FeedbackSetRoles && s.SubjectRoles==a.Roles() { panic("feedback roles are unchanged") }
55	case FeedbackCreateText:
56		if s.ChannelCount>=20 || s.ChannelExists { panic("feedback text creation unavailable") }
57	case FeedbackUnpause:
58		if !s.Paused { panic("feedback unpause is a no-op") }
59	default: panic("unsupported feedback action")
60	}
61}
62func (h *Host) ProposeFeedback(a FeedbackAction, s FeedbackState, rlm realm) uint64 {
63	who:=assertCaller(h,rlm)
64	h.validateFeedback(a,s)
65	p:=&roleProposal{proposer:who,feedback:&feedbackProposal{action:a,before:s}}
66	p.ballot=h.policy.NewProposal(a.Category(),feedbackCommitment(a,s))
67	h.addProposal(p)
68	return uint64(len(h.proposals))
69}
70func (h *Host) invalidateFeedbackPeers(cause string, id uint64) {
71	members:=[]memba_weighted_policy.Member{}
72	for _,seat:=range h.seats { members=append(members,seat.Member) }
73	h.policy.Reconfigure(members)
74	h.recordInvalidation(cause, id, FeedbackPath)
75}
76func (h *Host) ConsumeFeedback(id uint64, s FeedbackState, rlm realm) FeedbackAction {
77	assertCaller(h,rlm)
78	p:=h.proposal(id)
79	if p.feedback==nil { panic("proposal is not a feedback action") }
80	h.validateFeedback(p.feedback.action,s)
81	p.ballot.Consume(feedbackCommitment(p.feedback.action,s))
82	h.invalidateFeedbackPeers(InvalidatedByExecution, id)
83	return p.feedback.action
84}
85func (h *Host) PrepareFeedbackEmergencyPause(s FeedbackState, rlm realm) {
86	assertCaller(h,rlm)
87	if h.feedbackPolicy==nil || s.Owner!=h.feedbackPolicy.DAO() || s.Paused || !s.OwnerMember || !s.DAOMember || s.DAORoles!=s.OwnerRoles {
88		panic("feedback emergency pause unavailable")
89	}
90	h.invalidateFeedbackPeers(InvalidatedByPause, 0)
91}