Skip to content
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

Parse ConsensusBranchId into NetworkUpgrade for transaction v5 #2075

Merged
merged 13 commits into from
Apr 29, 2021
9 changes: 8 additions & 1 deletion zebra-chain/src/parameters/network_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use chrono::{DateTime, Duration, Utc};
///
/// Network upgrades can change the Zcash network protocol or consensus rules in
/// incompatible ways.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum NetworkUpgrade {
/// The Zcash protocol for a Genesis block.
///
Expand Down Expand Up @@ -301,6 +301,13 @@ impl NetworkUpgrade {
Network::Testnet => height >= TESTNET_MAX_TIME_START_HEIGHT,
}
}
/// Returns the NetworkUpgrade given an u32 as ConsensusBranchId
pub fn from_branch_id(branch_id: u32) -> Option<NetworkUpgrade> {
CONSENSUS_BRANCH_IDS
.iter()
.find(|id| id.1 == ConsensusBranchId(branch_id))
.map(|nu| nu.0)
}
}

impl ConsensusBranchId {
Expand Down
4 changes: 4 additions & 0 deletions zebra-chain/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ pub enum Transaction {
},
/// A `version = 5` transaction, which supports `Sapling` and `Orchard`.
V5 {
/// The Network Upgrade for this transaction.
///
/// Derived from the ConsensusBranchId field.
network_upgrade: NetworkUpgrade,
/// The earliest time or block height that this transaction can be added to the
/// chain.
lock_time: LockTime,
Expand Down
24 changes: 23 additions & 1 deletion zebra-chain/src/transaction/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,24 @@ impl Transaction {
/// Generate a proptest strategy for V5 Transactions
pub fn v5_strategy(ledger_state: LedgerState) -> BoxedStrategy<Self> {
(
Self::branch_id_strategy(),
any::<LockTime>(),
any::<block::Height>(),
transparent::Input::vec_strategy(ledger_state, 10),
vec(any::<transparent::Output>(), 0..10),
option::of(any::<sapling::ShieldedData<sapling::SharedAnchor>>()),
)
.prop_map(
|(lock_time, expiry_height, inputs, outputs, sapling_shielded_data)| {
|(
network_upgrade,
lock_time,
expiry_height,
inputs,
outputs,
sapling_shielded_data,
)| {
Transaction::V5 {
network_upgrade,
lock_time,
expiry_height,
inputs,
Expand All @@ -123,6 +132,19 @@ impl Transaction {
.boxed()
}

// A custom strategy to use only some of the NetworkUpgrade values
fn branch_id_strategy() -> BoxedStrategy<NetworkUpgrade> {
prop_oneof![
Just(NetworkUpgrade::Overwinter),
Just(NetworkUpgrade::Sapling),
Just(NetworkUpgrade::Blossom),
Just(NetworkUpgrade::Heartwood),
Just(NetworkUpgrade::Canopy),
Just(NetworkUpgrade::Nu5),
]
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
.boxed()
}

/// Proptest Strategy for creating a Vector of transactions where the first
/// transaction is always the only coinbase transaction
pub fn vec_strategy(
Expand Down
16 changes: 16 additions & 0 deletions zebra-chain/src/transaction/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ impl ZcashSerialize for Transaction {
}

Transaction::V5 {
network_upgrade,
lock_time,
expiry_height,
inputs,
Expand All @@ -356,6 +357,13 @@ impl ZcashSerialize for Transaction {
writer.write_u32::<LittleEndian>(5 | (1 << 31))?;
writer.write_u32::<LittleEndian>(TX_V5_VERSION_GROUP_ID)?;

// header: Write the nConsensusBranchId
writer.write_u32::<LittleEndian>(u32::from(
network_upgrade
.branch_id()
.expect("valid transactions must have a network upgrade with a branch id"),
))?;

// transaction validity time and height limits
lock_time.zcash_serialize(&mut writer)?;
writer.write_u32::<LittleEndian>(expiry_height.0)?;
Expand Down Expand Up @@ -491,6 +499,13 @@ impl ZcashDeserialize for Transaction {
if id != TX_V5_VERSION_GROUP_ID {
return Err(SerializationError::Parse("expected TX_V5_VERSION_GROUP_ID"));
}
// convert the nConsensusBranchId to a NetworkUpgrade
let network_upgrade = NetworkUpgrade::from_branch_id(
reader.read_u32::<LittleEndian>()?,
)
.ok_or(SerializationError::Parse(
"expected a valid network upgrade from the consensus branch id",
))?;

// transaction validity time and height limits
let lock_time = LockTime::zcash_deserialize(&mut reader)?;
Expand All @@ -514,6 +529,7 @@ impl ZcashDeserialize for Transaction {
}

Ok(Transaction::V5 {
network_upgrade,
lock_time,
expiry_height,
inputs,
Expand Down
9 changes: 9 additions & 0 deletions zebra-chain/src/transaction/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::super::*;

use crate::{
block::{Block, MAX_BLOCK_BYTES},
parameters::NetworkUpgrade::Nu5,
sapling::{PerSpendAnchor, SharedAnchor},
serialization::{ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize},
};
Expand Down Expand Up @@ -105,6 +106,7 @@ fn empty_v5_round_trip() {
zebra_test::init();

let tx = Transaction::V5 {
network_upgrade: NETWORK_UPGRADE,
lock_time: LockTime::min_lock_time(),
expiry_height: block::Height(0),
inputs: Vec::new(),
Expand Down Expand Up @@ -267,6 +269,9 @@ fn fake_v5_round_trip() {

// Utility functions

/// The network upgrade for any fake transactions we will create.
const NETWORK_UPGRADE: NetworkUpgrade = Nu5;

/// Convert `trans` into a fake v5 transaction,
/// converting sapling shielded data from v4 to v5 if possible.
fn transaction_to_fake_v5(trans: &Transaction) -> Transaction {
Expand All @@ -278,6 +283,7 @@ fn transaction_to_fake_v5(trans: &Transaction) -> Transaction {
outputs,
lock_time,
} => V5 {
network_upgrade: NETWORK_UPGRADE,
inputs: inputs.to_vec(),
outputs: outputs.to_vec(),
lock_time: *lock_time,
Expand All @@ -290,6 +296,7 @@ fn transaction_to_fake_v5(trans: &Transaction) -> Transaction {
lock_time,
..
} => V5 {
network_upgrade: NETWORK_UPGRADE,
inputs: inputs.to_vec(),
outputs: outputs.to_vec(),
lock_time: *lock_time,
Expand All @@ -303,6 +310,7 @@ fn transaction_to_fake_v5(trans: &Transaction) -> Transaction {
expiry_height,
..
} => V5 {
network_upgrade: NETWORK_UPGRADE,
inputs: inputs.to_vec(),
outputs: outputs.to_vec(),
lock_time: *lock_time,
Expand All @@ -317,6 +325,7 @@ fn transaction_to_fake_v5(trans: &Transaction) -> Transaction {
sapling_shielded_data,
..
} => V5 {
network_upgrade: NETWORK_UPGRADE,
inputs: inputs.to_vec(),
outputs: outputs.to_vec(),
lock_time: *lock_time,
Expand Down