Skip to content

feat: add zallet-rpc-diff parity harness (MVP)#404

Open
CreativesOnchain wants to merge 17 commits into
zcash:mainfrom
CreativesOnchain:feat/zallet-rpc-diff-milestone-1
Open

feat: add zallet-rpc-diff parity harness (MVP)#404
CreativesOnchain wants to merge 17 commits into
zcash:mainfrom
CreativesOnchain:feat/zallet-rpc-diff-milestone-1

Conversation

@CreativesOnchain
Copy link
Copy Markdown

@CreativesOnchain CreativesOnchain commented Mar 26, 2026

Summary

This draft PR introduces the zallet-rpc-diff parity harness — a reproducible, production-grade CLI tool that compares zcashd and Zallet wallet JSON-RPC responses, classifying each method as MATCH / DIFF / MISSING / ERROR.

This addresses the upstream request in #16.


✅ MVP Deliverables

Design & Scaffolding

See tools/zallet-rpc-diff/DESIGN_NOTE.md which explicitly defines the result categories, report.json schema, and the versioned manifest.toml format.

Rust Crate + CLI Skeleton

  • zallet-parity-core — library with custom Error types and result categorization.
  • zallet-parity-cli — binary zallet-rpc-diff with clap v4, color-eyre, and tracing.
  • zallet-parity-testkit — test helpers suite.

CI Workflow

.github/workflows/zallet-rpc-diff.yml — scoped workspace checks (build, test, fmt, clippy).

Execution Engine & Reporting

Implemented an async runner in zallet-parity-core using tokio::task::JoinSet. It executes the entire manifest suite concurrently against both upstream and target endpoints.

Deep Semantic Comparison

Integrated assert-json-diff to perform recursive comparison of serde_json::Value responses. It correctly identifies differences while being resilient to key ordering.

Premium CLI & Reporting

  • Progress Tracking: Added indicatif progress bars for real-time feedback during large suites.
  • Reporting: Automatically generates report.json (for automation) and a human-readable report.md (for PR review).

Automated Verification Suite

Implemented a robust testing suite using wiremock in the testkit:

  • Unit Tests: Verify the parity logic for matches and diffs.
  • Integration Tests: Verify the E2E CLI workflow against mock RPC nodes.
  • Run with: cargo test --workspace

Questions for Maintainers

  1. Location: Is tools/zallet-rpc-diff/ acceptable, or would you prefer testing/zallet-rpc-diff/?
  2. Workspace membership: Should these crates be added to the root workspace members list, or kept as a self-contained sub-workspace?
  3. Method suite: The current manifest.toml is a sample; I'm happy to align the v1 allowlist with your priorities.

TODOs (Future Milestones)

  • Implement JSON-RPC execution engine (MVP)
  • Normalization + ignore paths
  • Expected-differences file
  • Method suite v1 + runbook

@CreativesOnchain CreativesOnchain changed the title feat: zallet rpc diff (milestone 1 & 2) feat: add zallet-rpc-diff parity harness (Milestones 1 & 2) Mar 26, 2026
- Add tools/zallet-rpc-diff workspace with three crates:
  - zallet-parity-core: library with custom Error types
  - zallet-parity-cli: binary (zallet-rpc-diff) with clap, color-eyre, tracing
  - zallet-parity-testkit: test helpers with wiremock
- Add DESIGN_NOTE.md defining MATCH/DIFF/MISSING/ERROR categories,
  report schema, and manifest format
- Add CI workflow (.github/workflows/zallet-rpc-diff.yml)
- All crates compile cleanly in the workspace

This satisfies Milestone 1 deliverables:
  - Clearly defined report format and manifest structure
  - Rust crate + CLI skeleton ready for maintainer review
@CreativesOnchain CreativesOnchain force-pushed the feat/zallet-rpc-diff-milestone-1 branch from bb258ae to 84e8790 Compare March 26, 2026 16:09
@CreativesOnchain CreativesOnchain changed the title feat: add zallet-rpc-diff parity harness (Milestones 1 & 2) feat: add zallet-rpc-diff parity harness (MVP) Mar 26, 2026
… tests

- Add MethodNotFound error variant to lib.rs Error enum
- Engine detects JSON-RPC -32601 and maps to ParityResult::Missing
- report.rs: MISSING is now a first-class category with its own counter
- testkit: add mock_method_not_found() and mock_rpc_error() helpers
- engine tests: 4 cases covered — MATCH, DIFF, MISSING, ERROR
- All 5 workspace tests pass
…context

Milestone 3 implementation:

