upgrade.gno
3.01 Kb · 95 lines
1package pool
2
3import (
4 "errors"
5
6 "gno.land/r/gnoswap/access/v1"
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// Parameters:
14// - cur: Current realm context; callers use cross(cur) when crossing into this
15// realm.
16// - initializer: Version factory receiving the forwarded discriminator, current
17// realm, and shared IPoolStore; it returns the implementation instance to
18// register and later activate.
19//
20// Security: Only contracts within the domain path can register initializers.
21// Each package path can only register once to prevent duplicate registrations.
22func RegisterInitializer(cur realm, initializer func(_ int, rlm realm, poolStore IPoolStore) IPool) {
23 initializerFunc := func(_ int, rlm realm, domainStore any) any {
24 access.AssertIsRlmCurrent(0, rlm)
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// Parameters:
50// - cur: Current realm context; callers use cross(cur) when crossing into this
51// realm.
52// - packagePath: Full package path of a version previously registered for this
53// pool domain.
54//
55// Security: Only admin or governance can perform upgrades.
56// The new implementation must have been previously registered via RegisterInitializer.
57// The pool must not be locked (see assertPoolUnlocked).
58func UpgradeImpl(cur realm, packagePath string) {
59 // Ensure only admin or governance can perform upgrades
60 caller := cur.Previous().Address()
61 access.AssertIsAdminOrGovernance(caller)
62
63 assertPoolUnlocked()
64
65 err := versionManager.ChangeImplementation(0, cur, packagePath)
66 if err != nil {
67 panic(err)
68 }
69
70 err = updateImplementation()
71 if err != nil {
72 panic(err)
73 }
74}
75
76// assertPoolUnlocked panics if the pool's reentrancy lock is currently held.
77// It mirrors poolV1.assertPoolUnlocked (r/gnoswap/pool/v1/lock.gno): read-only,
78// so it is safe to call before the admin/governance authorization check too.
79// HasUnlocked() is false until a swap has ever run, so pools with no swap
80// history are unaffected.
81func assertPoolUnlocked() {
82 s := NewPoolStore(kvStore)
83 if s.HasUnlocked() && !s.GetUnlocked() {
84 panic(errors.New(errUpgradeWhileLocked))
85 }
86}
87
88// GetImplementationPackagePath returns the package path of the currently active implementation.
89//
90// Returns:
91// - packagePath: Full package path of the active implementation; empty before
92// any version has been registered.
93func GetImplementationPackagePath() string {
94 return versionManager.GetCurrentPackagePath()
95}