Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2b17f2b
ci: fix issues found in upstream Zebra PR
dmidem May 29, 2026
ba39b0a
Update Orchard ZSA workflow block tests to use ExpectedTranscriptErro…
dmidem Jun 1, 2026
1f21ee2
Revert "ci: fix issues found in upstream Zebra PR"
dmidem Jun 4, 2026
de3f2c0
Merge branch 'zsa1' into expected-transcript-error
dmidem Jun 4, 2026
a9a44df
split run attempts
PaulLaux Jun 4, 2026
df37409
Merge branch 'zsa1' into expected-transcript-error
dmidem Jun 4, 2026
06e16f4
Use ExpectedTranscriptError::Exact instead of ExpectedTranscriptError…
dmidem Jun 9, 2026
f3a224b
Add a comment to has_finalized_asset_error to explain why Debug outpu…
dmidem Jun 9, 2026
00ca0be
Fix error in check_burns_and_issuance test
dmidem Jun 9, 2026
c65c34e
ci: try to run non-network tests only
dmidem Jun 10, 2026
1353336
ci: fix an error in the previous commit
dmidem Jun 10, 2026
6f68d6e
ci: run zebra-network tests serially
dmidem Jun 10, 2026
b18ad52
ci: run network and acceptance tests separately with cargo-nextest
dmidem Jun 10, 2026
654f7c4
ci: increase the number of threads for zebra-network tests to 4
dmidem Jun 10, 2026
81cdac5
ci: remove thread limit for network tests
dmidem Jun 11, 2026
520f757
ci: try to increase the number of threads for acceptance tests
dmidem Jun 11, 2026
b3d1d3a
removed debug string (#143)
PaulLaux Jun 12, 2026
06f101b
Merge branch 'zsa1' into expected-transcript-error-v2
dmidem Jun 12, 2026
d17e7f1
Remove explanatory review comment in orchard_zsa/tests.rs
dmidem Jun 15, 2026
a958ed9
Merge branch 'zsa1' into expected-transcript-error-v2
dmidem Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 52 additions & 14 deletions zebra-consensus/src/orchard_zsa/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use std::{
collections::{hash_map, HashMap},
error::Error,
sync::Arc,
};

Expand All @@ -17,14 +18,15 @@ use tower::ServiceExt;
use orchard::{
issuance::{
auth::{IssueValidatingKey, ZSASchnorr},
{AssetRecord, IssueAction},
AssetRecord, IssueAction,
},
note::{AssetBase, AssetId},
value::NoteValue,
};

use zebra_chain::{
block::{genesis::regtest_genesis_block, Block, Hash},
orchard_zsa::AssetStateError,
parameters::{testnet::ConfiguredActivationHeights, Network},
serialization::ZcashDeserialize,
};
Expand All @@ -36,7 +38,7 @@ use zebra_state::{ReadRequest, ReadResponse, ReadStateService};

use zebra_test::{
transcript::{ExpectedTranscriptError, Transcript},
vectors::{OrchardWorkflowBlock, ORCHARD_ZSA_WORKFLOW_BLOCKS},
vectors::{OrchardWorkflowBlock, OrchardWorkflowBlockResult, ORCHARD_ZSA_WORKFLOW_BLOCKS},
};

use crate::{block::Request, Config};
Expand All @@ -56,6 +58,39 @@ enum AssetRecordsError {
ModifyFinalized,
}

type BoxError = Box<dyn Error + Send + Sync + 'static>;

fn has_finalized_asset_error(error: &(dyn Error + 'static)) -> bool {
let mut error = Some(error);

while let Some(err) = error {
if matches!(
err.downcast_ref::<AssetStateError>(),
Some(AssetStateError::Issue(
orchard::issuance::Error::IssueActionPreviouslyFinalizedAssetBase
))
) {
return true;
}

error = err.source();
}

false
}

fn expect_finalized_asset_error(error: Option<BoxError>) -> Result<(), BoxError> {
let Some(error) = error else {
return Err(eyre!("expected finalized asset error").into());
};

if has_finalized_asset_error(&*error) {
Ok(())
} else {
Err(error)
}
}

/// Processes orchard burns, decreasing asset supply.
fn process_burns<'a, I: IntoIterator<Item = &'a BurnItem>>(
asset_records: &mut AssetRecords,
Expand Down Expand Up @@ -176,25 +211,28 @@ fn create_transcript_data<'a, I: IntoIterator<Item = &'a OrchardWorkflowBlock>>(
|OrchardWorkflowBlock {
height: _,
bytes,
is_valid,
expected_result,
}| {
(
Arc::new(Block::zcash_deserialize(&bytes[..]).expect("block should deserialize")),
*is_valid,
)
let block =
Arc::new(Block::zcash_deserialize(&bytes[..]).expect("block should deserialize"));

let expected_result = match expected_result {
OrchardWorkflowBlockResult::Valid => Ok(()),
OrchardWorkflowBlockResult::IssueFinalizedAssetError => {
Err(ExpectedTranscriptError::exact(expect_finalized_asset_error))
}
};

(block, expected_result)
},
);

std::iter::once((regtest_genesis_block(), true))
std::iter::once((regtest_genesis_block(), Ok(())))
.chain(workflow_blocks)
.map(|(block, is_valid)| {
.map(|(block, expected_result)| {
(
Request::Commit(block.clone()),
if is_valid {
Ok(block.hash())
} else {
Err(ExpectedTranscriptError::Any)
},
expected_result.map(|_| block.hash()),
)
})
}
Expand Down
8 changes: 5 additions & 3 deletions zebra-state/src/service/check/tests/issuance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use zebra_chain::{
serialization::ZcashDeserialize,
};

use zebra_test::vectors::{OrchardWorkflowBlock, ORCHARD_ZSA_WORKFLOW_BLOCKS};
use zebra_test::vectors::{
OrchardWorkflowBlock, OrchardWorkflowBlockResult, ORCHARD_ZSA_WORKFLOW_BLOCKS,
};

use crate::{
check::Chain,
Expand Down Expand Up @@ -59,7 +61,7 @@ fn check_burns_and_issuance() {
for OrchardWorkflowBlock {
height,
bytes,
is_valid,
expected_result,
} in ORCHARD_ZSA_WORKFLOW_BLOCKS.iter()
{
let block =
Expand All @@ -83,7 +85,7 @@ fn check_burns_and_issuance() {
let commit_result =
validate_and_commit_non_finalized(&finalized_state.db, &mut non_finalized_state, block);

if !is_valid {
if !matches!(expected_result, OrchardWorkflowBlockResult::Valid) {
assert!(
issued_asset_changes_result.is_err() || commit_result.is_err(),
"invalid workflow block at height {height} should fail issued-asset validation or commit"
Expand Down
21 changes: 14 additions & 7 deletions zebra-test/src/vectors/orchard_zsa_workflow_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
use hex::FromHex;
use lazy_static::lazy_static;

/// Expected consensus result for a block.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrchardWorkflowBlockResult {
Valid,
IssueFinalizedAssetError,
}

/// Represents a serialized block and its validity status.
pub struct OrchardWorkflowBlock {
/// Block height.
pub height: u32,
/// Serialized byte data of the block.
pub bytes: &'static [u8],
/// Indicates whether the block is valid.
pub is_valid: bool,
/// Expected result of transcript validation for this block.
pub expected_result: OrchardWorkflowBlockResult,
}

fn decode_bytes(hex: &str) -> Vec<u8> {
Expand Down Expand Up @@ -41,35 +48,35 @@ lazy_static! {
OrchardWorkflowBlock {
height: 1,
bytes: ORCHARD_ZSA_WORKFLOW_BLOCK_1_BYTES.as_slice(),
is_valid: true
expected_result: OrchardWorkflowBlockResult::Valid
},

// Transfer
OrchardWorkflowBlock {
height: 2,
bytes: ORCHARD_ZSA_WORKFLOW_BLOCK_2_BYTES.as_slice(),
is_valid: true
expected_result: OrchardWorkflowBlockResult::Valid
},

// Burn: 7, Burn: 2
OrchardWorkflowBlock {
height: 3,
bytes: ORCHARD_ZSA_WORKFLOW_BLOCK_3_BYTES.as_slice(),
is_valid: true
expected_result: OrchardWorkflowBlockResult::Valid
},

// Issue: finalize
OrchardWorkflowBlock {
height: 4,
bytes: ORCHARD_ZSA_WORKFLOW_BLOCK_4_BYTES.as_slice(),
is_valid: true
expected_result: OrchardWorkflowBlockResult::Valid
},

// Try to issue: 2000
OrchardWorkflowBlock {
height: 5,
bytes: ORCHARD_ZSA_WORKFLOW_BLOCK_5_BYTES.as_slice(),
is_valid: false
expected_result: OrchardWorkflowBlockResult::IssueFinalizedAssetError
},
];
}
Loading