upgrade.gno
2.58 Kb · 85 lines
1package pool
2
3import (
4 "errors"
5
6 "gno.land/r/gnoswap/access"
7)
8
9// RegisterInitializer registers a new pool implementation version.
10// This function is called by each version (v1, v2, etc.) during initialization
11// to register their implementation with the proxy system.
12//
13// The initializer function creates a new instance of the implementation
14// using the provided poolStore interface.
15//
16// The stateInitializer function creates the initial state for this version.
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, poolStore IPoolStore) IPool) {
21 initializerFunc := func(_ int, rlm realm, domainStore any) any {
22 if !rlm.IsCurrent() {
23 panic(errors.New(ErrSpoofedRealm))
24 }
25
26 currentPoolStore, ok := domainStore.(IPoolStore)
27 if !ok {
28 panic("domainStore is not an IPoolStore")
29 }
30
31 return initializer(0, rlm, currentPoolStore)
32 }
33
34 err := versionManager.RegisterInitializer(0, cur, initializerFunc)
35 if err != nil {
36 panic(err)
37 }
38
39 err = updateImplementation()
40 if err != nil {
41 panic(err)
42 }
43}
44
45// UpgradeImpl switches the active pool implementation to a different version.
46// This function allows seamless upgrades from one version to another without
47// data migration or downtime.
48//
49// Security: Only admin or governance can perform upgrades.
50// The new implementation must have been previously registered via RegisterInitializer.
51// The pool must not be locked (see assertPoolUnlocked).
52func UpgradeImpl(cur realm, packagePath string) {
53 // Ensure only admin or governance can perform upgrades
54 caller := cur.Previous().Address()
55 access.AssertIsAdminOrGovernance(caller)
56
57 assertPoolUnlocked()
58
59 err := versionManager.ChangeImplementation(0, cur, packagePath)
60 if err != nil {
61 panic(err)
62 }
63
64 err = updateImplementation()
65 if err != nil {
66 panic(err)
67 }
68}
69
70// assertPoolUnlocked panics if the pool's reentrancy lock is currently held.
71// It mirrors poolV1.assertPoolUnlocked (r/gnoswap/pool/v1/lock.gno): read-only,
72// so it is safe to call before the admin/governance authorization check too.
73// HasUnlocked() is false until a swap has ever run, so pools with no swap
74// history are unaffected.
75func assertPoolUnlocked() {
76 s := NewPoolStore(kvStore)
77 if s.HasUnlocked() && !s.GetUnlocked() {
78 panic(errors.New(errUpgradeWhileLocked))
79 }
80}
81
82// GetImplementationPackagePath returns the package path of the currently active implementation.
83func GetImplementationPackagePath() string {
84 return versionManager.GetCurrentPackagePath()
85}