Kind Realm (renderable)
Name v0
Namespace moul / gnopm / registry
Exported functions 7
Module gno.land/r/moul/gnopm/registry/v0
gno 0.9 registry.gno gno
⧉
1 // Package registry is an open, on-chain map from a deployed gno package path 2 // back to the source that produced it: repository, commit, directory. 3 // 4 // It is the realm half of gno.land/p/moul/gnopm/v0, which holds the domain 5 // model and the whole of the reasoning; this file is wiring. Every exported 6 // mutation is a crossing function that resolves the caller, forwards to the 7 ClaimCount () int
HasClaims (pkgPath string) bool
OwnerClaim (pkgPath string) (repo string, commit string, dir string, ok bool)
PackageCount () int
Register (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pkgPath string, repo string, commit string, dir string, ref string)
Render (path string) string
Withdraw (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pkgPath string)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
// library, aborts on error (the only way to revert state in gno) and emits an
8 // event for indexers.
9 //
10 // # It cannot promise, and does not pretend to
11 //
12 // Nothing here is verified and nothing here can be. A realm cannot clone a
13 // repository, so it cannot check that the bytes at the claimed commit are the
14 // bytes deployed at the claimed path. What it stores is testimony under a
15 // signature: this address says this package came from that source.
16 //
17 // That is still worth storing, for two reasons.
18 //
19 // First, it is testimony in the exact shape a verifier needs. Path, repository,
20 // commit and directory are precisely the four inputs to "hash the addpkg
21 // payload of that directory and compare it with what the chain hands back",
22 // which gnopm already does against a local tree (`gnopm verify -deployed`). The
23 // registry does not answer the question; it makes the question answerable by
24 // anything that can clone.
25 //
26 // Second, the chain knows who signed. A claim from the address that owns the
27 // package path's namespace comes from the party that controls the path, and
28 // OwnedBy reports that. It is computed on every read, never stored, because a
29 // name can be transferred and a stored answer would rot into exactly the kind
30 // of stale claim this realm exists to distinguish from a live one.
31 //
32 // # Open, and tagged
33 //
34 // Anyone may claim any path, including one they had nothing to do with. That is
35 // deliberate: gating registration on namespace ownership would leave the map
36 // empty on day one, when almost nothing has been registered by its own
37 // deployer, and an empty registry teaches nobody anything. A stranger's claim
38 // is not suppressed, it is labelled and ranked below the owner's, and Render
39 // never presents an unverified claim as a fact.
40 //
41 // A claimant may always withdraw their own claim, and may never touch anyone
42 // else's.
43 package registry
44
45 import (
46 "chain"
47 "chain/runtime"
48
49 pm "gno.land/p/moul/gnopm/v0"
50 "gno.land/r/sys/users"
51 )
52
53 var reg = pm.New()
54
55 // caller is the address that crossed into this realm. Deliberately not
56 // restricted to end users: a realm may hold a namespace, and a DAO registering
57 // the source of the packages it governs is the same operation.
58 func caller(cur realm) address {
59 if !cur.IsCurrent() {
60 panic( "gnopm/registry: spoofed realm" )
61 }
62 return cur.Previous().Address()
63 }
64
65 func must(err error ) {
66 if err != nil {
67 panic(err)
68 }
69 }
70
71 // resolveName is the r/sys/users half of the ownership rule, passed to the
72 // library so the library stays pure.
73 //
74 // isCurrent is deliberately ignored, matching r/moul/forge: a name that
75 // resolves through an alias still resolves to the same holder, so a namespace
76 // survives its owner renaming. IsDeleted folds the nil check in, which is what
77 // its own doc comment asks call sites to rely on.
78 func resolveName(name string ) (address, bool ) {
79 data, _ := users.ResolveName(name)
80 if data.IsDeleted() {
81 return "" , false
82 }
83 return data.Addr(), true
84 }
85
86 // Register records that pkgPath was built from dir of repo at commit.
87 //
88 // Calling it again for the same path replaces the caller's own claim and
89 // nobody else's, so moving a claim to a new commit after a redeploy is one
90 // call with no read first.
91 //
92 // ref is optional and is never the thing verified: a ref moves, a commit does
93 // not. It is recorded so a reader can tell a claim pinned to a released tag
94 // from one pinned to a commit on nobody's branch, and so a verifier can report
95 // a commit that has since been orphaned by a force-push.
96 //
97 // dir is empty when the package sits at the repository root.
98 func Register(cur realm, pkgPath, repo, commit, dir, ref string ) {
99 a := caller(cur)
100 _, err := reg.Register(a, runtime.ChainHeight(), pkgPath, repo, commit, dir, ref)
101 must(err)
102 chain.Emit( "SourceClaimed" ,
103 "pkgpath" , pkgPath,
104 "claimant" , a.String(),
105 "repo" , repo,
106 "commit" , commit,
107 )
108 }
109
110 // Withdraw removes the caller's own claim about pkgPath.
111 func Withdraw(cur realm, pkgPath string ) {
112 a := caller(cur)
113 must(reg.Withdraw(a, pkgPath))
114 chain.Emit( "SourceWithdrawn" , "pkgpath" , pkgPath, "claimant" , a.String())
115 }
116
117 // PackageCount is how many package paths carry at least one claim.
118 func PackageCount() int { return reg.Size() }
119
120 // ClaimCount is the total number of claims across every path.
121 func ClaimCount() int { return reg.Claims() }
122
123 // HasClaims reports whether anything has been said about pkgPath. Cheap enough
124 // for another realm or an indexer to ask per package.
125 func HasClaims(pkgPath string ) bool { return reg.Package(pkgPath) != nil }
126
127 // OwnerClaim returns the repository, commit and directory claimed by the party
128 // that owns pkgPath's namespace, and whether such a claim exists.
129 //
130 // This is the only read that filters, and it filters on the one signal the
131 // chain can actually prove. Everything else a caller wants is in Render or in
132 // the events.
133 func OwnerClaim(pkgPath string ) (repo, commit, dir string , ok bool ) {
134 p := reg.Package(pkgPath)
135 if p == nil {
136 return "" , "" , "" , false
137 }
138 p.IterateClaims( func (c *pm.Claim) bool {
139 if c.OwnedBy(resolveName) {
140 repo, commit, dir, ok = c.Repo, c.Commit, c.Dir, true
141 return true // stop
142 }
143 return false
144 })
145 return repo, commit, dir, ok
146 }
147
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.