Skip to content

Commit 01870a3

Browse files
committed
CNS Registry refactoring
1 parent 2921403 commit 01870a3

File tree

11 files changed

+191
-169
lines changed

11 files changed

+191
-169
lines changed

convex-core/src/main/cvx/convex/core/core.cvx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -593,10 +593,7 @@
593593
:examples [{:code "(resolve convex.asset)"}]
594594
:signature [{:params [& args]}]}}
595595
[sym]
596-
`(call* *registry*
597-
0
598-
'cns-resolve
599-
(quote ~sym)))
596+
`(~*registry*/resolve (quote ~sym)))
600597

601598
(defmacro import
602599
^{:doc {:description ["Imports a library for use in the current environment."

convex-core/src/main/cvx/convex/core/registry.cvx

Lines changed: 81 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@
5353
;; Map of `path vector` -> `segment name` -> `[value trust-monitor meta child]`
5454
;; Where:
5555
;; value = Target value for CNS resolution, usually an address or scoped address
56-
;; trust-monitor = controller for this CNS entry
56+
;; trust-monitor = controller for this CNS record
5757
;; meta = metadata field
5858
;; child = child CNS node, may be nil. Usually a scoped address defining an actor and a path key e.g. [#5675 "bob"]
59-
;;
59+
;;
60+
;; Trust monitor may be called with following actions:
61+
;; :update - Update CNS record
62+
;;
6063
;; Node key is implementation defined in general, but for main registry uses:
6164
;; Empty vector for CNS root
6265
;; Vector of segment strings for paths
@@ -78,6 +81,14 @@
7881
(split (name sym) \.)
7982
(fail :ARGUMENT "CNS name must be a Symbol")))
8083

84+
(defn -check-values [values]
85+
(cond
86+
(vector? values)
87+
(cond
88+
(= 4 (count values)) :OK
89+
(fail :ARGUMENT "CNS record must have 4 elements"))
90+
(fail :ARGUMENT "CNS record values must be a Vymbol")))
91+
8192
;; ========================================================
8293
;; CNS User API - See CAD014
8394

@@ -117,15 +128,17 @@
117128
(get (read sym) 0))
118129

119130
(defn create ^{
120-
:doc {:description "Creates a CNS entry with given reference, controller and metadata"
131+
:doc {:description "Creates a CNS entry with given data [value, controller, metadata, child]"
121132
:examples [{:code "(*registry*/create 'my.actor.name target *address* {:some :metadata})"}]
122-
:signature [{:params [sym]}]}}
123-
([sym] (recur sym nil *address* nil nil))
124-
([sym addr] (recur sym addr *address* nil nil))
125-
([sym addr cont] (recur sym addr cont nil nil))
126-
([sym addr cont meta] (recur sym addr cont meta nil))
127-
([sym addr cont meta child]
128-
(let [path (-check sym)
133+
:signature [{:params [sym]}
134+
{:params [sym value]}
135+
{:params [sym value cont]}
136+
{:params [sym value cont meta]}
137+
{:params [sym value cont meta child]}]}}
138+
([sym & vals]
139+
(let [nv (count vals)
140+
_ (cond (> nv 4) (fail :ARITY "Too many CNS record values"))
141+
path (-check sym)
129142
n (count path)]
130143
(cond (zero? n) (fail :ARGUMENT "CNS path must have at least one segment"))
131144
(loop [i 0
@@ -135,109 +148,83 @@
135148
(nil? ref)
136149
(fail :STATE (str "No CNS child path at: " (slice path 0 i)))
137150

138-
;; are we at end of path? if so perform write at current position
151+
;; are we at end of path? if so, perform write at current position
139152
(>= (inc i) n)
140-
(call ref (cns-write pname addr cont meta child) )
141-
142-
(if-let [rec (call ref (cns-read pname))]
143-
(recur (inc i) (first rec))
153+
(let [rec (cond (< nv 4)
154+
(let [evs (call ref (cns-read pname))
155+
evs (or evs [nil *address* nil nil])]
156+
(concat vals (slice evs nv 4)))
157+
vals) ]
158+
(call ref (cns-write pname rec)))
159+
160+
(let [rec (call ref (cns-read pname))]
161+
(if-let [child (get rec 3)]
162+
(recur (inc i) child)
144163

145-
;; need to construct a new (empty) intermediate CNS child node here
146-
(let [nref (call ref (cns-create-node pname cont))]
147-
(call ref (cns-write pname nil cont nil nref) )
148-
(recur (inc i) nref)))
164+
;; need to construct a new (empty) intermediate CNS child node here
165+
(let [cont (or (get vals 1) *address*) ;; controller for intermediate node
166+
nref (call ref (cns-create-node pname cont))
167+
rec (cond rec
168+
(assoc rec 3 nref) ;; update existing child node link
169+
[nil cont nil nref])]
170+
(call ref (cns-write pname rec))
171+
(recur (inc i) nref))))
149172
))
150173
)
151174
;; TODO: Not clear what default return value should be? [~*address* path]?
152175
)))
153176

177+
(defn update
178+
^{:doc {:description "Updates a CNS entry with given value. Record must already exist."
179+
:signature [{:params [sym value]}]}}
180+
[sym value]
181+
(if-let [rec (read sym)]
182+
(apply create sym (assoc rec 0 value))
183+
(fail :STATE (str "CNS record to update does not exist: " sym))))
184+
154185
(defn control
186+
^{:doc {:description "Change controller for a CNS node."
187+
:signature [{:params [name controller]}]}}
155188
[sym cont]
156189
(if-let [rec (read sym)]
157-
(let [[v c m child] rec]
158-
(update sym v cont m child))
190+
(apply create sym (assoc rec 1 cont))
159191
(fail :STATE "CNS record does not exist")))
160192

161-
162-
(defn change-control
163-
^{:callable true
164-
:doc {:description "Changes controller for a CNS node."
165-
:examples [{:code "(call *registry* (cns-control 'my.actor trust-monitor-address)"}]
166-
:signature [{:params [name addr]}]}}
167-
[cont]
168-
(let [owners cns-owners
169-
own (get owners *scope*)]
170-
(cond
171-
(trust/trusted? own *caller* :control)
172-
(set! cns-owners (assoc owners *scope* cont))
173-
(fail :TRUST "No control right for CNS node"))))
174-
193+
;; private function to get controller for a node
175194
(defn -controller [path]
176195
(cond
177-
(empty? *scope*) root-controller
178-
(let [[& ps p] *scope*]
196+
(empty? path) root-controller
197+
(let [[& ps p] path]
179198
(get-in cns-database [ps p 1]))))
180199

181200
;; ============================================================================
182201
;; Standard CNS SPI - exprected to be callable by libraries / advanced users
183202

184-
(defn cns-control
203+
(defn change-control
185204
^{:callable true
186-
:doc {:description "Updates a CNS name mapping to set a new controller. May only be performed by a current controller."
205+
:doc {:description "Changes controller for a CNS node. May only be performed by a current controller."
187206
:examples [{:code "(call *registry* (cns-control 'my.actor trust-monitor-address)"}]
188207
:signature [{:params [name addr]}]}}
189-
[sym controller]
190-
(let [path (-check sym)
191-
record (get cns-database path)]
192-
(when (nil? record)
193-
(fail :STATE "CNS record does not exist"))
194-
(when (not (trust/trusted? (second record) *caller* :control))
195-
(fail :TRUST "Caller is not trusted with transferring control for that CNS record"))
196-
(set-in! cns-database [path 1] controller)))
197-
198-
(defn cns-resolve
199-
^{:callable true
200-
:doc {:description "Resolves a name in the Convex Name Service."
201-
:examples [{:code "(call *registry* (cns-resolve 'convex.registry)"}]
202-
:signature [{:params [addr]}]}}
203-
[sym]
204-
(let [path (-check sym)
205-
record (get cns-database path)]
206-
(if record (first record) nil)))
207-
208-
(defn cns-update
209-
^{:callable true
210-
:doc {:description "Updates or adds a name mapping in the Convex Name Service. Only the owner of a CNS record may update the mapping for an existing name"
211-
:examples [{:code "(call *registry* (cns-update 'my.actor addr)"}]
212-
:signature [{:params [name addr]}]}}
213-
([sym addr]
214-
(recur sym addr nil))
215-
([sym addr meta]
216-
(when-not (account addr)
217-
(fail :NOBODY "Can only use an existing account"))
218-
(let [path (-check sym)
219-
record (get cns-database path)
220-
monitor (if record (second record) *caller*)] ;; TODO limit ability to crteate top level CNS
221-
(and record (not (trust/trusted? monitor *caller* :update))
222-
(fail :TRUST "Unauthorised update to CNS record"))
223-
224-
(set! cns-database
225-
(assoc cns-database
226-
path
227-
[addr monitor meta])))))
208+
[controller]
209+
(let [path *scope*]
210+
(when (not (trust/trusted? (get cns-owners path) *caller* :control))
211+
(fail :TRUST "Formbitten to change controller for CNS node"))
212+
(set-in! cns-owners [path] controller)))
228213

229214
(defn cns-create-node
230215
^{:callable true
231-
:doc {:description "Creates a child CNS node."
216+
:doc {:description "Creates a child CNS node, if it does not yet exist. Returns child node scoped reference."
232217
:examples [{:code "(call parent-node (cns-create-node \\\"child-name\\\"))"}]
233218
:signature [{:params [sym]}]}}
234219
[pname owner]
235-
(or (trust/trusted? (get cns-owners *scope*) *caller* :create pname) (fail :TRUST "No permission to create CNS node"))
236-
(let [path (conj *scope* pname)]
237-
(if (get cns-database path) (fail :STATE "CNS node already exists"))
238-
(set-in! cns-owners [path] owner)
239-
(set-in! cns-database [path] {})
240-
[~*address* path]))
220+
(or (trust/trusted? (get cns-owners *scope*) *caller* :create pname) (fail :TRUST "Forbidden to create CNS node"))
221+
(let [rec (get-in cns-database [*scope* pname])
222+
_ (if-let [existing (get rec 3)] (return existing))
223+
path (conj *scope* pname)
224+
ref [~*address* path]]
225+
(set-in! cns-owners [path] owner) ;; new node owner
226+
(set-in! cns-database [path] {}) ;; new mapping to child records
227+
ref))
241228

242229
(defn cns-read
243230
^{:callable true
@@ -252,18 +239,21 @@
252239
:doc {:description "Writes a CNS record from this Actor. Assumes a path vector passed in *scope*."
253240
:examples [{:code "(call [cns-node cns-key] (cns-write \"my-name\" new-record))"}]
254241
:signature [{:params [sym]}]}}
255-
[pname addr cont meta child]
242+
[pname values]
243+
(or (str? pname) (fail :ARGUMENT "CNS path element must be a String"))
244+
(-check-values values)
256245
(let [sm (get cns-database *scope*)]
257-
(or (str? pname) (fail :ARGUMENT "CNS path element must be a string"))
258246
(or sm (error :STATE "CNS Node key not valid"))
259247
(if-let [rec (get sm pname)]
260248
;; This is an existing record, so check record controller
261-
(or (trust/trusted? (get rec 1) *caller* :update) (fail :TRUST "No permission to update CNS record"))
262-
;; This is a new record, so check create permission TODO use per-node monitor?
263-
(or (trust/trusted? (-controller *scope*) *caller* :create pname) (fail :TRUST "No permission to create CNS record")))
249+
(or (trust/trusted? (get rec 1) *caller* :update) (fail :TRUST "Forbidden to update CNS record"))
250+
251+
;; This is a new record, so check create permission
252+
(or (trust/trusted? (-controller *scope*) *caller* :create pname) (fail :TRUST "Forbidden to create CNS record")))
264253

265254
;; update record since at this point all required checks have passed
266-
(set-in! cns-database [*scope* pname] [addr cont meta child])))
255+
(set-in! cns-database [*scope* pname] values)
256+
values))
267257

268258
;; =========================================
269259
;; Trust SPI

convex-core/src/main/java/convex/core/init/Init.java

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
public class Init {
3333

3434
/**
35-
* Number of special "goverance" accounts. These hold all unissued coins
35+
* Number of special "governance" accounts. These hold all unissued coins
3636
*/
3737
public static final int NUM_GOVERNANCE_ACCOUNTS=8;
3838

@@ -178,8 +178,11 @@ public static State createBaseState(AccountKey governanceKey, AccountKey genesis
178178

179179
// Add the static defined libraries at addresses: TRUST_ADDRESS, REGISTRY_ADDRESS
180180
s = addStaticLibraries(s);
181+
182+
// Add the basic CNS tree
183+
s=addCNSBaseTree(s);
181184

182-
// Reload accounts with the libraries
185+
// Reload accounts with the base libraries
183186
accts = s.getAccounts();
184187
}
185188

@@ -252,13 +255,11 @@ public static State createBaseState(AccountKey governanceKey, AccountKey genesis
252255
private static State addStaticLibraries(State s) {
253256

254257
// At this point we have a raw initial State with no user or peer accounts
255-
s = doActorDeploy(s, "/convex/core/registry.cvx");
256-
s = doActorDeploy(s, "/convex/core/trust.cvx");
258+
s = doActorDeploy(s, "/convex/core/registry.cvx",false);
259+
s = doActorDeploy(s, "/convex/core/trust.cvx",false);
257260

258261
{ // Register core library now that registry exists
259-
Context ctx = Context.create(s, INIT_ADDRESS);
260-
ctx = ctx.eval(Reader.read("(call *registry* (cns-update 'convex.core " + CORE_ADDRESS + "))"));
261-
262+
Context ctx = Context.create(s, INIT_ADDRESS);
262263
s = ctx.getState();
263264
s = register(s, CORE_ADDRESS, "Convex Core Library", "Core utilities accessible by default in any account.");
264265

@@ -284,10 +285,9 @@ public static State createState(AccountKey genesisKey,List<AccountKey> peerKeys)
284285
public static State createState(AccountKey governanceKey, AccountKey genesisKey,List<AccountKey> peerKeys) {
285286
State s=createBaseState(governanceKey, genesisKey, peerKeys);
286287

287-
s = addCNSTree(s);
288288
s = addStandardLibraries(s);
289289
s = addTestingCurrencies(s);
290-
290+
s = addCNSExtraTree(s);
291291

292292
// Final funds check
293293
long finalTotal = s.computeTotalBalance();
@@ -339,9 +339,22 @@ private static State addStandardLibraries(State s) {
339339
return s;
340340
}
341341

342-
private static State addCNSTree(State s) {
342+
private static State addCNSBaseTree(State s) {
343343
Context ctx=Context.create(s, GOVERNANCE_ADDRESS);
344-
ctx=ctx.eval(Reader.read("(*registry*/create 'convex.cns *registry*)"));
344+
ctx=ctx.eval(Reader.read("(*registry*/create 'convex)"));
345+
ctx.getResult();
346+
347+
// convex.cns is alias to root cns namespace?
348+
ctx=ctx.eval(Reader.read("(*registry*/create 'convex.cns "+REGISTRY_ADDRESS+" *address* nil [#9 []])"));
349+
ctx.getResult();
350+
351+
ctx=ctx.eval(Reader.read("(*registry*/create 'convex.registry "+REGISTRY_ADDRESS+")"));
352+
ctx.getResult();
353+
354+
ctx=ctx.eval(Reader.read("(*registry*/create 'convex.core "+CORE_ADDRESS+")"));
355+
ctx.getResult();
356+
357+
ctx=ctx.eval(Reader.read("(*registry*/create 'convex.trust "+TRUST_ADDRESS+")"));
345358
ctx.getResult();
346359

347360
// check we can get access to general trust monitors
@@ -357,6 +370,17 @@ private static State addCNSTree(State s) {
357370
s=ctx.getState();
358371
return s;
359372
}
373+
374+
private static State addCNSExtraTree(State s) {
375+
Context ctx=Context.create(s, GOVERNANCE_ADDRESS);
376+
377+
// ctx=ctx.eval(Reader.read("(*registry*/create 'zoo "+TRUST_ADDRESS+")"));
378+
// ctx.getResult();
379+
380+
381+
s=ctx.getState();
382+
return s;
383+
}
360384

361385
public static Address calcPeerAddress(int userCount, int index) {
362386
return Address.create(GENESIS_ADDRESS.longValue() + userCount + index);
@@ -365,12 +389,16 @@ public static Address calcPeerAddress(int userCount, int index) {
365389
public static Address calcUserAddress(int index) {
366390
return Address.create(GENESIS_ADDRESS.longValue() + index);
367391
}
392+
393+
private static State doActorDeploy(State s, String resource) {
394+
return doActorDeploy(s,resource,true);
395+
}
368396

369397
// A CVX file contains forms which must be wrapped in a `(do ...)` and deployed as an actor.
370398
// First form is the name that must be used when registering the actor.
371399
//
372-
private static State doActorDeploy(State s, String resource) {
373-
Context ctx = Context.create(s, INIT_ADDRESS);
400+
private static State doActorDeploy(State s, String resource, boolean addCNS) {
401+
Context ctx = Context.create(s, GOVERNANCE_ADDRESS);
374402
ACell ADD_NETWORK_GOVERNANCE=Reader.read("(set-controller "+GOVERNANCE_ADDRESS+")");
375403

376404
try {
@@ -384,11 +412,13 @@ private static State doActorDeploy(State s, String resource) {
384412
if (ctx.isExceptional()) throw new Error("Error deploying actor: "+resource+"\n" + ctx.getValue());
385413
Address addr=ctx.getResult();
386414

387-
@SuppressWarnings("unchecked")
388-
AList<Symbol> qsym=(AList<Symbol>) forms.get(0);
389-
Symbol sym=qsym.get(1);
390-
ctx = ctx.eval(Code.cnsUpdate(sym, addr));
391-
if (ctx.isExceptional()) throw new Error("Error while registering actor:" + ctx.getValue());
415+
if (addCNS) {
416+
@SuppressWarnings("unchecked")
417+
AList<Symbol> qsym=(AList<Symbol>) forms.get(0);
418+
Symbol sym=qsym.get(1);
419+
ctx = ctx.eval(Code.cnsUpdate(sym, addr,GOVERNANCE_ADDRESS));
420+
if (ctx.isExceptional()) throw new Error("Error while registering actor:" + ctx.getValue());
421+
}
392422

393423
return ctx.getState();
394424
} catch (IOException e) {
@@ -432,7 +462,8 @@ private static State doCurrencyDeploy(State s, AVector<ACell> row) {
432462
if (ctx.isExceptional()) throw new Error("Error adding market liquidity: " + ctx.getValue());
433463

434464
Symbol sym=Symbol.create("currency."+symName);
435-
ctx = ctx.eval(Code.cnsUpdate(sym, addr));
465+
ctx = ctx.forkWithAddress(GOVERNANCE_ADDRESS);
466+
ctx = ctx.eval(Code.cnsUpdate(sym, addr,GOVERNANCE_ADDRESS));
436467
if (ctx.isExceptional()) throw new Error("Error registering currency in CNS: " + ctx.getValue());
437468
return ctx.getState();
438469
}

0 commit comments

Comments
 (0)