proxy.gno

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