Skip to content

Commit

Permalink
add(test): Add serialized NU5 blocks to test vectors (#9098)
Browse files Browse the repository at this point in the history
* Add serialized Mainnet blocks for tests

* Add Sapling anchors

* Add Mainnet Orchard anchors

* Remove wrong Testnet NU5 blocks

* Add Testnet blocks with V5 txs to test vectors

* Move the Sapling treestate

* Add Sapling & Orchard anchors

* Remove unneeded test for fake V5 txs

We don't need this test anymore since we have real V5 txs now.

* Add `has_transparent_inputs` to `Transaction`

* Fix `v5_with_sapling_spends` test

* Fix `binding_signatures` test

* Refactor block test vectors

* Use real V5 txs instead of fake ones

* Fix `v5_transaction_is_rejected_before_nu5` test

* Fix `v5_tx_is_accepted_after_nu5_activation` test

* Fix `v5_tx_with_no_outputs_fails_validation` test

* Move `v5_tx_with_no_outputs_fails_validation` test

* Fix `v5_tx_with_no_inputs_fails_verification` test

* Fix `v5_tx_with_orchard_actions_has_inputs..` test

* Fix `v5_coinbase_tx_without_spends_flag_passes`

* Simplify `orchard` imports

* Fix `v5_tx_with_orchard_actions_has_flags` test

* Fix `v5_coinbase_tx_with_enable_spends_fails`

* Fix `v5_tx_with_duplicate_orchard_action` test

* Fix `coinbase_outputs_are_decryptable_for_v5`

* Fix `shielded_outputs_are_not_decryptable_for_v5`

* Use `Network::iter` instead of Mainnet

* Rename basic V5 tx test

* Apply suggestions from code review

Co-authored-by: Arya <[email protected]>

* Return an `Ok` in tx is not coinbase

* formatting

* Update zebra-consensus/src/transaction/check.rs

Co-authored-by: Arya <[email protected]>

---------

Co-authored-by: Arya <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 15, 2025
1 parent 410cac0 commit 82c23f3
Show file tree
Hide file tree
Showing 18 changed files with 705 additions and 714 deletions.
132 changes: 61 additions & 71 deletions zebra-chain/src/block/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ use crate::{
block::{
serialize::MAX_BLOCK_BYTES, Block, BlockTimeError, Commitment::*, Hash, Header, Height,
},
parameters::{
Network::{self, *},
NetworkUpgrade::*,
},
parameters::{Network, NetworkUpgrade::*},
sapling,
serialization::{
sha256d, SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize,
},
Expand Down Expand Up @@ -191,88 +189,80 @@ fn block_test_vectors_unique() {
);
}

/// Checks that:
///
/// - the block test vector indexes match the heights in the block data;
/// - each post-Sapling block has a corresponding final Sapling root;
/// - each post-Orchard block has a corresponding final Orchard root.
#[test]
fn block_test_vectors_height_mainnet() {
let _init_guard = zebra_test::init();

block_test_vectors_height(Mainnet);
}

#[test]
fn block_test_vectors_height_testnet() {
fn block_test_vectors() {
let _init_guard = zebra_test::init();

block_test_vectors_height(Network::new_default_testnet());
}
for net in Network::iter() {
let sapling_anchors = net.sapling_anchors();
let orchard_anchors = net.orchard_anchors();

/// Test that the block test vector indexes match the heights in the block data,
/// and that each post-sapling block has a corresponding final sapling root.
fn block_test_vectors_height(network: Network) {
let (block_iter, sapling_roots) = network.block_sapling_roots_iter();

for (&height, block) in block_iter {
let block = block
.zcash_deserialize_into::<Block>()
.expect("block is structurally valid");
assert_eq!(
block.coinbase_height().expect("block height is valid").0,
height,
"deserialized height must match BTreeMap key height"
);
for (&height, block) in net.block_iter() {
let block = block
.zcash_deserialize_into::<Block>()
.expect("block is structurally valid");
assert_eq!(
block.coinbase_height().expect("block height is valid").0,
height,
"deserialized height must match BTreeMap key height"
);

if height
>= Sapling
.activation_height(&network)
.expect("sapling activation height is set")
.0
{
assert!(
sapling_roots.contains_key(&height),
"post-sapling block test vectors must have matching sapling root test vectors: missing {network} {height}"
if height
>= Sapling
.activation_height(&net)
.expect("activation height")
.0
{
assert!(
sapling_anchors.contains_key(&height),
"post-sapling block test vectors must have matching sapling root test vectors: \
missing {net} {height}"
);
}

if height >= Nu5.activation_height(&net).expect("activation height").0 {
assert!(
orchard_anchors.contains_key(&height),
"post-nu5 block test vectors must have matching orchard root test vectors: \
missing {net} {height}"
);
}
}
}
}

#[test]
fn block_commitment_mainnet() {
let _init_guard = zebra_test::init();

block_commitment(Mainnet);
}

#[test]
fn block_commitment_testnet() {
let _init_guard = zebra_test::init();

block_commitment(Network::new_default_testnet());
}

/// Check that the block commitment field parses without errors.
/// Checks that the block commitment field parses without errors.
/// For sapling and blossom blocks, also check the final sapling root value.
///
/// TODO: add chain history test vectors?
fn block_commitment(network: Network) {
let (block_iter, sapling_roots) = network.block_sapling_roots_iter();

for (height, block) in block_iter {
let block = block
.zcash_deserialize_into::<Block>()
.expect("block is structurally valid");
#[test]
fn block_commitment() {
let _init_guard = zebra_test::init();

let commitment = block.commitment(&network).unwrap_or_else(|_| {
panic!("unexpected structurally invalid block commitment at {network} {height}")
});
for net in Network::iter() {
let sapling_anchors = net.sapling_anchors();

if let FinalSaplingRoot(final_sapling_root) = commitment {
let expected_final_sapling_root = *sapling_roots
.get(height)
.expect("unexpected missing final sapling root test vector");
assert_eq!(
final_sapling_root,
crate::sapling::tree::Root::try_from(*expected_final_sapling_root).unwrap(),
"unexpected invalid final sapling root commitment at {network} {height}"
);
for (height, block) in net.block_iter() {
if let FinalSaplingRoot(anchor) = block
.zcash_deserialize_into::<Block>()
.expect("block is structurally valid")
.commitment(&net)
.expect("unexpected structurally invalid block commitment at {net} {height}")
{
let expected_anchor = *sapling_anchors
.get(height)
.expect("unexpected missing final sapling root test vector");
assert_eq!(
anchor,
sapling::tree::Root::try_from(*expected_anchor).unwrap(),
"unexpected invalid final sapling root commitment at {net} {height}"
);
}
}
}
}
Expand Down
27 changes: 16 additions & 11 deletions zebra-chain/src/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ use zebra_test::vectors::{
BLOCK_MAINNET_1046400_BYTES, BLOCK_MAINNET_653599_BYTES, BLOCK_MAINNET_982681_BYTES,
BLOCK_TESTNET_1116000_BYTES, BLOCK_TESTNET_583999_BYTES, BLOCK_TESTNET_925483_BYTES,
CONTINUOUS_MAINNET_BLOCKS, CONTINUOUS_TESTNET_BLOCKS, MAINNET_BLOCKS,
MAINNET_FINAL_SAPLING_ROOTS, MAINNET_FINAL_SPROUT_ROOTS,
MAINNET_FINAL_ORCHARD_ROOTS, MAINNET_FINAL_SAPLING_ROOTS, MAINNET_FINAL_SPROUT_ROOTS,
SAPLING_FINAL_ROOT_MAINNET_1046400_BYTES, SAPLING_FINAL_ROOT_TESTNET_1116000_BYTES,
TESTNET_BLOCKS, TESTNET_FINAL_SAPLING_ROOTS, TESTNET_FINAL_SPROUT_ROOTS,
TESTNET_BLOCKS, TESTNET_FINAL_ORCHARD_ROOTS, TESTNET_FINAL_SAPLING_ROOTS,
TESTNET_FINAL_SPROUT_ROOTS,
};

/// Network methods for fetching blockchain vectors.
Expand Down Expand Up @@ -118,17 +119,21 @@ impl Network {
}
}

/// Returns iterator over blocks and sapling roots.
pub fn block_sapling_roots_iter(
&self,
) -> (
std::collections::btree_map::Iter<'_, u32, &[u8]>,
std::collections::BTreeMap<u32, &[u8; 32]>,
) {
/// Returns a [`BTreeMap`] of heights and Sapling anchors for this network.
pub fn sapling_anchors(&self) -> std::collections::BTreeMap<u32, &[u8; 32]> {
if self.is_mainnet() {
MAINNET_FINAL_SAPLING_ROOTS.clone()
} else {
TESTNET_FINAL_SAPLING_ROOTS.clone()
}
}

/// Returns a [`BTreeMap`] of heights and Orchard anchors for this network.
pub fn orchard_anchors(&self) -> std::collections::BTreeMap<u32, &[u8; 32]> {
if self.is_mainnet() {
(MAINNET_BLOCKS.iter(), MAINNET_FINAL_SAPLING_ROOTS.clone())
MAINNET_FINAL_ORCHARD_ROOTS.clone()
} else {
(TESTNET_BLOCKS.iter(), TESTNET_FINAL_SAPLING_ROOTS.clone())
TESTNET_FINAL_ORCHARD_ROOTS.clone()
}
}

Expand Down
7 changes: 6 additions & 1 deletion zebra-chain/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,14 @@ impl Transaction {

// other properties

/// Does this transaction have transparent inputs?
pub fn has_transparent_inputs(&self) -> bool {
!self.inputs().is_empty()
}

/// Does this transaction have transparent or shielded inputs?
pub fn has_transparent_or_shielded_inputs(&self) -> bool {
!self.inputs().is_empty() || self.has_shielded_inputs()
self.has_transparent_inputs() || self.has_shielded_inputs()
}

/// Does this transaction have shielded inputs?
Expand Down
17 changes: 9 additions & 8 deletions zebra-chain/src/transaction/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,16 +992,17 @@ pub fn test_transactions(
transactions_from_blocks(blocks)
}

/// Generate an iterator over fake V5 transactions.
///
/// These transactions are converted from non-V5 transactions that exist in the provided network
/// blocks.
pub fn fake_v5_transactions_for_network<'b>(
network: &'b Network,
/// Returns an iterator over V5 transactions extracted from the given blocks.
pub fn v5_transactions<'b>(
blocks: impl DoubleEndedIterator<Item = (&'b u32, &'b &'static [u8])> + 'b,
) -> impl DoubleEndedIterator<Item = Transaction> + 'b {
transactions_from_blocks(blocks)
.map(move |(height, transaction)| transaction_to_fake_v5(&transaction, network, height))
transactions_from_blocks(blocks).filter_map(|(_, tx)| match *tx {
Transaction::V1 { .. }
| Transaction::V2 { .. }
| Transaction::V3 { .. }
| Transaction::V4 { .. } => None,
ref tx @ Transaction::V5 { .. } => Some(tx.clone()),
})
}

/// Generate an iterator over ([`block::Height`], [`Arc<Transaction>`]).
Expand Down
Loading

0 comments on commit 82c23f3

Please sign in to comment.