Skip to content

Comments

SPIKE: use offer result without zoe offer#11256

Closed
dckc wants to merge 21 commits intomasterfrom
dc-wallet-justin
Closed

SPIKE: use offer result without zoe offer#11256
dckc wants to merge 21 commits intomasterfrom
dc-wallet-justin

Conversation

@dckc
Copy link
Member

@dckc dckc commented Apr 11, 2025

closes: #8733, #10926, #8550
refs:

Description

This is an exploration of a design space...

  • test(boot): atomicSwap A<->B using smartWallet
    • WIP: current code has void E.when(walletHelper.receive(result), ???, ???) in a sync context. This looks like another state in offer handling.
    • fix(vats): work around NameAdmin.readonly() return guard (WIP NEEDSTEST)
    • feat(smart-wallet): endow evalExpr with namesByAddress so evalExpr can send to others
    • refactor(boot): use actor style in atomicSwap test
    • explore use of coveredCall in orchestration
  • feat: write access to the nameHub (NEEDSTEST)
  • endow evalExpr to make offers (subsume callPipe)

Security Considerations

  • promises as args can add a burden on the receiver

options for cost recovery / spam mitigation / credible governance:

Scaling Considerations

Justin expressions are designed to execute in O(N) in the size of the expressions, though using E can result in large constant factors -- cross-vat calls.

  • builtins such as [...].sort() use O(n log(N)) time

TODO:

  • measure cost savings for something like Fast USDC OCW submissions

Documentation Considerations

docs such as Submitting the Offer in the UI tutorial should get updated.

Testing Considerations

only basic happy-path testing is in place

Upgrade Considerations

  • does our keplr integration "just work" with evalExpr? If not, do we want/need to support it? Or do CLI tools suffice?

TODO:

  • proper smart wallet state migration

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Apr 11, 2025

Deploying agoric-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: e3f38fc
Status:🚫  Build failed.

View logs

@socket-security
Copy link

socket-security bot commented Apr 11, 2025

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@dckc dckc force-pushed the dc-wallet-justin branch 2 times, most recently from 2127774 to 315c79e Compare April 12, 2025 03:07
// XXX worth using a nameHub vs. a mapStore?
const { nameHub, nameAdmin } = this.state.my;
const endowments = { E, harden, assert, nameHub, nameAdmin };
const c = new Compartment(endowments);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endowments are additions to the HardenedJS default allowed properties of c.globalThis. To restrict the Compartment's globalThis so that only endowments can be reached, I think you'd need something more like (untested):

Suggested change
const c = new Compartment(endowments);
const c = new Compartment();
for (const key of Reflect.ownKeys(c.globalThis)) {
assert(Reflect.deleteProperty(c.globalThis, key));
}
for (const [key, value] of Object.entries(endowments)) {
assert(Reflect.defineProperty(c.globalThis, key, { value }));
}
harden(c.globalThis);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the scope of your suggestion... could you give an example of an expression that shows how things work differently with the suggested approach?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given evaluation of a Justin expression:

try {
  const ret = c.evaluate(`Number.isSafeInteger(123)`);
  console.log('@@@ returned', ret);
} catch (e) {
  console.log('@@@ caught', e);
}

With the existing code, all of HardenedJS's tamed globals, in addition to the explicit endowments, are reachable by c.evaluate:

@@@ returned true

With (something like) my proposed code, only the endowments are reachable, not any other globals, so the above c.evaluate(...) will instead do:

@@@ caught ReferenceError: Number is not defined

I suggest you indicate in a comment which of these behaviours you desire for the c.evaluate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like Number.isSafeInteger should be available. Is there anything in the default environment of Compartment that carries authority?

I suppose compute time is relevant too... [...].sort() will be O(n log(n)) rather than the usual case of O(n) for Justin exprs. I'm not sure denying that is practical, though. hm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anything in... Compartment that carries authority?

Not in the sense of the ability to break integrity, short of what is added to c.globalThis (such as the properties of additionalGlobals in new Compartment(additionalGlobals)).

I'm not sure denying that is practical

Just spitballing some ideas, neither of which is necessarily practical or desirable:

  • Further restrict an individual Compartment's capabilities with an allowlist or membrane, but both of those require HardenedJS features that we don't have yet.
  • Have the host vat spawn separate child vats to perform evaluations, but that doesn't scale well in the current SwingSet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking with @erights, it seems there's a sweet spot I hadn't considered:

  • Have a multitenant vat provide a hand-written Justin interpreter:
    • The interpreter can take a method allowlist as a parameter, and also have restricted implementations of JS builtins
    • Interpreter-level metering can abort a particular evaluation long before an XS-level meter overflow would kill the vat

Copy link
Member

@erights erights Apr 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelfig , I agree with the first bullet.

On the second bullet, yes, with care.

Normally we allow the Justin program to cause synchronous side effects. But if you terminate it with any meter-like mechanism and you don't kill the vat it is affecting, then you leave behind inconsistent corrupt state. Unless you

  • limit the Justin code to only performing synchronous invocations that it could have performed remotely and asynchronously.
  • start the Justin execution in its own turn.

