use zcash_protocol::PoolType;
use zcash_protocol::ShieldedPool;
use zcash_protocol::consensus::BlockHeight;
use zingo_status::confirmation_status::ConfirmationStatus;
use crate::check_client_balances;
use crate::testutils::lightclient::{from_inputs, get_base_address};
use crate::testutils::mock_indexer::{MockNet, faucet_funding_transaction};
const FUNDING: u64 = 100_000_000;
async fn fund_at_height_three(net: &MockNet, address: &str) -> Vec<u8> {
let funding = faucet_funding_transaction(vec![(address, FUNDING, None)]).await;
let mut chain = net.chain.write().await;
chain.mine_empty_blocks(2);
chain.mine_block(vec![funding.clone()]);
chain.mine_empty_blocks(2);
funding
}
#[tokio::test]
async fn reorg_removes_receipt() {
let mut net = MockNet::launch().await;
let mut wallet = net
.client(zingo_test_vectors::seeds::HOSPITAL_MUSEUM_SEED, None)
.await;
let address = get_base_address(&wallet, PoolType::Shielded(ShieldedPool::Orchard)).await;
fund_at_height_three(&net, &address).await;
wallet.sync_and_await().await.unwrap();
check_client_balances!(wallet, i: FUNDING o: 0 s: 0 t: 0);
{
let mut chain = net.chain.write().await;
let evicted = chain.reorg_to(2);
assert_eq!(evicted.len(), 1, "only the funding tx is evicted");
chain.mine_empty_blocks(5);
}
wallet.sync_and_await().await.unwrap();
check_client_balances!(wallet, i: 0 o: 0 s: 0 t: 0);
}
#[tokio::test]
async fn reorg_moves_receipt_to_new_height() {
let mut net = MockNet::launch().await;
let mut wallet = net
.client(zingo_test_vectors::seeds::HOSPITAL_MUSEUM_SEED, None)
.await;
let address = get_base_address(&wallet, PoolType::Shielded(ShieldedPool::Orchard)).await;
fund_at_height_three(&net, &address).await;
wallet.sync_and_await().await.unwrap();
let confirmed_at = |summaries: &crate::wallet::summary::data::TransactionSummaries| {
summaries
.iter()
.find(|summary| summary.value == FUNDING)
.expect("the funding receipt has a summary")
.status
};
let summaries = wallet.transaction_summaries(false).await.unwrap();
assert_eq!(
confirmed_at(&summaries),
ConfirmationStatus::Confirmed(BlockHeight::from_u32(3)),
);
{
let mut chain = net.chain.write().await;
let evicted = chain.reorg_to(2);
assert_eq!(evicted.len(), 1);
chain.mine_empty_blocks(2);
chain.mine_block(evicted);
chain.mine_empty_blocks(2);
}
wallet.sync_and_await().await.unwrap();
check_client_balances!(wallet, i: FUNDING o: 0 s: 0 t: 0);
let summaries = wallet.transaction_summaries(false).await.unwrap();
assert_eq!(
confirmed_at(&summaries),
ConfirmationStatus::Confirmed(BlockHeight::from_u32(5)),
"the receipt's confirmation height follows the re-mined block"
);
}
#[tokio::test]
async fn reorg_expires_outgoing_transaction() {
let mut net = MockNet::launch().await;
let mut sender = net
.client(zingo_test_vectors::seeds::HOSPITAL_MUSEUM_SEED, None)
.await;
let mut recipient = net
.client(zingo_test_vectors::seeds::DARKSIDE_SEED, None)
.await;
let sender_address = get_base_address(&sender, PoolType::Shielded(ShieldedPool::Orchard)).await;
let recipient_address =
get_base_address(&recipient, PoolType::Shielded(ShieldedPool::Orchard)).await;
fund_at_height_three(&net, &sender_address).await;
sender.sync_and_await().await.unwrap();
check_client_balances!(sender, i: FUNDING o: 0 s: 0 t: 0);
from_inputs::quick_send(&mut sender, vec![(&recipient_address, 10_000, None)])
.await
.unwrap();
{
let mut chain = net.chain.write().await;
chain.mine_mempool();
chain.mine_empty_blocks(1);
}
sender.sync_and_await().await.unwrap();
recipient.sync_and_await().await.unwrap();
let spent_less_fee = FUNDING - 10_000 - 10_000;
check_client_balances!(sender, i: spent_less_fee o: 0 s: 0 t: 0);
check_client_balances!(recipient, i: 10_000 o: 0 s: 0 t: 0);
{
let mut chain = net.chain.write().await;
let evicted = chain.reorg_to(5);
assert_eq!(evicted.len(), 1, "only the send is evicted");
chain.mine_empty_blocks(120);
}
sender.sync_and_await().await.unwrap();
recipient.sync_and_await().await.unwrap();
check_client_balances!(sender, i: FUNDING o: 0 s: 0 t: 0);
check_client_balances!(recipient, i: 0 o: 0 s: 0 t: 0);
}