-
Notifications
You must be signed in to change notification settings - Fork 5
Bump deps to prerelease, add ecdsa tests #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: beta
Are you sure you want to change the base?
Changes from all commits
001fc87
aa7be1f
78f2cbb
c61be9d
1f8929f
8dca627
7d179ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,10 @@ inputs: | |
| description: "Skip Compact compiler installation" | ||
| required: false | ||
| default: "false" | ||
| compact-prerelease: | ||
| description: "Pre-release Compact compiler to fetch from GitHub releases (bridge until the toolchain ships stable). Keep in sync with setup.ts COMPACTC_VERSION." | ||
| required: false | ||
| default: "0.33.0-rc.2" | ||
|
|
||
| runs: | ||
| using: "composite" | ||
|
|
@@ -44,3 +48,27 @@ runs: | |
| uses: midnightntwrk/setup-compact-action@4130145456ad3f45934788dd4a65647eb283e658 # loose commit/not released | ||
| with: | ||
| compact-version: "0.31.0" | ||
|
|
||
| # The tests pin a pre-release compiler (secp256k1 / 0.18 runtime) that | ||
| # `compact update` does not serve, so fetch its release asset directly and | ||
| # drop it where `compact +<version>` looks. Remove once the toolchain ships | ||
| # a stable release (then just bump compact-version above). | ||
| - name: Install pre-release Compact toolchain | ||
| if: ${{ inputs.skip-compact != 'true' }} | ||
| shell: bash | ||
| env: | ||
| VER: ${{ inputs.compact-prerelease }} | ||
| run: | | ||
| set -euo pipefail | ||
| # Reuse the platform dir the CLI already created for the stable install | ||
| # (e.g. x86_64-unknown-linux-musl), so the pre-release lands where the | ||
| # `+<version>` selector resolves it; fall back to the host triple. | ||
| PLAT="$(basename "$(find "$HOME/.compact/versions" -mindepth 2 -maxdepth 2 -type d 2>/dev/null | head -1)" 2>/dev/null || true)" | ||
| [ -z "$PLAT" ] && PLAT="$(uname -m)-unknown-linux-musl" | ||
| DEST="$HOME/.compact/versions/$VER/$PLAT" | ||
| mkdir -p "$DEST" | ||
| curl -fsSL -o /tmp/compactc.zip \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 blocking (downgrade if the team disagrees): the pre-release compiler is downloaded, Unblocks: pin a added by claude (dev3-midnight-basic-review) |
||
| "https://github.com/LFDT-Minokawa/compact/releases/download/compactc-v$VER/compactc_v${VER}_${PLAT}.zip" | ||
| unzip -oq /tmp/compactc.zip -d "$DEST" | ||
| chmod +x "$DEST"/* | ||
| compact compile +"$VER" --version | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,7 +93,7 @@ export abstract class AbstractSimulator<P, L> | |
| * @returns The current private state of type P | ||
| */ | ||
| public getPrivateState(): P { | ||
| return this.circuitContext.currentPrivateState; | ||
| return this.circuitContext.callContext.currentPrivateState as P; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚪ nitpick: added by claude (dev3-midnight-basic-review) |
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -102,7 +102,7 @@ export abstract class AbstractSimulator<P, L> | |
| * @returns The current state value containing the ledger data | ||
| */ | ||
| public getContractState(): StateValue { | ||
| return this.circuitContext.currentQueryContext.state.state; | ||
| return this.circuitContext.callContext.currentQueryContext.state.state; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -130,12 +130,13 @@ export abstract class AbstractSimulator<P, L> | |
| const original = Reflect.get(target, prop, receiver); | ||
| if (typeof original !== 'function') return original; | ||
|
|
||
| return (...args: unknown[]) => { | ||
| return async (...args: unknown[]) => { | ||
| const fn = original as ( | ||
| ctx: CircuitContext<P>, | ||
| ...args: unknown[] | ||
| ) => { result: unknown }; | ||
| const result = fn(context(), ...args).result; | ||
| ) => { result: unknown } | Promise<{ result: unknown }>; | ||
| // 0.18 circuits are async; `await` also tolerates the older sync shape. | ||
| const { result } = await fn(context(), ...args); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❔ question: does 0.33-generated circuit code copy the context before executing? The pure proxy is wired with added by claude (dev3-midnight-basic-review) |
||
|
|
||
| // Auto-reset single-use caller override | ||
| this.callerOverride = null; | ||
|
|
@@ -172,13 +173,16 @@ export abstract class AbstractSimulator<P, L> | |
| const original = Reflect.get(target, prop, receiver); | ||
| if (typeof original !== 'function') return original; | ||
|
|
||
| return (...args: unknown[]) => { | ||
| return async (...args: unknown[]) => { | ||
| const fn = original as ( | ||
| ctx: CircuitContext<P>, | ||
| ...args: unknown[] | ||
| ) => { result: unknown; context: CircuitContext<P> }; | ||
| ) => | ||
| | { result: unknown; context: CircuitContext<P> } | ||
| | Promise<{ result: unknown; context: CircuitContext<P> }>; | ||
|
|
||
| const { result, context: newCtx } = fn(context(), ...args); | ||
| // 0.18 circuits are async; `await` also tolerates the older sync shape. | ||
| const { result, context: newCtx } = await fn(context(), ...args); | ||
| updateContext(newCtx); | ||
|
|
||
| // Auto-reset single-use caller override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,9 @@ import { | |
| type ConstructorContext, | ||
| type ContractAddress, | ||
| type ContractState, | ||
| CostModel, | ||
| createCircuitContext, | ||
| createConstructorContext, | ||
| type EncodedZswapLocalState, | ||
| QueryContext, | ||
| } from '@midnight-ntwrk/compact-runtime'; | ||
|
|
||
| /** | ||
|
|
@@ -16,12 +15,36 @@ import { | |
| * Handles initialization and lifecycle management of the `CircuitContext`, | ||
| * which includes private state, public (ledger) state, zswap local state, and transaction context. | ||
| */ | ||
| /** Shape of a compiled contract's constructor result (sync or async in 0.18). */ | ||
| type InitialStateResult<P> = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 blocking: this local Unblocks: move the added by claude (dev3-midnight-basic-review) |
||
| currentPrivateState: P; | ||
| currentContractState: ContractState; | ||
| currentZswapLocalState: EncodedZswapLocalState; | ||
| }; | ||
|
|
||
| export class CircuitContextManager<P> { | ||
| public context: CircuitContext<P>; | ||
| // Assigned by the async `init()`; the manager is always constructed and then | ||
| // awaited (`init`) before any circuit call reads the context. | ||
| public context!: CircuitContext<P>; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 blocking: two-phase construction with no guard. Unblocks: back added by claude (dev3-midnight-basic-review) |
||
|
|
||
| private readonly contract: { | ||
| initialState: ( | ||
| ctx: ConstructorContext<P>, | ||
| ...args: any[] | ||
| ) => InitialStateResult<P> | Promise<InitialStateResult<P>>; | ||
| }; | ||
| private readonly privateState: P; | ||
| private readonly coinPK: CoinPublicKey; | ||
| private readonly contractAddress: ContractAddress; | ||
| private readonly contractArgs: any[]; | ||
|
|
||
| /** | ||
| * Creates an instance of `CircuitContextManager`. | ||
| * | ||
| * @remarks compact-runtime 0.18 made `initialState` (and every circuit) async, | ||
| * so the constructor only records inputs; the context is built by the async | ||
| * {@link init}, which callers must await before using the manager. | ||
| * | ||
| * @param contract - A compiled Compact contract instance exposing `initialState()` | ||
| * @param contract.initialState - Function that initializes contract state given a constructor context | ||
| * @param privateState - The initial private state to inject into the contract | ||
|
|
@@ -34,34 +57,44 @@ export class CircuitContextManager<P> { | |
| initialState: ( | ||
| ctx: ConstructorContext<P>, | ||
| ...args: any[] | ||
| ) => { | ||
| currentPrivateState: P; | ||
| currentContractState: ContractState; | ||
| currentZswapLocalState: EncodedZswapLocalState; | ||
| }; | ||
| ) => InitialStateResult<P> | Promise<InitialStateResult<P>>; | ||
| }, | ||
| privateState: P, | ||
| coinPK: CoinPublicKey, | ||
| contractAddress: ContractAddress, | ||
| ...contractArgs: any[] | ||
| ) { | ||
| const initCtx = createConstructorContext(privateState, coinPK); | ||
| this.contract = contract; | ||
| this.privateState = privateState; | ||
| this.coinPK = coinPK; | ||
| this.contractAddress = contractAddress; | ||
| this.contractArgs = contractArgs; | ||
| } | ||
|
|
||
| /** | ||
| * Runs the contract constructor and builds the initial `CircuitContext`. | ||
| * Must be awaited once, after construction, before any circuit call. | ||
| */ | ||
| async init(): Promise<void> { | ||
| const initCtx = createConstructorContext(this.privateState, this.coinPK); | ||
|
|
||
| const { | ||
| currentPrivateState, | ||
| currentContractState, | ||
| currentZswapLocalState, | ||
| } = contract.initialState(initCtx, ...contractArgs); | ||
|
|
||
| // Extract ChargedState from the compiler-generated ContractState | ||
| const chargedState = currentContractState.data; | ||
| } = await this.contract.initialState(initCtx, ...this.contractArgs); | ||
|
|
||
| this.context = { | ||
| currentPrivateState, | ||
| // compact-runtime 0.18 restructured `CircuitContext` into a call-tree | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❔ question (non-blocking): heads-up on an upstream quirk this comment glosses. added by claude (dev3-midnight-basic-review) |
||
| // (`callContext` + per-contract `queryContexts`/`gasCosts`). Build it via | ||
| // the runtime's `createCircuitContext` factory rather than a hand-rolled | ||
| // literal so every required field is populated correctly. | ||
| this.context = createCircuitContext<P>( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 blocking: this drops the optional Unblocks, any one of:
added by claude (dev3-midnight-basic-review) |
||
| 'circuit', | ||
| this.contractAddress, | ||
| currentZswapLocalState, | ||
| currentQueryContext: new QueryContext(chargedState, contractAddress), | ||
| costModel: CostModel.initialCostModel(), | ||
| }; | ||
| currentContractState.data, | ||
| currentPrivateState, | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -88,6 +121,6 @@ export class CircuitContextManager<P> { | |
| * @param newPrivateState - The new private state to set in the current context | ||
| */ | ||
| updatePrivateState(newPrivateState: P) { | ||
| this.context.currentPrivateState = newPrivateState; | ||
| this.context.callContext.currentPrivateState = newPrivateState; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import { | ||
| type CircuitContext, | ||
| copyCircuitContext, | ||
| emptyZswapLocalState, | ||
| } from '@midnight-ntwrk/compact-runtime'; | ||
| import { AbstractSimulator } from './AbstractSimulator.js'; | ||
|
|
@@ -43,15 +44,16 @@ export abstract class ContractSimulator<P, L> extends AbstractSimulator<P, L> { | |
| const activeCaller = this.callerOverride || this.persistentCallerOverride; | ||
| const baseCtx = this.circuitContext; | ||
|
|
||
| return { | ||
| currentPrivateState: baseCtx.currentPrivateState, | ||
| currentQueryContext: baseCtx.currentQueryContext, | ||
| currentZswapLocalState: activeCaller | ||
| ? emptyZswapLocalState(activeCaller) | ||
| : baseCtx.currentZswapLocalState, | ||
| costModel: baseCtx.costModel, | ||
| gasLimit: baseCtx.gasLimit, | ||
| }; | ||
| if (!activeCaller) { | ||
| return baseCtx; | ||
| } | ||
|
|
||
| // compact-runtime 0.18: the caller-scoped fields live on `callContext`. | ||
| // Copy (shallow-clones `callContext`) before overriding the Zswap local | ||
| // state so the base context is left untouched. | ||
| const ctx = copyCircuitContext(baseCtx) as CircuitContext<P>; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 followup (non-blocking): added by claude (dev3-midnight-basic-review) |
||
| ctx.callContext.currentZswapLocalState = emptyZswapLocalState(activeCaller); | ||
| return ctx; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,9 @@ export function createDrySimulator< | |
| >(config: SimulatorConfig<P, L, W, TContract, TArgs>) { | ||
| return class GeneratedSimulator extends ContractSimulator<P, L> { | ||
| contract: TContract; | ||
| readonly contractAddress: string; | ||
| // Assigned by the async `init()` (0.18 made `initialState` async, so the | ||
| // address — read from the built context — is not known at construction). | ||
| contractAddress!: string; | ||
| public _witnesses: W; | ||
|
|
||
| /** | ||
|
|
@@ -65,8 +67,18 @@ export function createDrySimulator< | |
| contractAddress, | ||
| ...processedArgs, | ||
| ); | ||
| } | ||
|
|
||
| this.contractAddress = this.circuitContext.currentQueryContext.address; | ||
| /** | ||
| * Runs the contract constructor and finalizes state. Must be awaited once, | ||
| * after construction, before any circuit call. Split out from the | ||
| * constructor because compact-runtime 0.18 made `initialState` async. | ||
| */ | ||
| async init(): Promise<this> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚪ nitpick: docs went stale with the async migration. Line 15 still calls this the "Internal synchronous simulator primitive"; added by claude (dev3-midnight-basic-review) |
||
| await this.circuitContextManager.init(); | ||
| this.contractAddress = | ||
| this.circuitContext.callContext.currentQueryContext.address; | ||
| return this; | ||
| } | ||
|
|
||
| public _pureCircuitProxy?: ContextlessCircuits< | ||
|
|
@@ -144,7 +156,7 @@ export function createDrySimulator< | |
| */ | ||
| getPublicState(): L { | ||
| return config.ledgerExtractor( | ||
| this.circuitContext.currentQueryContext.state.state, | ||
| this.circuitContext.callContext.currentQueryContext.state.state, | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -191,8 +203,8 @@ export function createDrySimulator< | |
| const circuitCtx = this.circuitContext; | ||
| return { | ||
| ledger: this.getPublicState(), | ||
| privateState: circuitCtx.currentPrivateState, | ||
| contractAddress: circuitCtx.currentQueryContext.address, | ||
| privateState: circuitCtx.callContext.currentPrivateState as P, | ||
| contractAddress: circuitCtx.callContext.currentQueryContext.address, | ||
| }; | ||
| } | ||
| }; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 blocking: the
compact-prereleaseinput is non-functional as written.VERis scoped to this step, andtest/setup.ts:55readsprocess.env.COMPACTC_VERSION, which nothing sets. Override the input and CI installs one toolchain while the tests compile with the hardcoded+0.33.0-rc.2.Unblocks: export it, e.g.
echo "COMPACTC_VERSION=$VER" >> "$GITHUB_ENV"in this step.added by claude (dev3-midnight-basic-review)