Move TZE components to a separate module & add TzeOutPoint

This commit is contained in:
Kris Nuttycombe 2021-03-04 09:35:53 -07:00 committed by Jack Grigg
parent 97f2502a5e
commit c839193b20
6 changed files with 206 additions and 160 deletions

View File

@ -26,7 +26,7 @@ use blake2b_simd::Params;
use zcash_primitives::{
extensions::transparent::{Extension, ExtensionTxBuilder, FromPayload, ToPayload},
transaction::components::{amount::Amount, OutPoint, TzeOut},
transaction::components::{amount::Amount, TzeOut, TzeOutPoint},
};
/// Types and constants used for Mode 0 (open a channel)
@ -374,7 +374,7 @@ impl<'a, B: ExtensionTxBuilder<'a>> DemoBuilder<&mut B> {
/// precondition to the transaction under construction.
pub fn demo_transfer_to_close(
&mut self,
prevout: (OutPoint, TzeOut),
prevout: (TzeOutPoint, TzeOut),
transfer_amount: Amount,
preimage_1: [u8; 32],
hash_2: [u8; 32],
@ -416,7 +416,7 @@ impl<'a, B: ExtensionTxBuilder<'a>> DemoBuilder<&mut B> {
/// Add a channel-closing witness to the transaction under construction.
pub fn demo_close(
&mut self,
prevout: (OutPoint, TzeOut),
prevout: (TzeOutPoint, TzeOut),
preimage_2: [u8; 32],
) -> Result<(), DemoBuildError<B::BuildError>> {
let hash_2 = {
@ -477,7 +477,7 @@ mod tests {
builder::Builder,
components::{
amount::{Amount, DEFAULT_FEE},
OutPoint, TzeIn, TzeOut,
TzeIn, TzeOut, TzeOutPoint,
},
Transaction, TransactionData,
},
@ -625,7 +625,7 @@ mod tests {
//
let in_b = TzeIn {
prevout: OutPoint::new(tx_a.txid().0, 0),
prevout: TzeOutPoint::new(tx_a.txid().0, 0),
witness: tze::Witness::from(0, &Witness::open(preimage_1)),
};
let out_b = TzeOut {
@ -642,7 +642,7 @@ mod tests {
//
let in_c = TzeIn {
prevout: OutPoint::new(tx_b.txid().0, 0),
prevout: TzeOutPoint::new(tx_b.txid().0, 0),
witness: tze::Witness::from(0, &Witness::close(preimage_2)),
};
@ -736,7 +736,10 @@ mod tests {
txn_builder: &mut builder_b,
extension_id: 0,
};
let prevout_a = (OutPoint::new(tx_a.txid().0, 0), tx_a.tze_outputs[0].clone());
let prevout_a = (
TzeOutPoint::new(tx_a.txid().0, 0),
tx_a.tze_outputs[0].clone(),
);
let value_xfr = value - DEFAULT_FEE;
db_b.demo_transfer_to_close(prevout_a, value_xfr, preimage_1, h2)
.map_err(|e| format!("transfer failure: {:?}", e))
@ -755,7 +758,10 @@ mod tests {
txn_builder: &mut builder_c,
extension_id: 0,
};
let prevout_b = (OutPoint::new(tx_a.txid().0, 0), tx_b.tze_outputs[0].clone());
let prevout_b = (
TzeOutPoint::new(tx_a.txid().0, 0),
tx_b.tze_outputs[0].clone(),
);
db_c.demo_close(prevout_b, preimage_2)
.map_err(|e| format!("close failure: {:?}", e))
.unwrap();

View File

@ -1,6 +1,6 @@
//! Core traits and structs for Transparent Zcash Extensions.
use crate::transaction::components::{Amount, OutPoint, TzeOut};
use crate::transaction::components::{Amount, TzeOut, TzeOutPoint};
use std::fmt;
/// Binary parsing capability for TZE preconditions & witnesses.
@ -178,7 +178,7 @@ pub trait ExtensionTxBuilder<'a> {
&mut self,
extension_id: u32,
mode: u32,
prevout: (OutPoint, TzeOut),
prevout: (TzeOutPoint, TzeOut),
witness_builder: WBuilder,
) -> Result<(), Self::BuildError>
where

View File

@ -32,17 +32,17 @@ use crate::{
};
#[cfg(feature = "transparent-inputs")]
use crate::{legacy::Script, transaction::components::TxIn};
use crate::{
legacy::Script,
transaction::components::{OutPoint, TxIn},
};
#[cfg(feature = "zfuture")]
use crate::{
extensions::transparent::{self as tze, ExtensionTxBuilder, ToPayload},
transaction::components::{TzeIn, TzeOut},
transaction::components::{TzeIn, TzeOut, TzeOutPoint},
};
#[cfg(any(feature = "transparent-inputs", feature = "zfuture"))]
use crate::transaction::components::OutPoint;
#[cfg(any(test, feature = "test-dependencies"))]
use crate::prover::mock::MockTxProver;
@ -869,7 +869,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> ExtensionTxBuilder<'a
&mut self,
extension_id: u32,
mode: u32,
(outpoint, prevout): (OutPoint, TzeOut),
(outpoint, prevout): (TzeOutPoint, TzeOut),
witness_builder: WBuilder,
) -> Result<(), Self::BuildError>
where

View File

@ -1,22 +1,10 @@
//! Structs representing the components within Zcash transactions.
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{self, Read, Write};
#[cfg(feature = "zfuture")]
use std::convert::TryFrom;
#[cfg(feature = "zfuture")]
use crate::{
extensions::transparent as tze,
serialize::{CompactSize, Vector},
};
pub mod amount;
pub mod sapling;
pub mod sprout;
pub mod transparent;
pub mod tze;
pub use self::{
amount::Amount,
sapling::{OutputDescription, SpendDescription},
@ -24,134 +12,8 @@ pub use self::{
transparent::{OutPoint, TxIn, TxOut},
};
#[cfg(feature = "zfuture")]
pub use self::tze::{TzeIn, TzeOut, TzeOutPoint};
// π_A + π_B + π_C
pub const GROTH_PROOF_SIZE: usize = 48 + 96 + 48;
#[cfg(feature = "zfuture")]
fn to_io_error(_: std::num::TryFromIntError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, "value out of range")
}
#[derive(Clone, Debug, PartialEq)]
#[cfg(feature = "zfuture")]
pub struct TzeIn {
pub prevout: OutPoint,
pub witness: tze::Witness,
}
/// Transaction encoding and decoding functions conforming to [ZIP 222].
///
/// [ZIP 222]: https://zips.z.cash/zip-0222#encoding-in-transactions
#[cfg(feature = "zfuture")]
impl TzeIn {
/// Convenience constructor
pub fn new(prevout: OutPoint, extension_id: u32, mode: u32) -> Self {
TzeIn {
prevout,
witness: tze::Witness {
extension_id,
mode,
payload: vec![],
},
}
}
/// Read witness metadata & payload
///
/// Used to decode the encoded form used within a serialized
/// transaction.
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let prevout = OutPoint::read(&mut reader)?;
let extension_id = CompactSize::read(&mut reader)?;
let mode = CompactSize::read(&mut reader)?;
let payload = Vector::read(&mut reader, |r| r.read_u8())?;
Ok(TzeIn {
prevout,
witness: tze::Witness {
extension_id: u32::try_from(extension_id).map_err(to_io_error)?,
mode: u32::try_from(mode).map_err(to_io_error)?,
payload,
},
})
}
/// Write without witness data (for signature hashing)
///
/// This is also used as the prefix for the encoded form used
/// within a serialized transaction.
pub fn write_without_witness<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.prevout.write(&mut writer)?;
CompactSize::write(
&mut writer,
usize::try_from(self.witness.extension_id).map_err(to_io_error)?,
)?;
CompactSize::write(
&mut writer,
usize::try_from(self.witness.mode).map_err(to_io_error)?,
)
}
/// Write prevout, extension, and mode followed by witness data.
///
/// This calls [`write_without_witness`] to serialize witness metadata,
/// then appends the witness bytes themselves. This is the encoded
/// form that is used in a serialized transaction.
///
/// [`write_without_witness`]: TzeIn::write_without_witness
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.write_without_witness(&mut writer)?;
Vector::write(&mut writer, &self.witness.payload, |w, b| w.write_u8(*b))
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg(feature = "zfuture")]
pub struct TzeOut {
pub value: Amount,
pub precondition: tze::Precondition,
}
#[cfg(feature = "zfuture")]
impl TzeOut {
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let value = {
let mut tmp = [0; 8];
reader.read_exact(&mut tmp)?;
Amount::from_nonnegative_i64_le_bytes(tmp)
}
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "value out of range"))?;
let extension_id = CompactSize::read(&mut reader)?;
let mode = CompactSize::read(&mut reader)?;
let payload = Vector::read(&mut reader, |r| r.read_u8())?;
Ok(TzeOut {
value,
precondition: tze::Precondition {
extension_id: u32::try_from(extension_id).map_err(to_io_error)?,
mode: u32::try_from(mode).map_err(to_io_error)?,
payload,
},
})
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.value.to_i64_le_bytes())?;
CompactSize::write(
&mut writer,
usize::try_from(self.precondition.extension_id).map_err(to_io_error)?,
)?;
CompactSize::write(
&mut writer,
usize::try_from(self.precondition.mode).map_err(to_io_error)?,
)?;
Vector::write(&mut writer, &self.precondition.payload, |w, b| {
w.write_u8(*b)
})
}
}

View File

@ -0,0 +1,171 @@
//! Structs representing the TZE components within Zcash transactions.
#![cfg(feature = "zfuture")]
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, Read, Write};
use std::convert::TryFrom;
use crate::{
extensions::transparent as tze,
serialize::{CompactSize, Vector},
};
use super::amount::Amount;
fn to_io_error(_: std::num::TryFromIntError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, "value out of range")
}
#[derive(Clone, Debug, PartialEq)]
pub struct TzeOutPoint {
hash: [u8; 32],
n: u32,
}
impl TzeOutPoint {
pub fn new(hash: [u8; 32], n: u32) -> Self {
TzeOutPoint { hash, n }
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let mut hash = [0u8; 32];
reader.read_exact(&mut hash)?;
let n = reader.read_u32::<LittleEndian>()?;
Ok(TzeOutPoint { hash, n })
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.hash)?;
writer.write_u32::<LittleEndian>(self.n)
}
pub fn n(&self) -> u32 {
self.n
}
pub fn hash(&self) -> &[u8; 32] {
&self.hash
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TzeIn {
pub prevout: TzeOutPoint,
pub witness: tze::Witness,
}
/// Transaction encoding and decoding functions conforming to [ZIP 222].
///
/// [ZIP 222]: https://zips.z.cash/zip-0222#encoding-in-transactions
impl TzeIn {
/// Convenience constructor
pub fn new(prevout: TzeOutPoint, extension_id: u32, mode: u32) -> Self {
TzeIn {
prevout,
witness: tze::Witness {
extension_id,
mode,
payload: vec![],
},
}
}
/// Read witness metadata & payload
///
/// Used to decode the encoded form used within a serialized
/// transaction.
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let prevout = TzeOutPoint::read(&mut reader)?;
let extension_id = CompactSize::read(&mut reader)?;
let mode = CompactSize::read(&mut reader)?;
let payload = Vector::read(&mut reader, |r| r.read_u8())?;
Ok(TzeIn {
prevout,
witness: tze::Witness {
extension_id: u32::try_from(extension_id).map_err(to_io_error)?,
mode: u32::try_from(mode).map_err(to_io_error)?,
payload,
},
})
}
/// Write without witness data (for signature hashing)
///
/// This is also used as the prefix for the encoded form used
/// within a serialized transaction.
pub fn write_without_witness<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.prevout.write(&mut writer)?;
CompactSize::write(
&mut writer,
usize::try_from(self.witness.extension_id).map_err(to_io_error)?,
)?;
CompactSize::write(
&mut writer,
usize::try_from(self.witness.mode).map_err(to_io_error)?,
)
}
/// Write prevout, extension, and mode followed by witness data.
///
/// This calls [`write_without_witness`] to serialize witness metadata,
/// then appends the witness bytes themselves. This is the encoded
/// form that is used in a serialized transaction.
///
/// [`write_without_witness`]: TzeIn::write_without_witness
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.write_without_witness(&mut writer)?;
Vector::write(&mut writer, &self.witness.payload, |w, b| w.write_u8(*b))
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TzeOut {
pub value: Amount,
pub precondition: tze::Precondition,
}
impl TzeOut {
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let value = {
let mut tmp = [0; 8];
reader.read_exact(&mut tmp)?;
Amount::from_nonnegative_i64_le_bytes(tmp)
}
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "value out of range"))?;
let extension_id = CompactSize::read(&mut reader)?;
let mode = CompactSize::read(&mut reader)?;
let payload = Vector::read(&mut reader, |r| r.read_u8())?;
Ok(TzeOut {
value,
precondition: tze::Precondition {
extension_id: u32::try_from(extension_id).map_err(to_io_error)?,
mode: u32::try_from(mode).map_err(to_io_error)?,
payload,
},
})
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.value.to_i64_le_bytes())?;
CompactSize::write(
&mut writer,
usize::try_from(self.precondition.extension_id).map_err(to_io_error)?,
)?;
CompactSize::write(
&mut writer,
usize::try_from(self.precondition.mode).map_err(to_io_error)?,
)?;
Vector::write(&mut writer, &self.precondition.payload, |w, b| {
w.write_u8(*b)
})
}
}

View File

@ -508,7 +508,7 @@ pub mod testing {
};
#[cfg(feature = "zfuture")]
use super::components::{TzeIn, TzeOut};
use super::components::{TzeIn, TzeOut, TzeOutPoint};
pub const VALID_OPCODES: [u8; 8] = [
0x00, // OP_FALSE,
@ -551,6 +551,13 @@ pub mod testing {
}
}
#[cfg(feature = "zfuture")]
prop_compose! {
pub fn arb_tzeoutpoint()(hash in prop::array::uniform32(1u8..), n in 1..100u32) -> TzeOutPoint {
TzeOutPoint::new(hash, n)
}
}
#[cfg(feature = "zfuture")]
prop_compose! {
pub fn arb_witness()(extension_id in 0..100u32, mode in 0..100u32, payload in vec(any::<u8>(), 32..256)) -> tze::Witness {
@ -560,7 +567,7 @@ pub mod testing {
#[cfg(feature = "zfuture")]
prop_compose! {
pub fn arb_tzein()(prevout in arb_outpoint(), witness in arb_witness()) -> TzeIn {
pub fn arb_tzein()(prevout in arb_tzeoutpoint(), witness in arb_witness()) -> TzeIn {
TzeIn { prevout, witness }
}
}