Realm on pearl-1
upgrade_registry
gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry
realmpipeline-applicationupgrade-tracking
Records successive versions of a logical component and which is current. GitHub-pipeline application #3.
Identity
| Import path | gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry |
|---|---|
| Kind | realm (/r/) |
| Chain | pearl-1 |
| Namespace | g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3 |
| Realm address | g1g453tcmapqn6hj9zlydfz3mt3vxh8gq5vwv8sg derived, never confirmed against the realm |
Provenance
chain-attested| Deployed at height | 602,876 |
|---|---|
| Deploy transaction | 532be90ab90521b0d6d4b3f983ede9dd315c8975cf30ad5c8984837f4d57e34d look it up on the RPC |
| Deployer | g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3 |
| Gas used | 23,191,456 |
| Storage | 17,492 bytes, deposit 1749200ugnot |
| Files on chain | gnomod.toml upgrade_registry.gno |
| Deployed bytes | upgrade_registry.gno — 13,940 bytes |
| sha256 | ff13c79b34e90d96910a0003207d7981737d32c0557f15beb5e730b4b4c87810 |
Do not take the hash above on trust. $download returns the bytes pearl-1 is actually running; this command fetches them and prints their digest, which should equal the one in the table:
curl -sS 'https://pearl.testnets.gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry$download&file=upgrade_registry.gno' | shasum -a 256Expected: ff13c79b34e90d96910a0003207d7981737d32c0557f15beb5e730b4b4c87810 — 13,940 bytes. This was checked for all 21 packages while building this site's architecture record; every one matched. Use curl: pearl's edge answers Python's default user-agent with HTTP 403.
API
chain-derived 8 exported functions, 1 type.
Every function below deep-links to gnoweb's call builder, which generates a ready-to-run gnokey maketx call for it:
AcceptOwnershipDeprecateGetInfoGetMigrationChainGetOwnerContractsRegisterRenderTransferOwnership
Overview
This package carries no package doc comment on chain, so there is nothing for vm/qdoc to return and gnoweb's $help Overview is empty. Deployed bytes are immutable, so this cannot be repaired in place — see catalog/DISCOVERY_APIDOCS.md §2.4.
Imports
chain/runtime/unsafestrconvstrings
Constants and variables
const (
MaxNameLen = 64
MaxChainLen = 50 // GetMigrationChain traversal/output bound (marked when hit)
// Render bounds (re-audit): rendering is paginated and the per-row
// "latest" annotation walks a bounded number of hops, so an
// attacker-built long chain cannot blow up the realm page.
MaxRenderEntries = 100
RenderLatestHops = 10
)
Types
type ContractEntry
type ContractEntry struct {
Address address
Owner address // current manager (accepted)
PendingOwner address // nominated, not yet accepted; empty if none
Name string
Deprecated bool
Successor address // address of the upgraded contract, empty if current
}
ContractEntry represents a registered contract and its upgrade status.
An entry's Address is ALWAYS the address that called Register — a contract can only register itself. That call is the proof of control: nobody can claim an address they don't command, so a Deprecate redirect on an entry always originates from whoever genuinely controlled the contract. Entries are permanent by design: migration history is what consumers rely on, so it must not be erasable (and a delete would reopen re-registration squatting).
Ownership is two-step (re-audit 2026-09-02): Register/Transfer only NOMINATE an owner; the nominee must AcceptOwnership. Until then the entry is owned by the contract itself, so nobody's address can be attached as "owner" without their consent.
| Exported field | Type | Doc |
|---|---|---|
Address | address | |
Owner | address | current manager (accepted) |
PendingOwner | address | nominated, not yet accepted; empty if none |
Name | string | |
Deprecated | bool | |
Successor | address | address of the upgraded contract, empty if current |
Functions
AcceptOwnership
func AcceptOwnership(cur realm, contractAddr address) string
Crossing function. Callable from a transaction via
MsgCall, and from another realm asAcceptOwnership(cross(cur), ...).
AcceptOwnership completes a nominated ownership: only the pending owner can accept, and only acceptance moves the entry (and the ownerContracts index) to them.
Deprecate
func Deprecate(cur realm, contractAddr, successorAddr address) string
Crossing function. Callable from a transaction via
MsgCall, and from another realm asDeprecate(cross(cur), ...).
Deprecate marks a contract as deprecated and points to its successor. Only the entry's owner can deprecate. The successor must itself be a REGISTERED entry — registration is self-proving, so a successor can never be a dangling pointer or an address squatted by a third party — and the successor entry must be OWNED BY THE CALLER (re-audit: without consent, an attacker could chain their entry INTO a legitimate contract, forging "official predecessor" provenance). Consent is checked AT CALL TIME: transferring the successor entry away later does not unlink an existing chain — the attestation is that both ends shared an owner when the deprecation was recorded.
GetInfo
func GetInfo(contractAddr address) string
GetInfo returns a one-line summary for a contract.
GetMigrationChain
func GetMigrationChain(contractAddr address) string
GetMigrationChain returns the full upgrade path starting from the given address, at most MaxChainLen hops. A chain longer than the bound is explicitly marked as truncated (re-audit: silent truncation presented a mid-chain node as the endpoint).
GetOwnerContracts
func GetOwnerContracts(owner address) string
GetOwnerContracts returns all contract addresses whose ACCEPTED owner is the given address (nominations don't count until accepted).
Register
func Register(cur realm, name string, owner address) string
Crossing function. Callable from a transaction via
MsgCall, and from another realm asRegister(cross(cur), ...).
Register adds the CALLING contract to the registry — the entry's address is the caller's own address, which is the proof of control. owner NOMINATES a manager (team EOA or governance realm); it holds no power until it calls AcceptOwnership (nobody can be made an owner without consent — re-audit). Pass "" to manage from the contract itself — but note (audit Y4): entries are permanent, so an entry managed by a contract that has no code path for calling this registry again is FROZEN as active forever: never deprecatable, never transferable. Realms registering from init() should nominate an EOA or governance manager instead.
Render
func Render(path string) string
Render returns a markdown overview of the most recent entries. Never panics.
TransferOwnership
func TransferOwnership(cur realm, contractAddr, newOwner address) string
Crossing function. Callable from a transaction via
MsgCall, and from another realm asTransferOwnership(cross(cur), ...).
TransferOwnership NOMINATES a new owner for a registry entry; the nominee must AcceptOwnership to take control (two-step — re-audit). Passing "" clears a pending nomination.
Doc text is reproduced as vm/qdoc returns it. The node markdown-escapes doc comments, so a bracket or angle bracket may carry a backslash the committed source does not have. The source itself is at source and in this repository.
Dependencies
chain-attested| Imports | chain/runtime/unsafe, strconv, strings |
|---|---|
| First-party dependencies | none |
| Used by | none |
Known limitations
curatedThe manifest records no limitation for this package. That is an absence of a recorded caveat, not a proof that none exists — the deployment record below is the fuller account, and it always carries its own "what was NOT verified live" section.
Source and records
| Source file | pearl/r/upgrade_registry/upgrade_registry.gno at commit 6a510c665a53 in the project repository (not public — the digest command above is the check that needs no repository) |
|---|---|
| Matches the deployed bytes | yes — byte-identical |
| Upstream repository | https://github.com/SillyZir/upgrade_registry |
| Deployed from commit | 2d5a74870b08d70ff8e56e6e1efbace1803dd3bd |
| Records | catalog/applications.md#upgrade_registrypearl/DEPLOYMENT.md |