Then, any of the methods it could invoke are designed to transition the vat from a consistent state to a consistent state by itself, without making assumptions about future incoming messages causing other effects.

IOW, sudden termination of such a local Justin computation is equivalent to a remote invoker who stops.

@dckc dckc force-pushed the dc-wallet-justin branch from 315c79e to b8cf5b4 Compare April 15, 2025 17:33
assert,
nameHub,
nameAdmin,
namesByAddress,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

watch out for promises as arguments.

@dckc dckc changed the title use offer result without zoe offer SPIKE: use offer result without zoe offer Apr 19, 2025
dckc added 10 commits April 18, 2025 21:31
WIP: validate Justin syntax
Logging sent error stack Error: In "readonly" method of (NamesByAddressAdmin): result: promise "[Promise]" - Must be a remotable
    at makeError (file:///home/connolly/projects/agoric-sdk/node_modules/ses/src/error/assert.js:350:61)
    at throwLabeled (.../common/throw-labeled.js:23:20)
    at applyLabelingError (.../common/apply-labeling-error.js:43:5)
    at checkMatches (.../patterns/src/patterns/patternMatchers.js:420:5)
    at mustMatch (.../patterns/src/patterns/patternMatchers.js:596:5)
    at In "readonly" method of (NamesByAddressAdmin) [as
    readonly] (.../exo/src/exo-tools.js:173:11)
@dckc dckc force-pushed the dc-wallet-justin branch from b8cf5b4 to fb1a040 Compare April 19, 2025 02:32
dckc added 3 commits April 19, 2025 00:02
returns obj after rx[method](...args) resolves
 - price contract tracks incarnation
 - carrier contract delivers prize and shuts down
   - get boardId for carrier instance without putting it in agoricNames
 - startContract() handles privateArgs
   - move name, issuers to options bag
   - different friction around type of startSwap
 - use my.XYZ instead of nameHub.lookup(...); e.g. my.priceSetter
@dckc dckc force-pushed the dc-wallet-justin branch from fb1a040 to ab873a7 Compare April 19, 2025 05:02
@dckc dckc force-pushed the dc-wallet-justin branch from c4647af to e3f38fc Compare April 19, 2025 20:15
@dckc dckc added the wallet label Apr 21, 2025
Comment on lines +293 to +299
E(
after(my.kit.publicFacet, {
rx: my.kit.adminFacet as any, // XXX after() type
method: 'restartContract',
args: [my.kit.privateArgs],
}),
).getIncarnation(); // use the public (TODO: creator) facet
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I learned in discussion with @kriskowal that this is needlessly contorted; it could/should be:

after(my.kit.publicFacet, E(my.kit.adminFacet).restartContract(my.kit.privateArgs)).getIncarnation()

with...

const after = (obj, prereq) = E.when(prereq, () => obj)

async evalExpr(expr) {
const { fromEntries } = Object;
trace(
'TODO: validate Justin syntax; see https://github.com/endojs/Jessie/pull/121#discussion_r1988126110',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelfig while Justin is designed to execute in O(N), here we'd be parsing it. The PEG parser... does it backtrack? That wouldn't be O(N), would it?

discovered in discussion with @kriskowal

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEG is the bnf-like grammar definition language. Packrat is the generated parsing algorithm. Due to its heavy memoization, for most purposes, packrat is linear in time and space. See the original paper at Packrat Parsing:
Simple, Powerful, Lazy, Linear Time
, or the wikipedia page.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Bryan Ford's paper:

The basic reason the backtracking parser can take super-linear
time is because of redundant calls to the same parse function on the
same input substring, and these redundant calls can be eliminated
through memoization.

mhofman added a commit that referenced this pull request Aug 6, 2025
refs:
 - #8733
 - #11256

## Description

 - add a `nameHub` and `nameAdmin` to state of each offer result
 - add `spec.after.saveAs` option in `OfferSpec` to save an offer result
- add `invokeItem` method in `BridgeAction` that uses a format somewhat
like `callPipe`

DRAFT until the TODOs below are addressed.

### Security / Scaling Considerations

This is intended to serve as an efficient, straightforward alternative
to continuing offers for the (common) case when no asset exchange is
happening. The motivating usage is ymax oracles (it facitiliates
optimizing Fast USDC oracles too).

TODO:
- [x] think thru allowing everyone, not just oracles, to use
`invokeItem`. Without a suitable invitation, it's useless; but what
about griefing?
- [x] `callPipe` was allowed only on `agoricContract`; are we ready to
drop that limitation?
- [x] length limit was 3; this is currently unlimited; we haven't found
motivation to extend past 3, have we?

### Documentation / Testing Considerations

One happy path test shows that the feature works and how to use it.

TODO
 - [x] test failure modes
- [x] the test uses bundled code, which doesn't mix well with coverage
tools. Invest in testBundle tests for smartWallet?

### Upgrade Considerations

TODO:
- [ ] figure out upgrade implications of adding to smartWallet exo state
@dckc
Copy link
Member Author

dckc commented Sep 29, 2025

OBE

@dckc dckc closed this Sep 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

invoke smart wallet offer result without making a zoe offer

3 participants