-
Notifications
You must be signed in to change notification settings - Fork 117
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
Serialize/Deserialize sapling data in V5 #1860
Conversation
struct SigShieldedData<'a> { | ||
sig: bool, | ||
shielded_data: &'a Option<ShieldedData>, | ||
} |
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.
transaction::ShieldedData
includes binding_sig
, for the Sapling data I'm not sure why this type is needed.
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 is needed for the order of the fields inside a transaction. In V4 transactions we have the spends and outputs for sapling then the joinsplits and then the binding sig. This is explained in https://github.com/ZcashFoundation/zebra/blob/main/zebra-chain/src/transaction/serialize.rs#L147-L153 and can be verified by checking the fields of the V4 transaction in the spec.
In the other hand in the V5 transactions the binding sig is intermediately after the sapling spends and outputs so it can be serialized right there as there is nothing in the middle.
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.
Please add a doc comment for this type, that explains why it's needed, and how it should be used.
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.
Actually, it looks like we can't use this type, because ShieldedData
is different in V4 and V5 transactions.
} else { | ||
None | ||
}; | ||
let shielded_data = |
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.
Transaction::v4
isn't changing so I don't think we need to change this.
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.
The idea is to use the same code in V4 and V5 as they are doing almost the same for sapling stuff(except for the order of the fields).
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.
Even though they have the same names, the underlying types of these fields are different, so it might be best to just duplicate some code.
@@ -222,21 +226,26 @@ impl Transaction { | |||
// This function returns a boxed iterator because the different | |||
// transaction variants end up having different iterator types | |||
match self { | |||
// JoinSplits with Groth Proofs | |||
// Transactions with ShieldedData |
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.
👍
zebra-chain/src/transaction.rs
Outdated
/// The shielded data for this transaction, if any. | ||
shielded_data: Option<ShieldedData>, | ||
/// The net value of Sapling spend transfers minus output transfers. | ||
value_balance: Amount, |
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.
v5 transactions also include the Orchard value balance.
So we'll need to rename shielded_data
, ShieldedData
, and value_balance
to include sapling
. We should make this change across V4
and V5
transactions, for consistency.
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.
Actually, we'll need to make this change in this PR, because the v5 transaction format changes the fields inside ShieldedData
. So we'll need to:
- rename
ShieldedData
toSaplingV4ShieldedData
- add
SaplingV5ShieldedData
- in a later PR, add
OrchardActionData
@dconnolly what's a good name for the new SaplingV5ShieldedData
type?
It doesn't have any proofs or signatures, just value commitments, nullifiers, keys, and ciphertext.
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.
What about having ShieldedData::V4
and ShieldedData::V5
instead ?
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.
What about having
ShieldedData::V4
andShieldedData::V5
instead ?
That's still easily confused with Orchard shielded data. (And a bit confusing with Sprout shielded data as well.)
let shielded_data = self.shielded_data; | ||
match shielded_data { | ||
None => { | ||
// Signal no shielded spends and no shielded outputs. |
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.
// Signal no shielded spends and no shielded outputs. | |
// There are no shielded spends and no shielded outputs. | |
// Since all other fields are omitted, the serialization is the same in V4 and V5 transactions. |
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.
The contents of the vSpendsSapling
and vOutputsSapling
fields has changed in V5
transactions: they contain much less data. So we won't be able to parse them using the existing ShieldedData
type.
This isn't quite clear from the spec, because the field sizes are wrong. I've made some comments on the draft spec PR.
Blocked on #1863 |
let shielded_spends = Vec::zcash_deserialize(&mut reader)?; | ||
let shielded_outputs = Vec::zcash_deserialize(&mut reader)?; | ||
let shielded_data = | ||
deserialize_shielded_data(&mut reader, shielded_spends, shielded_outputs)?; | ||
let sapling_value_balance = (&mut reader).zcash_deserialize_into()?; |
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.
If inputs and outputs are None
, these fields do not exist in V5
:
#1829 (comment)
I will add a test for this bug to the design in #1863.
After #1863 is completed, please revise all the code in this PR, based on the latest spec.
Motivation
Parse sapling data in transaction v5: #1829
Solution
It is very similar to V4 but the order of the fields is different in the 2 versions. This complicates a bit the de-duplication efforts.
For the serialize a new type
SigShieldedData
was added and theZcashSerialize
implementation is done against this new type that haves the shielded data and a flag to control if the serializing of thebinding_sig
field will be done here or not. V4 needs to serialize thebinding_sig
later so the flag for it isfalse
while in V5 everything can be done in the same place so this flag istrue
.For deserialization the idea is similar but we cant implement a type as
zcash_deserialize
cant access the instance(noself
is available). So by now i implemented this as a function.The rest is pretty straightforward however i am not sure if this is the best approach, open to options.
Review
Related Issues
If merged this will close #1829