normalizer.rs
- sort_keys(): recursive BTreeMap-based canonical JSON key ordering
- apply_ignore_paths(): RFC 6901 JSON Pointer path removal via jsonptr v0.7.1
- normalize(): combined pipeline (sort → remove paths)
- 10 unit tests covering ordering, nesting, noop, and combined cases

differ.rs
- DiffEntry: serializable struct with RFC 6901 path + upstream/target values
- diff_values(): recursive walker that returns Vec<DiffEntry>
- 8 unit tests covering scalars, nested objects, arrays, missing keys, RFC escaping

manifest.rs
- Add ignore_paths: Vec<String> field to MethodEntry (defaults to empty)
- 2 manifest parsing tests via tempfile

engine.rs
- Wire full normalization pipeline before comparison
- ParityResult::Diff now carries Vec<DiffEntry> (structured paths)
- 2 new engine tests: ordering-only diff → MATCH, ignore_path → MATCH

report.rs
- ParityResultReport::Diff exposes diff_count + diff_paths (no payload dump)
- Markdown table shows exact changed paths per method

Total: 27 tests passing
- Default: 30 seconds (DEFAULT_REQUEST_TIMEOUT const)
- New with_timeout() constructor for configurable timeouts
- Satisfies M2 deliverable: 'explicit per-request timeouts'
…F classification

expected_diffs.rs
- ExpectedDiffEntry: TOML-parseable struct with method, reason, diff_paths
- ExpectedDiffs::load(): reads expected_diffs.toml from disk
- ExpectedDiffs::none(): empty fallback (no file required)
- is_expected(): method-level (any diff) and field-level (path-prefix) matching
- 9 unit tests: parsing, method-level matching, field-level coverage, partial coverage

engine.rs
- ParityResult::ExpectedDiff { diff_entries, reason } — new variant
- run_all() now accepts &ExpectedDiffs parameter
- Promotes Diff → ExpectedDiff when diff paths are fully covered by an entry
- 3 new engine tests: method-level, field-level covered, partial-coverage still DIFF

report.rs
- RunSummary gains expected_diffs counter
- ParityResultReport::ExpectedDiff { diff_count, diff_paths, reason }
- Markdown output shows 📋 Expected Diff row with reason inline

main.rs (CLI)
- --expected-diffs flag (default: expected_diffs.toml, optional)
- Silently falls back to ExpectedDiffs::none() if file absent
- CLI summary line shows all 5 outcome categories

Total: 39 tests passing
manifest.toml (v1)
- 24 real Zcash JSON-RPC methods across 5 categories:
  blockchain, network, wallet, shielded, mining, utility
- Each method includes: ignore_paths for volatile fields, tags for filtering
- Inline comments explain every ignore_path decision

RUNBOOK.md
- Prerequisites: node setup, wallet key parity, network match
- Installation: build from source, or cargo run
- Configuration: env vars (endpoints.env) vs CLI flags
- Invocation patterns: minimal, custom output, with expected-diffs, verbose
- Exit code table: 0 (clean) / 1 (diffs found) / 2 (tool failure)
- Outcome interpretation: MATCH/DIFF/EXPECTED_DIFF/MISSING/ERROR table
- Extension guide: how to add methods + ignore_paths vs expected_diffs guidance
- Troubleshooting: common ERROR/DIFF/MISSING failure modes

examples/
- endpoints.env       — env var template for UPSTREAM_URL / TARGET_URL
- expected_diffs.toml — 4 documented known zcashd vs Zallet divergences
- sample_report.json  — illustrates all 5 outcome categories
- sample_report.md    — Markdown version of the same sample
main.rs — CLI UX polish
- ExitCode 0: all MATCH or EXPECTED_DIFF (clean)
- ExitCode 1: any DIFF, MISSING, or ERROR found
- ExitCode 2: tool-level failure (config/manifest/IO error)
- Rich --help: long_about on binary, per-arg long_help with format examples
- Actionable error messages: manifest path, expected-diffs path, endpoint URL
  all included in fatal error output
- Stderr advisory messages for DIFF / MISSING / ERROR outcomes
- Progress bar message shows method count upfront
- Summary line now shows all 5 categories with emoji labels

CI (.github/workflows/zallet-rpc-diff.yml)
- working-directory: tools/zallet-rpc-diff (all steps scoped correctly)
- --workspace flag on all cargo invocations
- --locked flag for reproducible builds
- Cargo registry + target cache (actions/cache@v4)
- Clippy: --all-targets --all-features -D warnings
- Single consolidated 'ci' job with logical step ordering

Code quality
- cargo fmt --all applied; format check passes clean
- cargo clippy --all-targets -- -D warnings: zero warnings
- 39 tests passing
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.

1 participant