upgrade.gno
2.55 Kb · 73 lines
1package governance
2
3import (
4 "errors"
5 "gno.land/r/gnoswap/access"
6)
7
8// RegisterInitializer registers a version-specific initializer. Each version
9// (e.g. v1, v2) calls this function from its init body to plug itself into
10// the proxy.
11//
12// The initializer constructs the version's IGovernance from the supplied
13// IGovernanceStore and GovStakerAccessor. It receives a realm value that
14// resolves to the governance proxy realm — the only address with write
15// permission on the shared KV store — so any per-version store bootstrap
16// performed inside the initializer passes the proxy's authorization check.
17//
18// Security: Only contracts within the domain path can register initializers.
19// Each package path can only register once to prevent duplicate registrations.
20func RegisterInitializer(cur realm, initializer func(_ int, rlm realm, governanceStore IGovernanceStore, stakerAccessor GovStakerAccessor) IGovernance) {
21 // `cur` captured here is the governance crossing frame. The wrapping
22 // closure forwards it to the version initializer so any store writes
23 // the initializer performs run under the proxy's identity rather than
24 // the version package's, which would fail the kvStore ACL.
25 initializerFunc := func(_ int, rlm realm, domainStore any) any {
26 if !rlm.IsCurrent() {
27 panic(errors.New(ErrSpoofedRealm))
28 }
29
30 currentGovernanceStore, ok := domainStore.(IGovernanceStore)
31 if !ok {
32 panic("domainStore is not an IGovernanceStore")
33 }
34 return initializer(0, rlm, currentGovernanceStore, newGovStakerAccessor())
35 }
36
37 err := versionManager.RegisterInitializer(0, cur, initializerFunc)
38 if err != nil {
39 panic(err)
40 }
41
42 err = updateImplementation()
43 if err != nil {
44 panic(err)
45 }
46}
47
48// UpgradeImpl switches the active governance implementation to a different version.
49// This function allows seamless upgrades from one version to another without
50// data migration or downtime.
51//
52// Security: Only admin or governance can perform upgrades.
53// The new implementation must have been previously registered via RegisterInitializer.
54func UpgradeImpl(cur realm, targetPackagePath string) {
55 // Ensure only admin or governance can perform upgrades
56 prev := cur.Previous()
57 access.AssertIsAdminOrGovernance(prev.Address())
58
59 err := versionManager.ChangeImplementation(0, cur, targetPackagePath)
60 if err != nil {
61 panic(err)
62 }
63
64 err = updateImplementation()
65 if err != nil {
66 panic(err)
67 }
68}
69
70// GetImplementationPackagePath returns the package path of the currently active implementation.
71func GetImplementationPackagePath() string {
72 return versionManager.GetCurrentPackagePath()
73}