upgrade.gno
1.68 Kb · 65 lines
1package core
2
3import (
4 "strings"
5
6 "gno.land/r/onbloc/ibc/union/access"
7)
8
9// upgrade.gno is the single admin-gated swap point for the IBC host logic. The
10// proxy keeps the Store and identity stable across upgrades; only `impl` changes.
11//
12// Activation note: core's public entrypoints delegate to the installed impl.
13// The impl realm registers its constructor from init(), and UpdateImpl injects
14// the proxy-owned Store before any delegated entrypoint can run.
15var (
16 currentImplPath string
17 currentImpl ICore
18 implConstructors map[string]func(store IStore) ICore
19)
20
21func init() {
22 currentImpl = nil
23 currentImplPath = ""
24 implConstructors = make(map[string]func(store IStore) ICore)
25}
26
27func RegisterImpl(cur realm, constructor func(store IStore) ICore) {
28 currentPath := cur.PkgPath()
29 previousPath := cur.Previous().PkgPath()
30
31 prefix := currentPath + "/"
32
33 if !strings.HasPrefix(previousPath, prefix) {
34 panic("previous impl path is not a prefix of the current impl path")
35 }
36
37 if _, ok := implConstructors[previousPath]; ok {
38 panic("impl already registered")
39 }
40
41 implConstructors[previousPath] = constructor
42}
43
44// UpdateImpl installs or re-points the implementation. It is admin-gated and
45// injects the proxy-owned store into the target, so the store needs no public
46// getter — the only way to obtain it is through this gated install.
47func UpdateImpl(cur realm, path string) {
48 access.AssertCanCall(0, cur, SelectorUpdateImpl)
49
50 constructor, ok := implConstructors[path]
51 if !ok {
52 panic("impl constructor not found")
53 }
54
55 currentImplPath = path
56 currentImpl = constructor(store)
57}
58
59func mustGetImpl() ICore {
60 if currentImpl == nil {
61 panic("implementation not installed")
62 }
63
64 return currentImpl
65}