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}