rpc: Add JSON-RPC methods for working with PCZTs#541
Open
sellout wants to merge 4 commits into
Open
Conversation
sellout
force-pushed
the
pczt-rpc-methods
branch
from
July 11, 2026 05:25
70a350b to
a75df52
Compare
Pin the pczt crate to the same librustzcash revision as the other patched crates, and enable the pczt roles zallet uses (prover, signer, spend-finalizer, tx-extractor). Enable the zcash_client_backend `pczt` feature for create_pczt_from_proposal, and the zcash_client_sqlite `serde` feature it needs (AccountUuid: Serialize). Vet the new dependencies for cargo-vet: mark `pczt` as a first-party librustzcash crate (`audit-as-crates-io = false`, like its siblings), and add `safe-to-deploy` exemptions for the crates.io deps it pulls in via `serde_with` (`serde_with`/`serde_with_macros` and `darling`/`darling_core`/`darling_macro`), across all three workspace supply-chains.
Add JSON-RPC methods for working with PCZTs (Partially Created Zcash Transactions), the robust replacements for createrawtransaction, fundrawtransaction, and signrawtransaction. A transaction is assembled by threading a PCZT through these roles: - pczt_create: build a PCZT from a payment request (propose_transfer + create_pczt_from_proposal), recording signing hints as proprietary fields since pczt 0.7 exposes no public getter for the native derivation metadata. - pczt_combine: merge several parties' contributions (Combiner). - pczt_prove: add the Sapling and/or Orchard proofs (Prover), off the async runtime, caching the Orchard proving key. - pczt_sign: sign with the wallet's keys (Signer). - pczt_extract: finalize spends and verify before extracting the final transaction (SpendFinalizer + TransactionExtractor). The stateless roles (combine, prove, extract) and the shared decode helper (with a 10 MiB input cap and a 20-PCZT combine cap) are available in every build; create and sign require wallet state. Includes unit tests for the decode limits and combine caps.
Extract the propose/validate pipeline that z_sendmany and pczt_create had in common into a shared payments::propose_and_check helper: the privacy-policy validation loop, propose_transfer with the standard change strategy and input selector, privacy-policy enforcement, and the Orchard-action-limit check. Both call sites now share one implementation. Also have pczt_create reuse the recently-added payments::AmountParameter type and payments::build_request (upstream #535), instead of its own AmountParam struct and inline recipient parsing. And tidy pczt_create's signing hints: drop the unused zallet.v1.network proprietary field (pczt_sign never reads it) and collapse the two Updater passes into one chained pass. Finally, centralize the `zallet.v1.*` signing-hint keys and the key-scope encoding in `pczt_common`, so the `pczt_create` writer and the `pczt_sign` reader share one definition rather than duplicating the string keys and the scope-to-u32 mapping.
sellout
force-pushed
the
pczt-rpc-methods
branch
from
July 11, 2026 06:18
a75df52 to
4878e58
Compare
sellout
marked this pull request as ready for review
July 11, 2026 06:51
Contributor
I think this is the biggest deal here, and obviously it's out of scope for this PR, so I've opened zcash/librustzcash#2623 to track that. Other than that the only thing that jumps out at me is that there's a number of discarded errors and I wonder if it might be good to either roll those into the mapped messages or create variants in the mapped-to error enum? Not a biggy though. Let me know when it's ready for another pass and I'll give it my stamp 🙇 . |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the PCZT (Partially Created Zcash Transaction) JSON-RPC methods requested in #99, as the modern, robust replacements for
createrawtransaction,fundrawtransaction, andsignrawtransaction.Supersedes #354 (thanks @lamb356 for the initial implementation) — this branch rebuilds that work on current
main, addresses all of @nullcopy's review feedback, and fills in the structural gaps.Closes #99.
Methods
A transaction is assembled by threading a PCZT through these roles:
pczt_createpropose_transfer+create_pczt_from_proposalcreaterawtransaction+fundrawtransaction).pczt_combinepczt_provepczt_signpczt_extractThe stateless roles (
combine/prove/extract) live in the generalRpctrait;create/signrequire wallet state.Notes for review
pczt_createvspczt_fund. feat: Add PCZT RPC methods (issue #99) #354 named thispczt_fund; @nullcopy noted that "fund" reads like adding funds to an existing PCZT. That operation (≈fundrawtransactionon a partial PCZT) is effectively infeasible at the pinnedlibrustzcashrev:create_pczt_from_proposalIO-finalizes its output (permanently clearingtx_modifiable), there is noConstructorimplementation or Builder-from-PCZT path, and no input-selector API for a "cover the remaining value" target. So this method builds a complete PCZT from a payment request in one shot (matchingzcash-devtool'spczt create), andpczt_createis the accurate name.pczt_createreusespayments::AmountParameter+build_request(from Extract the shared amount parameter into a reusable payments type #535) and a new sharedpayments::propose_and_checkhelper (privacy-policy validation → propose → enforce → Orchard-action-limit) thatz_sendmanynow also uses, so the two stay in sync.pczt_createrecordszallet.v1.*proprietary fields for an offlinepczt_signto read back — a stand-in for the native path until upstream adds accessors.pczt_extractverifies. It runs the spend finalizer and verifies all proofs/signatures (supplying the bundled Sapling verifying keys) before producing the transaction, rather than deferring to the network.Dependencies
Adds
pczt0.7, pinned to the samelibrustzcashrevision as the other[patch.crates-io]crates, and enables thezcash_client_backend/pcztbuilder support pluszcash_client_sqlite/serde(required forAccountUuid: Serialize, whichcreate_pczt_from_proposalneeds).Testing
pczt_combinecaps.cargo clippy --all-targets -- -D warningsclean; fullzalletlib test suite green.zcash_client_backenddata_api::testingframework can't be used from a downstream crate at the pinned rev — its only concrete store factory (zcash_client_sqlite::testing) is#[cfg(test)]-only, and there is nozcash_client_memorycrate at this rev — so the fullcreate → prove → sign → extractpath is verified by manual regtest for now. A follow-up could vendor a minimal in-memory store factory to unlock a node-free CI test.Rebased onto
main@ 4fa38e1. The commits on this branch are currently unsigned.