-
Notifications
You must be signed in to change notification settings - Fork 252
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
pczt: Define the structure and semantics of the PCZT format #1577
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1577 +/- ##
==========================================
- Coverage 61.63% 54.80% -6.83%
==========================================
Files 148 158 +10
Lines 18836 19581 +745
==========================================
- Hits 11610 10732 -878
- Misses 7226 8849 +1623 ☔ View full report in Codecov by Sentry. |
|
||
/// Global fields that are relevant to the transaction as a whole. | ||
#[derive(Clone)] | ||
pub(crate) struct Global { |
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.
Keystone's proposal included a network
field (indicating mainnet vs testnet vs ?) at the global level, possibly because in my 2019 PCZT draft I suggested it. However, I note that PSBTs (BIP 174) do not include such a field (AFAICT). Is such a field necessary, and/or useful?
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.
I don't see why it would be necessary or useful here, but it looks like BIP 174 does include an implicit indication of the network in the serialized extended public keys.
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.
We meet a similar problem on Unisat's Fractal Bitcoin recently. PSBT doesn't have a network field, so we have to set it on the global map field which means it becomes a custom protocol between Unisat and us.
This can be useful if the chain have multiple sub/child chains like Bitcoin vs Litecoin or Dogecoin. In theory Litecoin can also use PSBT, but without network field, we cannot know some accurate info like coin precision.
Anyway, that's depends on Zcash's needs.
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.
Hmm, this is a good point. And as @arya2 notes above and @pacu notes below, we will already be semi-explicitly encoding the network into the PCZT at some later stage. So I think it makes sense for the Creator to encode the network up-front, and then every later instance of data that includes network information can be checked against it for correctness.
Next question then is what format this network field should have. A SLIP 44 coin_type
(as used in BIP 32 and ZIP 32 derivation paths) would make sense for mainnet applications, but SLIP 44 only defines a single testnet code for all coins. Would that be sufficient for Zcash (and potentially other) testnet uses? (I think so, because if you're running against testnet then you already likely know what network you're dealing with, and the important part is that we have domain separation between mainnet and non-mainnet, as well as between Zcash and non-Zcash mainnets.)
pub(crate) tx_version: u32, | ||
pub(crate) version_group_id: u32, |
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.
Should this pair of fields be optional independently of the others?
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.
Would it be better to infer the version group id from the tx version instead of having it as an explicit field?
Should this pair of fields be optional independently of the others?
Would it make sense to adding a builder struct where the tx_version
field is optional instead of making it optional here?
Update: I see there's already a builder struct, so it seems unnecessary to make the field optional here as well.
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.
Would it be better to infer the version group id from the tx version instead of having it as an explicit field?
That's more fragile across consensus forks, but I can see an argument that the tuple (tx_version, consensus_branch_id)
might be sufficient to fully constrain the value of version_group_id
such that every role can reliably deduce it. The main argument against this would be that it would force PCZT roles to be aware of more details about transaction formats, where they might otherwise just be able to focus on the PCZT.
pub(crate) lock_time: u32, | ||
pub(crate) expiry_height: u32, |
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.
Should these be independently optional?
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.
It could be nice to type these as LockTime
and BlockHeight
.
Should these be independently optional?
If this needs to be able to produce v1 or v2 transactions, then at least expiry_height
should probably be optional.
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.
@arya2 I'm intentionally not adding types to the core structure (at least at this stage), to keep its dependencies as minimal / non-existent as possible (because there are many roles that do not need to care about every type in the PCZT, e.g. an Orchard signer doesn't need to be able to parse Sapling-specific types). The Transaction Extractor role necessarily performs all conversions and checks, so that acts as a backstop.
Once we've figured out and agreed on the structure, then it may make sense to add certain newtypes that pczt
can rely on (depending on who the downstream consumers of the crate will be).
/// | ||
/// This is initialized by the Creator, and updated by the Constructor as spends or | ||
/// outputs are added to the PCZT. It enables per-spend and per-output values to be | ||
/// redacted from the PCZT after they are no longer necessary. |
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.
Maybe calculate this at the same time as bsk (in which case it would be an option of (value_balance, bsk)).
/// This is initialized by the Creator, and updated by the Constructor as spends or | ||
/// outputs are added to the PCZT. It enables per-spend and per-output values to be | ||
/// redacted from the PCZT after they are no longer necessary. | ||
pub(crate) value_balance: u64, |
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.
Same comment as Orchard.
pczt/src/orchard.rs
Outdated
/// - After`zkproof` / `spend_auth_sig` has been set, this can be redacted. | ||
pub(crate) alpha: Option<[u8; 32]>, | ||
|
||
// TODO derivation path |
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.
wouldn't this account for network
information (see comments on top of the PR)
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.
Looks good, added some comments about FROST usage
For ZSA issuance I think we need the fields required for computing the |
Force-pushed to fill in some more parts:
|
I'm currently inclined to leave out both FROST support and ZSA issuance support from the first version of PCZTs, as we don't have experience with either of them yet, and trying to get them right at the same time as the base PCZT format is likely to end in sorrow. As @conradoplg notes, we can in some cases have FROST internally pass around a PCZT, but that won't necessarily help for all possible PCZT use cases, so we'll likely want a v2 that adds those fields. That would also be the right time to adjust the core fields if we find weaknesses in the v1 PCZT format. |
I'm happy with leaving FROST out of v1, we can make it work for now by sending additional data along with the PCZT. |
Force-pushed with more changes:
|
These follow the equivalent fields in BIP 174 and BIP 370.
Use of the Constructor role interacts heavily with the per-protocol crates, so I'm now working on the production impl of those, both to fix the format bugs and get us to a working client-side implementation. |
Todo: