diff --git a/zebra-chain/src/block/arbitrary.rs b/zebra-chain/src/block/arbitrary.rs index 5a39afa2e..02cfca435 100644 --- a/zebra-chain/src/block/arbitrary.rs +++ b/zebra-chain/src/block/arbitrary.rs @@ -260,8 +260,9 @@ impl Default for LedgerState { let default_override = LedgerStateOverride::default(); let most_recent_nu = NetworkUpgrade::current(&default_network, Height::MAX); - let most_recent_activation_height = - most_recent_nu.activation_height(&default_network).unwrap(); + let most_recent_activation_height = most_recent_nu + .activation_height(&default_network) + .expect("should have an activation height in default networks"); LedgerState { height: most_recent_activation_height, @@ -467,8 +468,10 @@ impl Block { let current_height = block.coinbase_height().unwrap(); let heartwood_height = NetworkUpgrade::Heartwood .activation_height(¤t.network) - .unwrap(); - let nu5_height = NetworkUpgrade::Nu5.activation_height(¤t.network); + .expect("should have an activation height in default networks"); + let nu5_height = NetworkUpgrade::Nu5 + .activation_height(¤t.network) + .expect("should have an activation height in default networks"); match current_height.cmp(&heartwood_height) { std::cmp::Ordering::Less => { @@ -491,7 +494,7 @@ impl Block { Some(tree) => tree.hash().unwrap_or_else(|| [0u8; 32].into()), None => [0u8; 32].into(), }; - if nu5_height.is_some() && current_height >= nu5_height.unwrap() { + if current_height >= nu5_height { // From zebra-state/src/service/check.rs let auth_data_root = block.auth_data_root(); let hash_block_commitments = @@ -696,7 +699,11 @@ impl Arbitrary for Commitment { fn arbitrary_with(_args: ()) -> Self::Strategy { (any::<[u8; 32]>(), any::(), any::()) .prop_map(|(commitment_bytes, network, block_height)| { - if block_height == Heartwood.activation_height(&network).unwrap() { + if block_height + == Heartwood + .activation_height(&network) + .expect("should have an activation height in default networks") + { Commitment::ChainHistoryActivationReserved } else { Commitment::from_bytes(commitment_bytes, &network, block_height) diff --git a/zebra-chain/src/block/tests/vectors.rs b/zebra-chain/src/block/tests/vectors.rs index 5ff19ca10..7f56b263a 100644 --- a/zebra-chain/src/block/tests/vectors.rs +++ b/zebra-chain/src/block/tests/vectors.rs @@ -223,7 +223,7 @@ fn block_test_vectors_height(network: Network) { if height >= Sapling .activation_height(&network) - .expect("sapling activation height is set") + .expect("sapling activation height is set on default network") .0 { assert!( diff --git a/zebra-chain/src/chain_tip/tests/prop.rs b/zebra-chain/src/chain_tip/tests/prop.rs index 3b5fff99f..612bad1cd 100644 --- a/zebra-chain/src/chain_tip/tests/prop.rs +++ b/zebra-chain/src/chain_tip/tests/prop.rs @@ -25,7 +25,7 @@ proptest! { let (chain_tip, mock_chain_tip_sender) = MockChainTip::new(); let blossom_activation_height = NetworkUpgrade::Blossom .activation_height(&network) - .expect("Blossom activation height is missing"); + .expect("Blossom activation height is missing on default network"); block_heights.sort(); let current_height = block_heights[0]; diff --git a/zebra-chain/src/history_tree.rs b/zebra-chain/src/history_tree.rs index d3a45f15f..59dcb13a6 100644 --- a/zebra-chain/src/history_tree.rs +++ b/zebra-chain/src/history_tree.rs @@ -428,9 +428,11 @@ impl HistoryTree { sapling_root: &sapling::tree::Root, orchard_root: &orchard::tree::Root, ) -> Result { - let heartwood_height = NetworkUpgrade::Heartwood - .activation_height(network) - .expect("Heartwood height is known"); + let Some(heartwood_height) = NetworkUpgrade::Heartwood.activation_height(network) else { + // Return early if there is no Heartwood activation height. + return Ok(HistoryTree(None)); + }; + match block .coinbase_height() .expect("must have height") diff --git a/zebra-chain/src/history_tree/tests/vectors.rs b/zebra-chain/src/history_tree/tests/vectors.rs index e65da99b6..a02244109 100644 --- a/zebra-chain/src/history_tree/tests/vectors.rs +++ b/zebra-chain/src/history_tree/tests/vectors.rs @@ -35,7 +35,10 @@ fn push_and_prune_for_network_upgrade( ) -> Result<()> { let (blocks, sapling_roots) = network.block_sapling_roots_map(); - let height = network_upgrade.activation_height(&network).unwrap().0; + let height = network_upgrade + .activation_height(&network) + .expect("network upgrade activation height is missing on default network") + .0; // Load first block (activation block of the given network upgrade) let first_block = Arc::new( @@ -118,7 +121,10 @@ fn upgrade() -> Result<()> { fn upgrade_for_network_upgrade(network: Network, network_upgrade: NetworkUpgrade) -> Result<()> { let (blocks, sapling_roots) = network.block_sapling_roots_map(); - let height = network_upgrade.activation_height(&network).unwrap().0; + let height = network_upgrade + .activation_height(&network) + .expect("network upgrade activation height is missing on default network") + .0; // Load previous block (the block before the activation block of the given network upgrade) let block_prev = Arc::new( diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 47fd41e74..6ef607663 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -267,6 +267,12 @@ impl Network { // // See the `ZIP_212_GRACE_PERIOD_DURATION` documentation for more information. + // TODO: + // - Support constructing pre-Canopy coinbase tx and block templates and return `Height::MAX` instead of panicking + // when Canopy activation height is `None` (#8434) + // - Add semantic block validation during the ZIP-212 grace period and update this method to return the lesser of + // `canopy_activation + ZIP_212_GRACE_PERIOD_DURATION` or the NU5 activation height. (#8430) + let canopy_activation = NetworkUpgrade::Canopy .activation_height(self) .expect("Canopy activation height must be present for both networks"); @@ -296,10 +302,8 @@ impl Network { } /// Returns the Sapling activation height for this network. - pub fn sapling_activation_height(&self) -> Height { - super::NetworkUpgrade::Sapling - .activation_height(self) - .expect("Sapling activation height needs to be set") + pub fn sapling_activation_height(&self) -> Option { + super::NetworkUpgrade::Sapling.activation_height(self) } } diff --git a/zebra-chain/src/parameters/network/tests/prop.rs b/zebra-chain/src/parameters/network/tests/prop.rs index c2b1e31e0..1aad87547 100644 --- a/zebra-chain/src/parameters/network/tests/prop.rs +++ b/zebra-chain/src/parameters/network/tests/prop.rs @@ -19,7 +19,7 @@ proptest! { let canopy_activation = NetworkUpgrade::Canopy .activation_height(&network) - .expect("Canopy activation height is set"); + .expect("Canopy activation height is set on default networks"); let grace_period_end_height = (canopy_activation + ZIP_212_GRACE_PERIOD_DURATION) .expect("ZIP-212 grace period ends in a valid block height"); diff --git a/zebra-chain/src/parameters/network/tests/vectors.rs b/zebra-chain/src/parameters/network/tests/vectors.rs index e54fa4d7c..dd1e51b7d 100644 --- a/zebra-chain/src/parameters/network/tests/vectors.rs +++ b/zebra-chain/src/parameters/network/tests/vectors.rs @@ -112,7 +112,7 @@ fn activates_network_upgrades_correctly() { let genesis_activation_height = NetworkUpgrade::Genesis .activation_height(&network) - .expect("must return an activation height"); + .expect("must always return an activation height for Genesis network upgrade"); assert_eq!( genesis_activation_height, @@ -123,7 +123,7 @@ fn activates_network_upgrades_correctly() { for nu in NETWORK_UPGRADES_IN_ORDER.into_iter().skip(1) { let activation_height = nu .activation_height(&network) - .expect("must return an activation height"); + .expect("must return an activation height for all network upgrades when there's an NU5 activation height"); assert_eq!( activation_height, Height(expected_activation_height), diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index de546e3b4..4297eb764 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -402,14 +402,10 @@ impl NetworkUpgrade { ), ] .into_iter() - .map(move |(upgrade, spacing_seconds)| { - let activation_height = upgrade - .activation_height(network) - .expect("missing activation height for target spacing change"); - + .filter_map(move |(upgrade, spacing_seconds)| { + let activation_height = upgrade.activation_height(network)?; let target_spacing = Duration::seconds(spacing_seconds); - - (activation_height, target_spacing) + Some((activation_height, target_spacing)) }) } diff --git a/zebra-chain/src/parameters/tests.rs b/zebra-chain/src/parameters/tests.rs index 2b0f8b4a2..3c32f05a8 100644 --- a/zebra-chain/src/parameters/tests.rs +++ b/zebra-chain/src/parameters/tests.rs @@ -127,7 +127,7 @@ fn activation_consistent(network: Network) { for &network_upgrade in network_upgrades { let height = network_upgrade .activation_height(&network) - .expect("activations must have a height"); + .expect("activations must have a height on default networks"); assert!(NetworkUpgrade::is_activation_height(&network, height)); if height > block::Height(0) { diff --git a/zebra-chain/src/primitives/zcash_history/tests/vectors.rs b/zebra-chain/src/primitives/zcash_history/tests/vectors.rs index d23cb078d..d7646a6cd 100644 --- a/zebra-chain/src/primitives/zcash_history/tests/vectors.rs +++ b/zebra-chain/src/primitives/zcash_history/tests/vectors.rs @@ -21,7 +21,10 @@ fn tree() -> Result<()> { fn tree_for_network_upgrade(network: &Network, network_upgrade: NetworkUpgrade) -> Result<()> { let (blocks, sapling_roots) = network.block_sapling_roots_map(); - let height = network_upgrade.activation_height(network).unwrap().0; + let height = network_upgrade + .activation_height(network) + .expect("must have activation height on default network") + .0; // Load Block 0 (activation block of the given network upgrade) let block0 = Arc::new( diff --git a/zebra-chain/src/sapling/tests/tree.rs b/zebra-chain/src/sapling/tests/tree.rs index 37773e01e..aa3dd1e9e 100644 --- a/zebra-chain/src/sapling/tests/tree.rs +++ b/zebra-chain/src/sapling/tests/tree.rs @@ -62,7 +62,7 @@ fn incremental_roots_with_blocks_for_network(network: Network) -> Result<()> { let height = NetworkUpgrade::Sapling .activation_height(&network) - .unwrap() + .expect("must have activation height on default network") .0; // Build empty note commitment tree diff --git a/zebra-chain/src/sprout/tests/tree.rs b/zebra-chain/src/sprout/tests/tree.rs index f04ee9af3..1cf896854 100644 --- a/zebra-chain/src/sprout/tests/tree.rs +++ b/zebra-chain/src/sprout/tests/tree.rs @@ -92,7 +92,7 @@ fn incremental_roots_with_blocks_for_network(network: Network) -> Result<()> { // Load the Genesis height. let genesis_height = NetworkUpgrade::Genesis .activation_height(&network) - .unwrap() + .expect("must have activation height on default network") .0; // Load the Genesis block. diff --git a/zebra-chain/src/transaction/tests/vectors.rs b/zebra-chain/src/transaction/tests/vectors.rs index 7115d7f36..8fb1a8ddf 100644 --- a/zebra-chain/src/transaction/tests/vectors.rs +++ b/zebra-chain/src/transaction/tests/vectors.rs @@ -352,7 +352,7 @@ fn fake_v5_round_trip_for_network(network: Network) { let overwinter_activation_height = NetworkUpgrade::Overwinter .activation_height(&network) - .expect("a valid height") + .expect("must have activation height on default network") .0; // skip blocks that are before overwinter as they will not have a valid consensus branch id @@ -500,7 +500,7 @@ fn fake_v5_librustzcash_round_trip_for_network(network: Network) { let overwinter_activation_height = NetworkUpgrade::Overwinter .activation_height(&network) - .expect("a valid height") + .expect("must have activation height on default network") .0; let nu5_activation_height = NetworkUpgrade::Nu5 diff --git a/zebra-consensus/src/block/check.rs b/zebra-consensus/src/block/check.rs index 797df65c5..054a2d983 100644 --- a/zebra-consensus/src/block/check.rs +++ b/zebra-consensus/src/block/check.rs @@ -155,7 +155,7 @@ pub fn subsidy_is_valid(block: &Block, network: &Network) -> Result<(), BlockErr let canopy_activation_height = NetworkUpgrade::Canopy .activation_height(network) - .expect("Canopy activation height is known"); + .expect("Canopy activation height is required for semantic block validation"); if height < SLOW_START_INTERVAL { unreachable!( diff --git a/zebra-consensus/src/block/subsidy/funding_streams.rs b/zebra-consensus/src/block/subsidy/funding_streams.rs index c3389782b..c46068167 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams.rs @@ -25,7 +25,9 @@ pub fn funding_stream_values( height: Height, network: &Network, ) -> Result>, Error> { - let canopy_height = Canopy.activation_height(network).unwrap(); + let canopy_height = Canopy + .activation_height(network) + .expect("requires Canopy activation height"); let mut results = HashMap::new(); if height >= canopy_height { diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index e7cf8f91b..1e0ac3a8d 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -230,7 +230,7 @@ impl ParameterSubsidy for Network { match self { Network::Mainnet => NetworkUpgrade::Canopy .activation_height(self) - .expect("canopy activation height should be available"), + .expect("Canopy activation height should be available"), // TODO: Check what zcashd does here, consider adding a field to `testnet::Parameters` to make this configurable. Network::Testnet(_params) => FIRST_HALVING_TESTNET, } diff --git a/zebra-consensus/src/transaction/check.rs b/zebra-consensus/src/transaction/check.rs index 432f3d2f6..e96168d4c 100644 --- a/zebra-consensus/src/transaction/check.rs +++ b/zebra-consensus/src/transaction/check.rs @@ -356,7 +356,6 @@ pub fn coinbase_expiry_height( ) -> Result<(), TransactionError> { let expiry_height = coinbase.expiry_height(); - // TODO: replace `if let` with `expect` after NU5 mainnet activation if let Some(nu5_activation_height) = NetworkUpgrade::Nu5.activation_height(network) { // # Consensus // diff --git a/zebra-grpc/src/tests/snapshot.rs b/zebra-grpc/src/tests/snapshot.rs index 6b81a3c70..dc19a3bec 100644 --- a/zebra-grpc/src/tests/snapshot.rs +++ b/zebra-grpc/src/tests/snapshot.rs @@ -88,7 +88,9 @@ async fn test_mocked_rpc_response_data_for_network(network: Network, random_port .expect_request_that(|req| matches!(req, ScanRequest::Info)) .await .respond(ScanResponse::Info { - min_sapling_birthday_height: network.sapling_activation_height(), + min_sapling_birthday_height: network + .sapling_activation_height() + .expect("must have Sapling activation height for default network"), }) }); } diff --git a/zebra-grpc/src/tests/vectors.rs b/zebra-grpc/src/tests/vectors.rs index b34a8ec8b..e9a956bf1 100644 --- a/zebra-grpc/src/tests/vectors.rs +++ b/zebra-grpc/src/tests/vectors.rs @@ -57,7 +57,10 @@ async fn test_mocked_getinfo_for_network( // test the response assert_eq!( get_info_response.into_inner().min_sapling_birthday_height, - network.sapling_activation_height().0, + network + .sapling_activation_height() + .expect("must have Sapling activation height for default network") + .0, "get_info response min sapling height should match network sapling activation height" ); } @@ -396,7 +399,9 @@ async fn call_get_info( .expect_request_that(|req| matches!(req, ScanRequest::Info)) .await .respond(ScanResponse::Info { - min_sapling_birthday_height: network.sapling_activation_height(), + min_sapling_birthday_height: network + .sapling_activation_height() + .expect("must have Sapling activation height for default network"), }) }); diff --git a/zebra-scan/src/service.rs b/zebra-scan/src/service.rs index 200160ab3..e8705f44a 100644 --- a/zebra-scan/src/service.rs +++ b/zebra-scan/src/service.rs @@ -95,7 +95,10 @@ impl Service for ScanService { return async move { Ok(Response::Info { - min_sapling_birthday_height: db.network().sapling_activation_height(), + min_sapling_birthday_height: db + .network() + .sapling_activation_height() + .ok_or("missing Sapling activation height")?, }) } .boxed(); diff --git a/zebra-scan/src/service/scan_task/commands.rs b/zebra-scan/src/service/scan_task/commands.rs index e718d742c..5f5ceb211 100644 --- a/zebra-scan/src/service/scan_task/commands.rs +++ b/zebra-scan/src/service/scan_task/commands.rs @@ -78,7 +78,9 @@ impl ScanTask { let mut new_keys = HashMap::new(); let mut new_result_senders = HashMap::new(); let mut new_result_receivers = Vec::new(); - let sapling_activation_height = network.sapling_activation_height(); + let sapling_activation_height = network.sapling_activation_height().ok_or(eyre!( + "must have Sapling activation height for default network" + ))?; loop { let cmd = match cmd_receiver.try_recv() { diff --git a/zebra-scan/src/service/scan_task/scan.rs b/zebra-scan/src/service/scan_task/scan.rs index 12bbb86a1..779fef5d5 100644 --- a/zebra-scan/src/service/scan_task/scan.rs +++ b/zebra-scan/src/service/scan_task/scan.rs @@ -79,7 +79,9 @@ pub async fn start( mut cmd_receiver: tokio::sync::mpsc::Receiver, ) -> Result<(), Report> { let network = storage.network(); - let sapling_activation_height = network.sapling_activation_height(); + let sapling_activation_height = network + .sapling_activation_height() + .ok_or(eyre!("missing Sapling activation height"))?; info!(?network, "starting scan task"); diff --git a/zebra-scan/src/service/scan_task/scan/scan_range.rs b/zebra-scan/src/service/scan_task/scan/scan_range.rs index b4b75cfe5..ce97e3249 100644 --- a/zebra-scan/src/service/scan_task/scan/scan_range.rs +++ b/zebra-scan/src/service/scan_task/scan/scan_range.rs @@ -6,7 +6,7 @@ use crate::{ scan::{get_min_height, scan_height_and_store_results, wait_for_height, State, CHECK_INTERVAL}, storage::Storage, }; -use color_eyre::eyre::Report; +use color_eyre::eyre::{eyre, Report}; use tokio::{ sync::{mpsc::Sender, watch}, task::JoinHandle, @@ -88,7 +88,10 @@ pub async fn scan_range( storage: Storage, subscribed_keys_receiver: watch::Receiver>>>, ) -> Result<(), Report> { - let sapling_activation_height = storage.network().sapling_activation_height(); + let sapling_activation_height = storage + .network() + .sapling_activation_height() + .ok_or(eyre!("missing Sapling activation height"))?; // Do not scan and notify if we are below sapling activation height. wait_for_height( sapling_activation_height, diff --git a/zebra-scan/src/storage/db/sapling.rs b/zebra-scan/src/storage/db/sapling.rs index b3c7b870b..4a24df106 100644 --- a/zebra-scan/src/storage/db/sapling.rs +++ b/zebra-scan/src/storage/db/sapling.rs @@ -213,7 +213,10 @@ impl Storage { sapling_key: &SaplingScanningKey, birthday_height: Option, ) { - let min_birthday_height = self.network().sapling_activation_height(); + let min_birthday_height = self + .network() + .sapling_activation_height() + .unwrap_or(Height(1)); // The birthday height must be at least the minimum height for that pool. let birthday_height = birthday_height diff --git a/zebra-scan/src/tests/vectors.rs b/zebra-scan/src/tests/vectors.rs index 9fff00c62..c5e47fcc3 100644 --- a/zebra-scan/src/tests/vectors.rs +++ b/zebra-scan/src/tests/vectors.rs @@ -170,7 +170,9 @@ fn scanning_fake_blocks_store_key_and_results() -> Result<()> { .expect("height is stored") .next() .expect("height is not maximum"), - network.sapling_activation_height() + network + .sapling_activation_height() + .expect("should have Sapling activation height on default networks") ); let nf = Nullifier([7; 32]); diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 203c1d34c..423ef50a7 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -423,9 +423,7 @@ impl StateService { let timer = CodeTimer::start(); if let Some(tip) = state.best_tip() { - let nu5_activation_height = NetworkUpgrade::Nu5 - .activation_height(network) - .expect("NU5 activation height is set"); + let nu5_activation_height = NetworkUpgrade::Nu5.activation_height(network); if let Err(error) = check::legacy_chain( nu5_activation_height, diff --git a/zebra-state/src/service/check.rs b/zebra-state/src/service/check.rs index 30144d8d3..a9b8cdf4f 100644 --- a/zebra-state/src/service/check.rs +++ b/zebra-state/src/service/check.rs @@ -306,7 +306,7 @@ fn difficulty_threshold_and_time_are_valid( /// `max_legacy_chain_blocks` should be [`MAX_LEGACY_CHAIN_BLOCKS`](crate::constants::MAX_LEGACY_CHAIN_BLOCKS). /// They are only changed from the defaults for testing. pub(crate) fn legacy_chain( - nu5_activation_height: block::Height, + nu5_activation_height: Option, ancestors: I, network: &Network, max_legacy_chain_blocks: usize, @@ -323,11 +323,7 @@ where // // If the cached tip is close to NU5 activation, but there aren't any V5 transactions in the // chain yet, we could reach MAX_BLOCKS_TO_CHECK in Canopy, and incorrectly return an error. - if block - .coinbase_height() - .expect("valid blocks have coinbase heights") - < nu5_activation_height - { + if block.coinbase_height() < nu5_activation_height { return Ok(()); } diff --git a/zebra-state/src/service/tests.rs b/zebra-state/src/service/tests.rs index ca8d195af..7b447a405 100644 --- a/zebra-state/src/service/tests.rs +++ b/zebra-state/src/service/tests.rs @@ -306,7 +306,7 @@ proptest! { fn some_block_less_than_network_upgrade( (network, nu_activation_height, chain) in partial_nu5_chain_strategy(4, true, UNDER_LEGACY_CHAIN_LIMIT, NetworkUpgrade::Canopy) ) { - let response = crate::service::check::legacy_chain(nu_activation_height, chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) + let response = crate::service::check::legacy_chain(Some(nu_activation_height), chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) .map_err(|error| error.to_string()); prop_assert_eq!(response, Ok(())); @@ -323,7 +323,7 @@ proptest! { .coinbase_height() .expect("chain contains valid blocks"); - let response = crate::service::check::legacy_chain(nu_activation_height, chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) + let response = crate::service::check::legacy_chain(Some(nu_activation_height), chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) .map_err(|error| error.to_string()); prop_assert_eq!( @@ -360,7 +360,7 @@ proptest! { ); let response = crate::service::check::legacy_chain( - nu_activation_height, + Some(nu_activation_height), chain.clone().into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT, @@ -380,7 +380,7 @@ proptest! { fn at_least_one_transaction_with_valid_network_upgrade( (network, nu_activation_height, chain) in partial_nu5_chain_strategy(5, true, UNDER_LEGACY_CHAIN_LIMIT, NetworkUpgrade::Canopy) ) { - let response = crate::service::check::legacy_chain(nu_activation_height, chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) + let response = crate::service::check::legacy_chain(Some(nu_activation_height), chain.into_iter().rev(), &network, TEST_LEGACY_CHAIN_LIMIT) .map_err(|error| error.to_string()); prop_assert_eq!(response, Ok(()));