feat: extend private PDA support to CLI dispatch and smoke test#174
feat: extend private PDA support to CLI dispatch and smoke test#174vpavlin wants to merge 4 commits into
Conversation
- IdlPda: add `npk_arg: Option<String>` so CLI knows which instruction
arg holds the NullifierPublicKey for PDA derivation
- Macro: populate npk_arg in both generate_idl_fn and generate_idl_json
- tx.rs: resolve npk from parsed args when computing private PDAs,
replacing the hardcoded None that always produced public addresses
- parse.rs: handle IdlType::Defined{"NullifierPublicKey"} as 32-byte hex
- serialize.rs: serialize NullifierPublicKey ByteArray as tuple of u8s
- smoke-test-privacy.sh: add init_private_pda instruction to test
program plus steps 11–13 (get npk, compute PDA, init PDA account)
- Fixture test: assert npk_arg == "user_npk" in IDL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- codegen.rs: compute_{account}_pda helpers add `npk: &NullifierPublicKey`
param and call compute_private_pda when pda.private == true; import
NullifierPublicKey conditionally
- ffi_codegen.rs: add compute_private_pda_with_program helper; inline PDA
derivation in per-instruction FFI functions branches on pda.private to
call the private variant with the npk arg already parsed from JSON;
standalone compute_{account}_pda helpers updated likewise; import
NullifierPublicKey conditionally
- util.rs: idl_type_to_json_parse handles Defined{"NullifierPublicKey"}
by parsing hex string → [u8; 32] → NullifierPublicKey(arr)
- tests.rs: PRIVATE_PDA_IDL fixture + 6 tests covering npk param presence,
correct derivation function, JSON arg ordering, import inclusion, and
syntax validity for both client and FFI output
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix 1 (E2E compile): compute_private_pda_with_program was always emitted in FFI codegen even when the IDL has no private PDAs, but the NullifierPublicKey import is guarded by needs_npk — causing E0425 in the treasury fixture compile-check. Gate the helper emission on needs_npk. Fix 2 (Privacy smoke test): --npk hex parsing in the pda command used decode_bytes_32 which tries base58 first. A 64-char hex string without any '0' digit passes base58 decode (yielding ~46 bytes), triggering "Base58 decoded to N bytes, expected 32" instead of falling through to hex. Parse --npk directly as hex to avoid the ambiguity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix 1 (E2E compile): compute_private_pda_with_program was always emitted in FFI codegen even when the IDL has no private PDAs, but the NullifierPublicKey import is guarded by needs_npk — causing E0425 in the treasury fixture compile-check. Gate the helper emission on needs_npk. Fix 2 (Privacy smoke test): --npk hex parsing in the pda command used decode_bytes_32 which tries base58 first. A 64-char hex string without any '0' digit passes base58 decode (yielding ~46 bytes), triggering "Base58 decoded to N bytes, expected 32" instead of falling through to hex. Parse --npk directly as hex to avoid the ambiguity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…upport
The privacy-preserving circuit validates private PDA claims via mask=3 using
AccountId::for_private_pda. The LEZ v0.2.0-rc3 wallet API only exposes
PrivacyPreservingAccount::{Public, PrivateOwned, PrivateForeign} (masks 0-2);
there is no PrivatePdaInit variant that sets mask=3 and provides the NPK to
the circuit. Submitting the vault PDA as Public (mask=0) causes the circuit
to check for_public_pda, which doesn't match the for_private_pda address,
producing "Invalid PDA claim".
Skip step 13 with a clear warning; all other parts of the private PDA feature
(IDL generation, framework macros, PDA address computation, CLI pda subcommand)
are correct and covered by unit tests. Add a TODO comment in tx.rs pointing
at the exact mask-3 gap so it's easy to find when LEZ adds the missing variant.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Step 13 (private PDA TX) blocked on LEZThe smoke test passes through step 12 (PDA address computation) but step 13 ( Root cause: The privacy-preserving circuit validates private PDA claims using visibility mask=3, which calls Where it's missing in rc3: Where it exists in main: Unblocking: bump the LEZ dependency from |
29887fa to
2eb5b8c
Compare
Summary
Follow-up to #171 (private PDA macro support). Completes the end-to-end story for private PDAs:
IdlPda.npk_arg: addsnpk_arg: Option<String>to the IDL PDA struct so the CLI knows which instruction arg supplies the NullifierPublicKey — without it, the CLI couldn't compute private PDA addresses at transaction timetx.rswas passingNonefor npk when computing PDAs, always producing a public address; now reads the correct arg from the IDLNullifierPublicKeyin CLI args:parse.rsandserialize.rsnow handleIdlType::Defined{"NullifierPublicKey"}(hex → 32-byte tuple) so instructions that take an npk arg work end-to-endinit_private_pdainstruction to the test program and steps 11–13: retrieve npk from wallet, compute private PDA address viaspel pda, submit the instructionTest plan
cargo test --workspace)idl_init_private_account_marks_pda_as_private(now also assertsnpk_arg == "user_npk")LEZ_TAG=v0.2.0-rc3 LSSA_DIR=<path> ./scripts/smoke-test-privacy.shcompletes all 13 steps including the new private PDA TX🤖 Generated with Claude Code