chain: move LockTime into transaction
This commit is contained in:
parent
8e9a239687
commit
5f71bcd0d1
|
|
@ -6,7 +6,7 @@ use crate::merkle_tree::MerkleTreeRootHash;
|
|||
use crate::serialization::{
|
||||
sha256d, SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize,
|
||||
};
|
||||
use crate::types::LockTime;
|
||||
use crate::transaction::LockTime;
|
||||
use crate::Network;
|
||||
|
||||
use crate::test::generate;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use std::sync::Arc;
|
|||
use crate::{
|
||||
block::{Block, BlockHeader, MAX_BLOCK_BYTES},
|
||||
serialization::{ZcashDeserialize, ZcashSerialize},
|
||||
transaction::{Transaction, TransparentInput, TransparentOutput},
|
||||
types::LockTime,
|
||||
transaction::{LockTime, Transaction, TransparentInput, TransparentOutput},
|
||||
};
|
||||
|
||||
/// Generate a block header
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
mod hash;
|
||||
mod joinsplit;
|
||||
mod lock_time;
|
||||
mod serialize;
|
||||
mod shielded_data;
|
||||
mod transparent;
|
||||
|
|
@ -13,12 +14,13 @@ mod tests;
|
|||
|
||||
pub use hash::TransactionHash;
|
||||
pub use joinsplit::{JoinSplit, JoinSplitData};
|
||||
pub use lock_time::LockTime;
|
||||
pub use shielded_data::{Output, ShieldedData, Spend};
|
||||
pub use transparent::{CoinbaseData, OutPoint, TransparentInput, TransparentOutput};
|
||||
|
||||
use crate::amount::Amount;
|
||||
use crate::proofs::{Bctv14Proof, Groth16Proof};
|
||||
use crate::types::{BlockHeight, LockTime};
|
||||
use crate::types::BlockHeight;
|
||||
|
||||
/// A Zcash transaction.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
use std::io;
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||
use crate::types::BlockHeight;
|
||||
|
||||
/// A Bitcoin-style `locktime`, representing either a block height or an epoch
|
||||
/// time.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// Users should not construct a `LockTime` with:
|
||||
/// - a `BlockHeight` greater than MAX_BLOCK_HEIGHT,
|
||||
/// - a timestamp before 6 November 1985
|
||||
/// (Unix timestamp less than MIN_LOCK_TIMESTAMP), or
|
||||
/// - a timestamp after 5 February 2106
|
||||
/// (Unix timestamp greater than MAX_LOCK_TIMESTAMP).
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LockTime {
|
||||
/// Unlock at a particular block height.
|
||||
Height(BlockHeight),
|
||||
/// Unlock at a particular time.
|
||||
Time(DateTime<Utc>),
|
||||
}
|
||||
|
||||
impl LockTime {
|
||||
/// The minimum LockTime::Time, as a timestamp in seconds.
|
||||
///
|
||||
/// Users should not construct lock times less than `MIN_TIMESTAMP`.
|
||||
pub const MIN_TIMESTAMP: i64 = 500_000_000;
|
||||
|
||||
/// The maximum LockTime::Time, as a timestamp in seconds.
|
||||
///
|
||||
/// Users should not construct lock times greater than `MAX_TIMESTAMP`.
|
||||
/// LockTime is u32 in the spec, so times are limited to u32::MAX.
|
||||
pub const MAX_TIMESTAMP: i64 = u32::MAX as i64;
|
||||
|
||||
/// Returns the minimum LockTime::Time, as a LockTime.
|
||||
///
|
||||
/// Users should not construct lock times less than `min_lock_timestamp`.
|
||||
//
|
||||
// When `Utc.timestamp` stabilises as a const function, we can make this a
|
||||
// const function.
|
||||
pub fn min_lock_time() -> LockTime {
|
||||
LockTime::Time(Utc.timestamp(Self::MIN_TIMESTAMP, 0))
|
||||
}
|
||||
|
||||
/// Returns the maximum LockTime::Time, as a LockTime.
|
||||
///
|
||||
/// Users should not construct lock times greater than `max_lock_timestamp`.
|
||||
//
|
||||
// When `Utc.timestamp` stabilises as a const function, we can make this a
|
||||
// const function.
|
||||
pub fn max_lock_time() -> LockTime {
|
||||
LockTime::Time(Utc.timestamp(Self::MAX_TIMESTAMP, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashSerialize for LockTime {
|
||||
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.
|
||||
use LockTime::*;
|
||||
match self {
|
||||
Height(BlockHeight(n)) => writer.write_u32::<LittleEndian>(*n)?,
|
||||
Time(t) => writer.write_u32::<LittleEndian>(t.timestamp() as u32)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashDeserialize for LockTime {
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
let n = reader.read_u32::<LittleEndian>()?;
|
||||
if n <= BlockHeight::MAX.0 {
|
||||
Ok(LockTime::Height(BlockHeight(n)))
|
||||
} else {
|
||||
Ok(LockTime::Time(Utc.timestamp(n as i64, 0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
use chrono::{TimeZone, Utc};
|
||||
use futures::future::Either;
|
||||
use proptest::{arbitrary::any, array, collection::vec, option, prelude::*};
|
||||
|
||||
|
|
@ -7,11 +8,11 @@ use crate::{
|
|||
notes::{sapling, sprout},
|
||||
proofs::{Bctv14Proof, Groth16Proof, ZkSnarkProof},
|
||||
transaction::{
|
||||
CoinbaseData, JoinSplit, JoinSplitData, OutPoint, Output, ShieldedData, Spend, Transaction,
|
||||
TransparentInput, TransparentOutput,
|
||||
CoinbaseData, JoinSplit, JoinSplitData, LockTime, OutPoint, Output, ShieldedData, Spend,
|
||||
Transaction, TransparentInput, TransparentOutput,
|
||||
},
|
||||
treestate::{self, note_commitment_tree::SaplingNoteTreeRootHash},
|
||||
types::{BlockHeight, LockTime, Script},
|
||||
types::{BlockHeight, Script},
|
||||
};
|
||||
|
||||
impl Transaction {
|
||||
|
|
@ -100,6 +101,22 @@ impl Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for LockTime {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||
prop_oneof![
|
||||
(BlockHeight::MIN.0..=BlockHeight::MAX.0)
|
||||
.prop_map(|n| LockTime::Height(BlockHeight(n))),
|
||||
(LockTime::MIN_TIMESTAMP..=LockTime::MAX_TIMESTAMP)
|
||||
.prop_map(|n| { LockTime::Time(Utc.timestamp(n as i64, 0)) })
|
||||
]
|
||||
.boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
impl<P: ZkSnarkProof + Arbitrary + 'static> Arbitrary for JoinSplit<P> {
|
||||
type Parameters = ();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use proptest::prelude::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
use super::super::*;
|
||||
|
||||
use crate::serialization::{ZcashDeserializeInto, ZcashSerialize};
|
||||
use crate::serialization::{ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize};
|
||||
|
||||
proptest! {
|
||||
|
||||
#[test]
|
||||
fn transaction_roundtrip(tx in any::<Transaction>()) {
|
||||
let data = tx.zcash_serialize_to_vec().expect("tx should serialize");
|
||||
|
|
@ -13,4 +13,15 @@ proptest! {
|
|||
|
||||
prop_assert_eq![tx, tx2];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locktime_roundtrip(locktime in any::<LockTime>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
locktime.zcash_serialize(&mut bytes)?;
|
||||
|
||||
bytes.set_position(0);
|
||||
let other_locktime = LockTime::zcash_deserialize(&mut bytes)?;
|
||||
|
||||
prop_assert_eq![locktime, other_locktime];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
use crate::serialization::{
|
||||
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
|
||||
};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use std::{
|
||||
fmt,
|
||||
io::{self, Read},
|
||||
|
|
@ -46,25 +44,6 @@ impl Arbitrary for BlockHeight {
|
|||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
/// A Bitcoin-style `locktime`, representing either a block height or an epoch
|
||||
/// time.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// Users should not construct a `LockTime` with:
|
||||
/// - a `BlockHeight` greater than MAX_BLOCK_HEIGHT,
|
||||
/// - a timestamp before 6 November 1985
|
||||
/// (Unix timestamp less than MIN_LOCK_TIMESTAMP), or
|
||||
/// - a timestamp after 5 February 2106
|
||||
/// (Unix timestamp greater than MAX_LOCK_TIMESTAMP).
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LockTime {
|
||||
/// Unlock at a particular block height.
|
||||
Height(BlockHeight),
|
||||
/// Unlock at a particular time.
|
||||
Time(DateTime<Utc>),
|
||||
}
|
||||
|
||||
impl BlockHeight {
|
||||
/// The minimum BlockHeight.
|
||||
///
|
||||
|
|
@ -87,81 +66,6 @@ impl BlockHeight {
|
|||
pub const MAX_AS_U32: u32 = Self::MAX.0;
|
||||
}
|
||||
|
||||
impl LockTime {
|
||||
/// The minimum LockTime::Time, as a timestamp in seconds.
|
||||
///
|
||||
/// Users should not construct lock times less than `MIN_TIMESTAMP`.
|
||||
pub const MIN_TIMESTAMP: i64 = 500_000_000;
|
||||
|
||||
/// The maximum LockTime::Time, as a timestamp in seconds.
|
||||
///
|
||||
/// Users should not construct lock times greater than `MAX_TIMESTAMP`.
|
||||
/// LockTime is u32 in the spec, so times are limited to u32::MAX.
|
||||
pub const MAX_TIMESTAMP: i64 = u32::MAX as i64;
|
||||
|
||||
/// Returns the minimum LockTime::Time, as a LockTime.
|
||||
///
|
||||
/// Users should not construct lock times less than `min_lock_timestamp`.
|
||||
//
|
||||
// When `Utc.timestamp` stabilises as a const function, we can make this a
|
||||
// const function.
|
||||
pub fn min_lock_time() -> LockTime {
|
||||
LockTime::Time(Utc.timestamp(Self::MIN_TIMESTAMP, 0))
|
||||
}
|
||||
|
||||
/// Returns the maximum LockTime::Time, as a LockTime.
|
||||
///
|
||||
/// Users should not construct lock times greater than `max_lock_timestamp`.
|
||||
//
|
||||
// When `Utc.timestamp` stabilises as a const function, we can make this a
|
||||
// const function.
|
||||
pub fn max_lock_time() -> LockTime {
|
||||
LockTime::Time(Utc.timestamp(Self::MAX_TIMESTAMP, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashSerialize for LockTime {
|
||||
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.
|
||||
use LockTime::*;
|
||||
match self {
|
||||
Height(BlockHeight(n)) => writer.write_u32::<LittleEndian>(*n)?,
|
||||
Time(t) => writer.write_u32::<LittleEndian>(t.timestamp() as u32)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashDeserialize for LockTime {
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
let n = reader.read_u32::<LittleEndian>()?;
|
||||
if n <= BlockHeight::MAX.0 {
|
||||
Ok(LockTime::Height(BlockHeight(n)))
|
||||
} else {
|
||||
Ok(LockTime::Time(Utc.timestamp(n as i64, 0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Arbitrary for LockTime {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||
prop_oneof![
|
||||
(BlockHeight::MIN.0..=BlockHeight::MAX.0)
|
||||
.prop_map(|n| LockTime::Height(BlockHeight(n))),
|
||||
(LockTime::MIN_TIMESTAMP..=LockTime::MAX_TIMESTAMP)
|
||||
.prop_map(|n| { LockTime::Time(Utc.timestamp(n as i64, 0)) })
|
||||
]
|
||||
.boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
/// A sequence of message authentication tags ...
|
||||
///
|
||||
/// binding h_sig to each a_sk of the JoinSplit description, computed as
|
||||
|
|
@ -223,21 +127,10 @@ mod proptests {
|
|||
|
||||
use proptest::prelude::*;
|
||||
|
||||
use super::{LockTime, Script};
|
||||
use super::*;
|
||||
use crate::serialization::{ZcashDeserialize, ZcashSerialize};
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn locktime_roundtrip(locktime in any::<LockTime>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
locktime.zcash_serialize(&mut bytes)?;
|
||||
|
||||
bytes.set_position(0);
|
||||
let other_locktime = LockTime::zcash_deserialize(&mut bytes)?;
|
||||
|
||||
prop_assert_eq![locktime, other_locktime];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn script_roundtrip(script in any::<Script>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
|
|
|
|||
Loading…
Reference in New Issue