proxy.gno
4.54 Kb ยท 174 lines
1package dao
2
3import (
4 "chain"
5 "chain/runtime"
6 "strconv"
7)
8
9// dao is the actual govDAO implementation, having all the needed business logic
10var dao DAO
11
12// allowedDAOs contains realms that can be used to update the actual govDAO implementation,
13// and validate Proposals.
14// This is like that to be able to rollback using a previous govDAO implementation in case
15// the latest implementation has a breaking bug. After a test period, a proposal can be
16// executed to remove all previous govDAOs implementations and leave the last one.
17var allowedDAOs []string
18
19// proposals contains all the proposals in history.
20var proposals *Proposals = NewProposals()
21
22// Remember this realm for rendering.
23var gRealm = runtime.CurrentRealm()
24
25// Render calls directly to Render's DAO implementation.
26// This allows to have this realm as the main entry point for everything.
27func Render(p string) string {
28 return dao.Render(gRealm.PkgPath(), p)
29}
30
31// MustCreateProposal is an utility method that does the same as CreateProposal,
32// but instead of erroing if something happens, it panics.
33func MustCreateProposal(cur realm, r ProposalRequest) ProposalID {
34 pid, err := CreateProposal(cur, r)
35 if err != nil {
36 panic(err.Error())
37 }
38
39 return pid
40}
41
42// ExecuteProposal will try to execute the proposal with the provided ProposalID.
43// If the proposal was denied, it will return false. If the proposal is correctly
44// executed, it will return true. If something happens this function will panic.
45func ExecuteProposal(cur realm, pid ProposalID) bool {
46 execute, err := dao.PreExecuteProposal(pid)
47 if err != nil {
48 panic(err.Error())
49 }
50
51 if !execute {
52 return false
53 }
54 prop, err := GetProposal(cur, pid)
55 if err != nil {
56 panic(err.Error())
57 }
58 if err := prop.executor.Execute(cross); err != nil {
59 panic(err.Error())
60 }
61 return true
62}
63
64// CreateProposal will try to create a new proposal, that will be validated by the actual
65// govDAO implementation. If the proposal cannot be created, an error will be returned.
66func CreateProposal(cur realm, r ProposalRequest) (ProposalID, error) {
67 author, err := dao.PreCreateProposal(r)
68 if err != nil {
69 return -1, err
70 }
71
72 p := &Proposal{
73 author: author,
74 title: r.title,
75 description: r.description,
76 executor: r.executor,
77 allowedDAOs: allowedDAOs[:],
78 }
79
80 pid := proposals.SetProposal(p)
81 dao.PostCreateProposal(r, pid)
82
83 chain.Emit("ProposalCreated",
84 "id", strconv.FormatInt(int64(pid), 10),
85 )
86
87 return pid, nil
88}
89
90func MustVoteOnProposal(cur realm, r VoteRequest) {
91 if err := VoteOnProposal(cur, r); err != nil {
92 panic(err.Error())
93 }
94}
95
96// VoteOnProposal sends a vote to the actual govDAO implementation.
97// If the voter cannot vote the specified proposal, this method will return an error
98// with the explanation of why.
99func VoteOnProposal(cur realm, r VoteRequest) error {
100 return dao.VoteOnProposal(r)
101}
102
103// MustVoteOnProposalSimple is like MustVoteOnProposal but intended to be used through gnokey with basic types.
104func MustVoteOnProposalSimple(cur realm, pid int64, option string) {
105 MustVoteOnProposal(cur, VoteRequest{
106 Option: VoteOption(option),
107 ProposalID: ProposalID(pid),
108 })
109}
110
111func MustGetProposal(cur realm, pid ProposalID) *Proposal {
112 p, err := GetProposal(cur, pid)
113 if err != nil {
114 panic(err.Error())
115 }
116
117 return p
118}
119
120// GetProposal gets created proposal by its ID
121func GetProposal(cur realm, pid ProposalID) (*Proposal, error) {
122 if err := dao.PreGetProposal(pid); err != nil {
123 return nil, err
124 }
125
126 prop := proposals.GetProposal(pid)
127
128 if err := dao.PostGetProposal(pid, prop); err != nil {
129 return nil, err
130 }
131
132 return prop, nil
133}
134
135// UpdateImpl is a method intended to be used on a proposal.
136// This method will update the current govDAO implementation
137// to a new one. AllowedDAOs are a list of realms that can
138// call this method, in case the new DAO implementation had
139// a breaking bug. Any value set as nil will be ignored.
140// If AllowedDAOs field is not set correctly, the actual DAO
141// implementation wont be able to execute new Proposals!
142func UpdateImpl(cur realm, r UpdateRequest) {
143 gRealm := runtime.PreviousRealm().PkgPath()
144
145 if !InAllowedDAOs(gRealm) {
146 panic("permission denied for prev realm: " + gRealm)
147 }
148
149 if r.AllowedDAOs != nil {
150 allowedDAOs = r.AllowedDAOs
151 }
152
153 if r.DAO != nil {
154 dao = r.DAO
155 }
156}
157
158func AllowedDAOs() []string {
159 dup := make([]string, len(allowedDAOs))
160 copy(dup, allowedDAOs)
161 return dup
162}
163
164func InAllowedDAOs(pkg string) bool {
165 if len(allowedDAOs) == 0 {
166 return true // corner case for initialization
167 }
168 for _, d := range allowedDAOs {
169 if pkg == d {
170 return true
171 }
172 }
173 return false
174}