Skip to content

Feat/pow inner computer refactor - #486

Open
ltardivo wants to merge 6 commits into
feat/powfrom
feat/pow-inner-computer-refactor
Open

Feat/pow inner computer refactor#486
ltardivo wants to merge 6 commits into
feat/powfrom
feat/pow-inner-computer-refactor

Conversation

@ltardivo

@ltardivo ltardivo commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

This PR tightens the determinism and fail-closed guarantees of the InnerComputer that every smart-contract method sees. Successful queries must now be stable under chain extension: unconfirmed locations, mempool-only successors, unspent tips treated as last, and unguarded TXO queries all invalidate the evaluation—even when the contract catches the thrown error. Invalidation is tracked per evaluation frame, the compartment endowment is a hardened public-method facade, and every public error ends with exactly one copy of the standard forbidden suffix.

Lib

  • Confirmed-location guards on sync, decode, load, first, prev, next, last, block-time/height/hash helpers, and getTXOs (plus aliases). next requires a confirmed successor; last requires a confirmed spending input of the tip (unspent or mempool-only spend invalidates).
  • Inner Computer Endowment exposes only bound public methods + getters, hardened after SES lockdown; method replacement, prototype tampering, and getter shadowing are blocked.
  • Expanded unit tests cover free-var mismatch, nested frames, concurrent unfunded encodes, module-deployed classes with try/catch, unconfirmed starts, mempool next, confirmed-spend last, and indexer-lag stabilizers.

Contracts & tokens

  • TBC777 / TBC777M: finalWithdraw and computeFinalWithdraw documentation and tests now require the tip to be spent in a confirmed transaction before computer.last succeeds. Tests mine after delete.
  • Chess contracts: ChessContractHelper gains waitForConfirmed; withdrawTokens and cancelGameAndWithdraw wait for the chess tip before the TBC777 audit. UI copy and README updated. calculateTimes / timeout helpers document the confirmed-prev-chain requirement; new regression test.
  • Commodity: claim fails closed on unconfirmed mint creation (uses block-height / decode / OTXO paths).

Apps

  • Chess board shows snackbars while waiting for confirmation before withdraw / cancel-and-refund.

Docs

  • New pages: Lib/Contract/sandbox-and-inner-computer.md and docs-2 architecture counterpart.
  • Contract querying reference rewritten for confirmed-location rules, single-suffix errors, eval frames, hardened endowment, and practical migration notes (confirm deploys, history walks, terminal last, stabilize TXO queries).
  • Cross-links from Lib index, how-it-works, language, and intro.

Breaking / migration notes

Call sites that previously observed unconfirmed tips or mempool state inside contracts will now invalidate:

  1. After deploy / new / method calls / delete, wait for confirmation before any on-chain code that uses load, sync, first/prev/next/last, or block times on those locations.
  2. Terminal escrow claims: record final withdrawals → delete the tip → mine → then finalWithdraw(tipRev).
  3. Match errors with message.endsWith('Accessing non-existent on-chain state inside a smart contract is forbidden.') (or the shared helper); short policy reasons never stand alone.

ltardivo and others added 6 commits August 5, 2026 16:55
Guard first, prev, next, last, and load with confirmed-location checks;
require confirmed successors/spends for next/last. Expand InnerComputer
tests for unconfirmed starts, mempool next, spent last, and sync.

fix (monorepo): Adapt apps and docs to confirmed InnerComputer queries

Mine after deletes before finalWithdraw; confirm modules and mints in
tests. Chess helper waits for tip confirmation before withdraw/cancel
refund. Document observation stability and contract-vs-client computer
APIs in docs and docs-2.
Add formatInvalidStateError so the standard forbidden phrase is appended
at most once from _safeCall and Db.eval. Cover uncaught, catch-and-continue, and short policy messages in tests.

(docs): document single-suffix InnerComputer invalidation errors

Update Contract querying and docs-2 intro/how-it-works/sandbox pages so public invalidation messages always end with one forbidden suffix on
uncaught and catch-and-continue paths.
SES free-variable `computer` is bound to the definition compartment
(create / Modules.load), which is often a different InnerComputer instance
than the one Db.eval endows for the current call. A pure instance flag
therefore missed catch-and-continue invalidations after V4 instance-local
state.

Introduce beginEvalInvalidation/endEvalInvalidation stack frames as the
authoritative invalidation record: _invalidate marks the current top frame
(and mirrors on the instance). Db.eval and Modules.load each push/pop around evaluate/import so concurrent Promise.all evals cannot cross-talk, while module bodies that call computer still participate.

Tests cover free-var mismatch, nested frames, concurrent unfunded encode isolation, and module-deployed classes with try/catch still rejected after evaluate returns.

docs: document eval-stack invalidation and SES free-var computer

Explain that invalidation is tracked per evaluation frame (push/pop in
Db.eval and Modules.load), not a process-global flag, so concurrent
evaluations stay isolated. Note that free-variable computer may resolve to
the create-time or module-load instance while the active frame still
records invalidation—catch-and-continue cannot soft-succeed. Update
Lib/Contract querying and docs-2 sandbox architecture accordingly.
Replace the plain invalidation stack with withEvalInvalidation dual backends:
Node uses AsyncLocalStorage via process.getBuiltinModule('async_hooks') (no
static node:async_hooks import), and the browser uses an await-scoped stack
with serialized root frames so concurrent Promise.all evals cannot cross-talk
under SES lockdown.

Harden the host path and error shape:
- Db.eval prefers frame.invalid / frame.msg on both compartment throw and
  catch-and-continue return, not computer.isInvalid alone.
- _invalidate and _safeCall always apply formatInvalidStateError (single
  forbidden suffix; policy reasons never stand alone).
- _ensureConfirmedTx treats any falsy block hash as unconfirmed.
- createInnerComputerEndowment remains a hardened public-method facade.

Stabilize InnerComputer tests against indexer lag and mixed unconfirmed
dispatch (confirm the query object first; poll outer getTXOs before asserting
in-contract results; expectSingleForbiddenSuffix everywhere).

Includes modules.ts wiring for load-time frames.

(docs): align InnerComputer sandbox docs with eval-frame implementation

Document dual-runtime evaluation frames (Node ALS without a static node:async_hooks import; browser stack + serialized roots), host reject on
frame.invalid for throw and catch-and-continue, and the canonical single forbidden-suffix error shape for policy and missing observations.

- Add Lib/Contract/sandbox-and-inner-computer.md and link it from Contract querying, Lib index, how-it-works, and language.
- Refresh Contract querying invalidation / error / getTXOs wording.
- Sync docs-2 architecture sandbox page, intro, and how-it-works notes with the same model (drop obsolete plain eval-stack-only wording).
Build SES compartment globals via buildContractCompartmentGlobals so host
console is available only in client mode dev/debug. In prod, console is not in scope (contracts must not rely on it).

Simplify without changing security semantics:
- Shared globals helper for Db.eval and Modules.load
- Single invalidation exit in Db.eval (capture frame.msg before resetInvalid)
- Same host pattern for Modules.load import failures
- Drop redundant formatInvalidStateError in _safeCall
- Slim stack-frame pop in withEvalInvalidation

(docs): no console in prod contracts; refresh sandbox notes

Document that compartment host console is endowed only in dev/debug client
mode and must not be used in production smart contracts (ReferenceError in
prod). Update sandbox-and-inner-computer, Contract querying, how-it-works,
language, and docs-2 architecture accordingly.
Document query-only endowment, host frame authority, and free-var routing
to the active eval client. Drop obsolete isInvalid / resetInvalid contract APIs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants