upgrade.gno

package ucs03_zkgm

import (
	"strings"

	"gno.land/r/onbloc/ibc/union/access"
)

func ProxyPkgPath() string {
	return proxyPkgPath
}

func ProxyAddress() address {
	return proxyAddress
}

// RegisterImpl records an impl constructor under the calling realm's package
// path. It is called from the impl realm's init, so the path is permanent once
// installed: re-registration is rejected. The caller must be a sub-realm of this
// proxy (its path must be prefixed by the proxy path), matching core's host
// registration rule.
func RegisterImpl(cur realm, constructor func(store IStore) IApp) {
	currentPath := cur.PkgPath()
	previousPath := cur.Previous().PkgPath()

	prefix := currentPath + "/"

	if !strings.HasPrefix(previousPath, prefix) {
		panic("previous impl path is not a prefix of the current impl path")
	}

	if _, ok := implConstructors[previousPath]; ok {
		panic("impl already registered")
	}

	implConstructors[previousPath] = constructor
}

// UpdateImpl installs or re-points the implementation following the bootstrap and
// steady-state tiers of the trust model. It is admin-gated and injects the
// proxy-owned store into the registered constructor for path.
func UpdateImpl(cur realm, path string) {
	access.AssertCanCall(0, cur, SelectorUpdateImpl)

	constructor, ok := implConstructors[path]
	if !ok {
		panic("impl constructor not found")
	}

	oldImplPath := currentImplPath
	currentImplPath = path
	currentImpl = constructor(store)
	emitZkgmImplUpdatedEvent(cur.Previous().PkgPath(), oldImplPath, path, []string{path})
}

// mustGetImpl returns the installed impl, panicking until the first UpdateImpl.
func mustGetImpl() IApp {
	if currentImpl == nil {
		panic("implementation not installed")
	}

	return currentImpl
}