Offline ZBVM block fixture
Read the signed-transaction block replay and recovery evidence.
The offline fixture uses the existing ZBX ZBLC compiler, canonical V3 signed contract envelope and ZBVM v1 runtime from a supplied ZBX checkout. The harness lives in the ZBL repository. Its build output, transaction journal and test evidence go to a fresh directory outside the ZBX checkout.
Reproduce on Windows
Load the ZBL toolchain helper and provide the ZBX checkout and a fresh output path. LocalArtifact optionally checks a real ZCT v1 artifact from the ZBL SDK against the V3 deploy format.
. ./scripts/toolchain.ps1
./scripts/verify-zbvm-local.ps1 -ZbxRoot $zbxCheckout -OutDirectory $newEvidenceDirectory -LocalArtifact $localZct -Offline
Use Offline when the dependency cache is populated. The script starts with a copy of the ZBX lockfile and records the resulting isolated lockfile hash, the ZBX checkout commit, and hashes of the consumed manifests and source files. The output records whether those inputs had worktree changes. The script checks the same input file hashes again after execution.
What the fixture verifies
- Compile a native ZBVM v1 Counter contract and carry it in a signed V3 deploy message. Verify the signature, chain ID, genesis binding and nonce before creating the local instance.
- Sign and call the eight-byte increment selector using the deployment address. Authenticate the legacy ZBVM caller by deriving it from the same verified public key as the V3 sender. Check the event, measured opcode gas and instance commitment.
- Revert when a second arithmetic operation fails after a staged write. Reject an insufficient gas limit, a write from another signer, a replayed nonce, a foreign genesis and a tampered signature. Compare state and nonce before and after each rejection.
- Save the successful signed messages, replay them in a separate process and compare the resulting state, instance commitment, event and gas. Make a signed view call after replay and verify the returned value.
The fixture uses deterministic public test keys, an isolated chain context, and contract instances rebuilt in memory by replay. Its nonce rule advances only for successful operations. These are fixture policies. The measured gas counts VM opcode units. Deployment gas, balance debits and fee settlement are outside the fixture.
ZCT v1 carries ZBC2 for the ZBL SDK's local ZBR runner. The ZBX V3 deploy envelope verifies native ZBVM v1 module framing. A prior SDK ZCT artifact is rejected by that native verifier. This run does not add a new compiler target or activate a node feature.
Durable local journal
After running the verification script, the harness executable is in the output directory under target/debug/zbvm-local.exe. It accepts the following journal commands.
zbvm-local journal init <file>
zbvm-local journal submit <file> <signed-tx> [expected-head]
zbvm-local journal verify <file> [expected-head]
zbvm-local journal recover <damaged-file> <new-file> <expected-head>
Keep the head returned by a successful operation in an independent trusted location. Supply the latest trusted head when verifying or submitting to detect replacement and truncation. For a retry with an uncertain append outcome, verify the file and compare the last receipt with the intended submission before accepting a newer head. Resubmitting the same signed bytes against the current head returns the original receipt without writing a new frame.
The versioned header binds the fixture chain ID and genesis. Each frame stores a little-endian 32-bit length, the signed transaction bytes, a 32-byte receipt digest, and a 32-byte chained digest. Replay verifies the original envelope, re-executes the transaction, and compares the receipt digest. Call receipts include return values, events, and measured VM gas. Each receipt also includes the resulting instance commitment and journal head. Receipt digests cover the JSON payload before the head is added.
The journal uses an exclusive file lock for submissions, shared locks for reads, and flushes each accepted append before returning success. Recovery copies a verified prefix to a new file only when the tail is incomplete and the supplied checkpoint matches. It preserves the damaged file and rejects complete corrupt frames. Use a trusted local directory with cooperating writers. A checkpoint stored alongside an untrusted journal can be replaced with it.
The journal is capped at 1,024 records and 16 MiB. Each operation replays the file in full. The tests simulate a partial append and verify recovery across separate CLI processes. Power-loss behavior, sustained throughput and validator storage are separate validation work.
Windows result
The signed call advanced the Counter from 0 to 42, emitted Changed(42), and used 38 VM gas units. Both rollback cases preserved the instance commitment. The signed view returned 42 for 6 gas units after replay. The verification script tests receipt tampering, duplicate submission, lock contention, truncation, and checkpoint-bound recovery, and emits the results in zbvm-local-evidence.json. The prior ZCT artifact was rejected. The consumed ZBX checkout at b7c328f had pre-existing staged source changes. The script verified identical source hashes before and after the run.
Block execution profile
The harness can write a two-block fixture and verify it from genesis against a separately supplied tip. The first block contains a signed deployment and increment. The second contains a signed view. Keep the expected tip in a trusted location independent of the block files.
zbvm-local block-demo <fixtures> <existing-empty-output-directory>
zbvm-local block-verify <trusted-tip> <block-1> <block-2>
Each block binds the profile version, chain ID, genesis, height, parent, state and receipt commitments, and the ordered signed V3 transaction bytes. The state commitment covers each deployed instance and each sender's next nonce in address order. The receipt commitment covers each transaction hash and its deployment address or call result, including measured gas, state, returned values and events. The block tip hashes the full encoded block.
Execution uses a cloned candidate state. The verifier advances the ledger only after all transactions succeed and both commitments match. If a later transaction fails, earlier transactions in the candidate leave no changes to the accepted state or nonces. This fixture caps each block at 32 transactions, 256 KiB, and 1,000,000 total signed gas units, with at most 64 blocks per replay. Deployment reserves its signed gas limit against that cap. Call receipts record metered VM work. Balance debits and fee settlement are outside the profile.
The Windows verification script starts four independent replay processes and compares their complete reports. It also checks an incomplete block file, wrong block order, and a chain truncated before the trusted tip. The Rust tests check a late transaction failure, a gas-cap violation, a forged receipt commitment and duplicate block admission. These are isolated replay processes with no network, validator votes, or consensus finality. The block files are fixtures. Durable journal recovery is tested separately.
Remaining node integration
The inspected ZBX checkout keeps V3 contract transactions inactive. The active transaction codec and mempool carry the existing signed transaction type. Consensus executes proposals in crates/consensus/src/proposal.rs, while RocksDB persistence lives in crates/storage/src/rocks.rs. The production integration needs an activation rule across those boundaries, an agreed fee and revert policy, and an atomic migration that includes contract code, state and receipt commitments without changing legacy roots. A private four-validator test can then verify matching finalized roots, certified history catch-up and restart recovery. The block profile is a fixture format. Validator consensus and production storage retain their own wire and persistence requirements.