Make ZcashSerialize infallible mod its Writer.
Closes #158. As discussed on the issue, this makes it possible to safely serialize data into hashes, and encourages serializable data to make illegal states unrepresentable.
This commit is contained in:
parent
b0f61c4dd2
commit
972d16518f
|
|
@ -48,13 +48,13 @@ impl From<BlockHeader> for BlockHeaderHash {
|
|||
let mut hash_writer = Sha256dWriter::default();
|
||||
block_header
|
||||
.zcash_serialize(&mut hash_writer)
|
||||
.expect("Block headers must serialize.");
|
||||
.expect("Sha256dWriter is infallible");
|
||||
Self(hash_writer.finish())
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashSerialize for BlockHeaderHash {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ pub struct BlockHeader {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for BlockHeader {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
// "The current and only defined block version number for Zcash is 4."
|
||||
writer.write_u32::<LittleEndian>(4)?;
|
||||
self.previous_block_hash.zcash_serialize(&mut writer)?;
|
||||
|
|
@ -170,7 +170,7 @@ pub struct Block {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for Block {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.header.zcash_serialize(&mut writer)?;
|
||||
self.transactions.zcash_serialize(&mut writer)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl Clone for EquihashSolution {
|
|||
impl Eq for EquihashSolution {}
|
||||
|
||||
impl ZcashSerialize for EquihashSolution {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_compactsize(EQUIHASH_SOLUTION_SIZE as u64)?;
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub struct MerkleTree<T> {
|
|||
}
|
||||
|
||||
impl<Transaction> ZcashSerialize for MerkleTree<Transaction> {
|
||||
fn zcash_serialize<W: io::Write>(&self, _writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, _writer: W) -> Result<(), io::Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ impl From<MerkleTree<Transaction>> for MerkleTreeRootHash {
|
|||
let mut hash_writer = Sha256dWriter::default();
|
||||
merkle_tree
|
||||
.zcash_serialize(&mut hash_writer)
|
||||
.expect("The merkle tree of transactions must serialize.");
|
||||
.expect("Sha256dWriter is infallible");
|
||||
Self(hash_writer.finish())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl SaplingNoteCommitmentTree {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for SaplingNoteCommitmentTree {
|
||||
fn zcash_serialize<W: io::Write>(&self, _writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, _writer: W) -> Result<(), io::Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl PartialEq for Bctv14Proof {
|
|||
impl Eq for Bctv14Proof {}
|
||||
|
||||
impl ZcashSerialize for Bctv14Proof {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl PartialEq for Groth16Proof {
|
|||
impl Eq for Groth16Proof {}
|
||||
|
||||
impl ZcashSerialize for Groth16Proof {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,12 @@ pub trait ZcashSerialize: Sized {
|
|||
/// This function has a `zcash_` prefix to alert the reader that the
|
||||
/// serialization in use is consensus-critical serialization, rather than
|
||||
/// some other kind of serialization.
|
||||
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), SerializationError>;
|
||||
///
|
||||
/// Notice that the error type is [`std::io::Error`]; this indicates that
|
||||
/// serialization MUST be infallible up to errors in the underlying writer.
|
||||
/// In other words, any type implementing `ZcashSerialize` must make illegal
|
||||
/// states unrepresentable.
|
||||
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error>;
|
||||
}
|
||||
|
||||
/// Consensus-critical serialization for Zcash.
|
||||
|
|
@ -56,7 +61,7 @@ pub trait ZcashDeserialize: Sized {
|
|||
}
|
||||
|
||||
impl<T: ZcashSerialize> ZcashSerialize for Vec<T> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_compactsize(self.len() as u64)?;
|
||||
for x in self {
|
||||
x.zcash_serialize(&mut writer)?;
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ impl PartialEq for EncryptedCiphertext {
|
|||
impl Eq for EncryptedCiphertext {}
|
||||
|
||||
impl ZcashSerialize for EncryptedCiphertext {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C4_8270;
|
|||
const SAPLING_VERSION_GROUP_ID: u32 = 0x892F_2085;
|
||||
|
||||
impl ZcashSerialize for OutPoint {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.hash.0[..])?;
|
||||
writer.write_u32::<LittleEndian>(self.index)?;
|
||||
Ok(())
|
||||
|
|
@ -33,7 +33,7 @@ impl ZcashDeserialize for OutPoint {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for TransparentInput {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.previous_output.zcash_serialize(&mut writer)?;
|
||||
self.signature_script.zcash_serialize(&mut writer)?;
|
||||
writer.write_u32::<LittleEndian>(self.sequence)?;
|
||||
|
|
@ -52,7 +52,7 @@ impl ZcashDeserialize for TransparentInput {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for TransparentOutput {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_u64::<LittleEndian>(self.value)?;
|
||||
self.pk_script.zcash_serialize(&mut writer)?;
|
||||
Ok(())
|
||||
|
|
@ -69,7 +69,7 @@ impl ZcashDeserialize for TransparentOutput {
|
|||
}
|
||||
|
||||
impl<P: ZkSnarkProof> ZcashSerialize for JoinSplit<P> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_u64::<LittleEndian>(self.vpub_old)?;
|
||||
writer.write_u64::<LittleEndian>(self.vpub_new)?;
|
||||
writer.write_all(&self.anchor[..])?;
|
||||
|
|
@ -109,7 +109,7 @@ impl<P: ZkSnarkProof> ZcashDeserialize for JoinSplit<P> {
|
|||
}
|
||||
|
||||
impl<P: ZkSnarkProof> ZcashSerialize for JoinSplitData<P> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_compactsize(self.joinsplits().count() as u64)?;
|
||||
for joinsplit in self.joinsplits() {
|
||||
joinsplit.zcash_serialize(&mut writer)?;
|
||||
|
|
@ -145,7 +145,7 @@ impl<P: ZkSnarkProof> ZcashDeserialize for Option<JoinSplitData<P>> {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for SpendDescription {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.cv[..])?;
|
||||
writer.write_all(&self.anchor.0[..])?;
|
||||
writer.write_all(&self.nullifier[..])?;
|
||||
|
|
@ -171,7 +171,7 @@ impl ZcashDeserialize for SpendDescription {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for OutputDescription {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.cv[..])?;
|
||||
writer.write_all(&self.cmu[..])?;
|
||||
writer.write_all(&self.ephemeral_key[..])?;
|
||||
|
|
@ -196,7 +196,7 @@ impl ZcashDeserialize for OutputDescription {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for Transaction {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
match self {
|
||||
Transaction::V1 {
|
||||
inputs,
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ impl PartialEq for EncryptedCiphertext {
|
|||
impl Eq for EncryptedCiphertext {}
|
||||
|
||||
impl ZcashSerialize for EncryptedCiphertext {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -300,7 +300,7 @@ impl PartialEq for OutCiphertext {
|
|||
impl Eq for OutCiphertext {}
|
||||
|
||||
impl ZcashSerialize for OutCiphertext {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pub enum LockTime {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for LockTime {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
// This implementation does not check the invariants on `LockTime` so that the
|
||||
// serialization is fallible only if the underlying writer is. This ensures that
|
||||
// we can always compute a hash of a transaction object.
|
||||
|
|
@ -106,7 +106,7 @@ impl Arbitrary for LockTime {
|
|||
pub struct Script(pub Vec<u8>);
|
||||
|
||||
impl ZcashSerialize for Script {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_compactsize(self.0.len() as u64)?;
|
||||
writer.write_all(&self.0[..])?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl PartialOrd for MetaAddr {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for MetaAddr {
|
||||
fn zcash_serialize<W: Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
|
||||
writer.write_u32::<LittleEndian>(self.last_seen.timestamp() as u32)?;
|
||||
writer.write_u64::<LittleEndian>(self.services.bits())?;
|
||||
writer.write_socket_addr(self.addr)?;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl From<BlockHeaderHash> for InventoryHash {
|
|||
}
|
||||
|
||||
impl ZcashSerialize for InventoryHash {
|
||||
fn zcash_serialize<W: Write>(&self, mut writer: W) -> Result<(), SerializationError> {
|
||||
fn zcash_serialize<W: Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
|
||||
let (code, bytes) = match *self {
|
||||
InventoryHash::Error => (0, [0; 32]),
|
||||
InventoryHash::Tx(hash) => (1, hash.0),
|
||||
|
|
|
|||
Loading…
Reference in New Issue