migrate.gno
2.22 Kb · 66 lines
1package basedao
2
3import (
4 "errors"
5
6 "gno.land/p/samcrew/daokit"
7)
8
9// Making this action name extra explicit.
10const ActionChangeDAOImplementationKind = "gno.land/p/samcrew/basedao.ChangeDAOImplementation"
11
12type MigrateFn = func(prev *DAOPrivate, params []any, rlm realm) daokit.DAO
13
14type MigrationParamsFn = func() []any
15
16type actionChangeDAOImplementation struct {
17 label string
18 migrate MigrateFn
19}
20
21func (a *actionChangeDAOImplementation) String() string {
22 return "WARNING: this replaces the DAO's implementation.\n\n" +
23 "The migration function receives the DAO's live realm and full private\n" +
24 "state, so approving it grants whoever wrote it the DAO's authority.\n" +
25 "Read the code it refers to before voting.\n\n" +
26 "Migration: " + a.label
27}
28
29func NewChangeDAOImplementationHandler(dao *DAOPrivate, setImplem daokit.SetImplemFn, paramsFn MigrationParamsFn) daokit.ActionHandler {
30 if dao == nil || setImplem == nil || paramsFn == nil {
31 panic("nil arg")
32 }
33 return daokit.NewActionHandler(ActionChangeDAOImplementationKind, func(i interface{}, rlm realm) {
34 action, ok := i.(*actionChangeDAOImplementation)
35 if !ok {
36 panic(errors.New("invalid action type"))
37 }
38
39 migrated := action.migrate(dao, paramsFn(), rlm)
40 setImplem(migrated)
41 })
42}
43
44// The label is required and appears in the proposal a member votes on.
45//
46// Without it every migration renders as the same fixed sentence, so a voter sees
47// nothing distinguishing a routine upgrade from a takeover. A function value
48// cannot be rendered, so the caller has to say what it is — name the version,
49// the commit, or the change.
50//
51// It is NOT a safety control. Whoever writes the migration writes the label, so
52// a takeover can ship as "routine security patch". It exists so an honest
53// proposal can be told apart from another honest proposal, and so a voter has
54// something to check the code against. Read the migration.
55func NewChangeDAOImplementationAction(label string, migrate MigrateFn) daokit.Action {
56 if label == "" {
57 panic("migration label must not be empty")
58 }
59 if migrate == nil {
60 panic("migration function must not be nil")
61 }
62 return daokit.NewAction(ActionChangeDAOImplementationKind, &actionChangeDAOImplementation{
63 label: label,
64 migrate: migrate,
65 })
66}