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

Backport stable zfz fix 3 #1304

Merged
merged 6 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 36 additions & 1 deletion libtonode-tests/tests/concrete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,48 @@ mod fast {
use zcash_primitives::transaction::components::amount::NonNegativeAmount;
use zingo_status::confirmation_status::ConfirmationStatus;
use zingo_testutils::lightclient::from_inputs;
use zingoconfig::ZENNIES_FOR_ZINGO_REGTEST_ADDRESS;
use zingolib::{
utils::conversion::txid_from_hex_encoded_str,
wallet::{notes::ShieldedNoteInterface, WalletBase},
wallet::{data::summaries::ValueTransferKind, notes::ShieldedNoteInterface, WalletBase},
};

use super::*;

#[tokio::test]
async fn create_send_to_self_with_zfz_active() {
let (_regtest_manager, _cph, _faucet, recipient, _txid) =
scenarios::orchard_funded_recipient(5_000_000).await;

recipient
.propose_send_all(
address_from_str(
&get_base_address_macro!(&recipient, "unified"),
&recipient.config().chain,
)
.unwrap(),
true,
None,
)
.await
.unwrap();

recipient
.complete_and_broadcast_stored_proposal()
.await
.unwrap();

let value_transfers = &recipient.value_transfers().await;

assert!(value_transfers
.iter()
.any(|vt| vt.kind() == ValueTransferKind::SendToSelf));
assert!(value_transfers
.iter()
.any(|vt| vt.kind() == ValueTransferKind::Sent
&& vt.recipient_address() == Some(ZENNIES_FOR_ZINGO_REGTEST_ADDRESS)));
}

#[tokio::test]
async fn targetted_rescan() {
let (regtest_manager, _cph, _faucet, recipient, txid) =
Expand Down
6 changes: 6 additions & 0 deletions zingoconfig/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ use zcash_primitives::consensus::{
/// TODO: Add Doc Comment Here!
pub const DEVELOPER_DONATION_ADDRESS: &str = "u1w47nzy4z5g9zvm4h2s4ztpl8vrdmlclqz5sz02742zs5j3tz232u4safvv9kplg7g06wpk5fx0k0rx3r9gg4qk6nkg4c0ey57l0dyxtatqf8403xat7vyge7mmen7zwjcgvryg22khtg3327s6mqqkxnpwlnrt27kxhwg37qys2kpn2d2jl2zkk44l7j7hq9az82594u3qaescr3c9v";
/// TODO: Add Doc Comment Here!
pub const ZENNIES_FOR_ZINGO_DONATION_ADDRESS: &str = "u1p32nu0pgev5cr0u6t4ja9lcn29kaw37xch8nyglwvp7grl07f72c46hxvw0u3q58ks43ntg324fmulc2xqf4xl3pv42s232m25vaukp05s6av9z76s3evsstax4u6f5g7tql5yqwuks9t4ef6vdayfmrsymenqtshgxzj59hdydzygesqa7pdpw463hu7afqf4an29m69kfasdwr494";
/// TODO: Add Doc Comment Here!
pub const ZENNIES_FOR_ZINGO_REGTEST_ADDRESS: &str = "uregtest14emvr2anyul683p43d0ck55c04r65ld6f0shetcn77z8j7m64hm4ku3wguf60s75f0g3s7r7g89z22f3ff5tsfgr45efj4pe2gyg5krqp5vvl3afu0280zp9ru2379zat5y6nkqkwjxsvpq5900kchcgzaw8v8z3ggt5yymnuj9hymtv3p533fcrk2wnj48g5vg42vle08c2xtanq0e";
/// TODO: Add Doc Comment Here!
pub const ZENNIES_FOR_ZINGO_AMOUNT: u64 = 1_000_000;
/// TODO: Add Doc Comment Here!
pub const DEFAULT_LIGHTWALLETD_SERVER: &str = "https://zec.rocks:443";
/// TODO: Add Doc Comment Here!
pub const MAX_REORG: usize = 100;
Expand Down
136 changes: 75 additions & 61 deletions zingolib/src/lightclient/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use crate::{
finsight,
summaries::{
basic_transaction_summary_parts, DetailedTransactionSummaries,
DetailedTransactionSummaryBuilder, TransactionSummaries, TransactionSummaryBuilder,
TransactionSummaryInterface as _, ValueTransfer, ValueTransferBuilder,
ValueTransferKind, ValueTransfers,
DetailedTransactionSummaryBuilder, TransactionSummaries, TransactionSummary,
TransactionSummaryBuilder, TransactionSummaryInterface as _, ValueTransfer,
ValueTransferBuilder, ValueTransferKind, ValueTransfers,
},
OutgoingTxData,
},
Expand Down Expand Up @@ -268,6 +268,72 @@ impl LightClient {
/// Provides a list of value transfers related to this capability
/// A value transfer is a group of all notes to a specific receiver in a transaction.
pub async fn value_transfers(&self) -> ValueTransfers {
fn create_send_value_transfers(
value_transfers: &mut Vec<ValueTransfer>,
transaction_summary: &TransactionSummary,
) {
let mut addresses =
HashSet::with_capacity(transaction_summary.outgoing_tx_data().len());
transaction_summary
.outgoing_tx_data()
.iter()
.for_each(|outgoing_tx_data| {
let address = if let Some(ua) = outgoing_tx_data.recipient_ua.clone() {
ua
} else {
outgoing_tx_data.recipient_address.clone()
};
// hash set is used to create unique list of addresses as duplicates are not inserted twice
addresses.insert(address);
});
addresses.iter().for_each(|address| {
let outgoing_data_to_address: Vec<OutgoingTxData> = transaction_summary
.outgoing_tx_data()
.iter()
.filter(|outgoing_tx_data| {
let query_address = if let Some(ua) = outgoing_tx_data.recipient_ua.clone()
{
ua
} else {
outgoing_tx_data.recipient_address.clone()
};
query_address == address.clone()
})
.cloned()
.collect();
let value: u64 = outgoing_data_to_address
.iter()
.map(|outgoing_tx_data| outgoing_tx_data.value)
.sum();
let memos: Vec<String> = outgoing_data_to_address
.iter()
.filter_map(|outgoing_tx_data| {
if let Memo::Text(memo_text) = outgoing_tx_data.memo.clone() {
Some(memo_text.to_string())
} else {
None
}
})
.collect();
value_transfers.push(
ValueTransferBuilder::new()
.txid(transaction_summary.txid())
.datetime(transaction_summary.datetime())
.status(transaction_summary.status())
.blockheight(transaction_summary.blockheight())
.transaction_fee(transaction_summary.fee())
.zec_price(transaction_summary.zec_price())
.kind(ValueTransferKind::Sent)
.value(value)
.recipient_address(Some(address.clone()))
.pool_received(None)
.memos(memos)
.build()
.expect("all fields should be populated"),
);
});
}

let mut value_transfers: Vec<ValueTransfer> = Vec::new();
let transaction_summaries = self.transaction_summaries().await;

Expand All @@ -276,62 +342,7 @@ impl LightClient {
TransactionKind::Sent(SendType::Send) => {
// create 1 sent value transfer for each non-self recipient address
// if recipient_ua is available it overrides recipient_address
let mut addresses = HashSet::with_capacity(tx.outgoing_tx_data().len());
tx.outgoing_tx_data().iter().for_each(|outgoing_tx_data| {
let address = if let Some(ua) = outgoing_tx_data.recipient_ua.clone() {
ua
} else {
outgoing_tx_data.recipient_address.clone()
};
// hash set is used to create unique list of addresses as duplicates are not inserted twice
addresses.insert(address);
});
addresses.iter().for_each(|address| {
let outgoing_data_to_address: Vec<OutgoingTxData> = tx
.outgoing_tx_data()
.iter()
.filter(|outgoing_tx_data| {
let query_address =
if let Some(ua) = outgoing_tx_data.recipient_ua.clone() {
ua
} else {
outgoing_tx_data.recipient_address.clone()
};
query_address == address.clone()
})
.cloned()
.collect();
let value: u64 = outgoing_data_to_address
.iter()
.map(|outgoing_tx_data| outgoing_tx_data.value)
.sum();
let memos: Vec<String> = outgoing_data_to_address
.iter()
.filter_map(|outgoing_tx_data| {
if let Memo::Text(memo_text) = outgoing_tx_data.memo.clone() {
Some(memo_text.to_string())
} else {
None
}
})
.collect();
value_transfers.push(
ValueTransferBuilder::new()
.txid(tx.txid())
.datetime(tx.datetime())
.status(tx.status())
.blockheight(tx.blockheight())
.transaction_fee(tx.fee())
.zec_price(tx.zec_price())
.kind(ValueTransferKind::Sent)
.value(value)
.recipient_address(Some(address.clone()))
.pool_received(None)
.memos(memos)
.build()
.expect("all fields should be populated"),
);
});
create_send_value_transfers(&mut value_transfers, tx);

// create 1 memo-to-self if a sending transaction receives any number of memos
if tx.orchard_notes().iter().any(|note| note.memo().is_some())
Expand Down Expand Up @@ -473,6 +484,9 @@ impl LightClient {
.expect("all fields should be populated"),
);
}

// in the case Zennies For Zingo! is active
create_send_value_transfers(&mut value_transfers, tx);
}
TransactionKind::Received => {
// create 1 received value tansfer for each pool recieved to
Expand Down Expand Up @@ -579,7 +593,7 @@ impl LightClient {
.values()
.map(|tx| {
let (kind, value, fee, orchard_notes, sapling_notes, transparent_coins) =
basic_transaction_summary_parts(tx, transaction_records);
basic_transaction_summary_parts(tx, transaction_records, &self.config().chain);

TransactionSummaryBuilder::new()
.txid(tx.txid)
Expand Down Expand Up @@ -622,7 +636,7 @@ impl LightClient {
.values()
.map(|tx| {
let (kind, value, fee, orchard_notes, sapling_notes, transparent_coins) =
basic_transaction_summary_parts(tx, transaction_records);
basic_transaction_summary_parts(tx, transaction_records, &self.config().chain);
let orchard_nullifiers: Vec<String> = tx
.spent_orchard_nullifiers
.iter()
Expand Down
21 changes: 11 additions & 10 deletions zingolib/src/lightclient/propose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use zcash_client_backend::ShieldedProtocol;
use zcash_primitives::{memo::MemoBytes, transaction::components::amount::NonNegativeAmount};

use thiserror::Error;
use zingoconfig::ZENNIES_FOR_ZINGO_AMOUNT;
use zingoconfig::ZENNIES_FOR_ZINGO_DONATION_ADDRESS;

use crate::data::proposal::ProportionalFeeProposal;
use crate::data::proposal::ProportionalFeeShieldProposal;
Expand Down Expand Up @@ -98,15 +100,16 @@ pub enum ProposeShieldError {
fn append_zingo_zenny_receiver(receivers: &mut Vec<Receiver>) {
let dev_donation_receiver = Receiver::new(
crate::utils::conversion::address_from_str(
zingoconfig::DEVELOPER_DONATION_ADDRESS,
ZENNIES_FOR_ZINGO_DONATION_ADDRESS,
&ChainType::Mainnet,
)
.expect("Hard coded str"),
NonNegativeAmount::from_u64(1_000_000).expect("Hard coded u64."),
Some(MemoBytes::from_bytes(b"A Zenny for Zingo!").expect("Hard Coded memo bytes.")),
NonNegativeAmount::from_u64(ZENNIES_FOR_ZINGO_AMOUNT).expect("Hard coded u64."),
None,
);
receivers.push(dev_donation_receiver);
}

impl LightClient {
/// Stores a proposal in the `latest_proposal` field of the LightClient.
/// This field must be populated in order to then send a transaction.
Expand All @@ -115,9 +118,7 @@ impl LightClient {
*latest_proposal_lock = Some(proposal);
}

/// Unstable function to expose the zip317 interface for development
// TOdo: add correct functionality and doc comments / tests
// TODO: Add migrate_sapling_to_orchard argument
/// Creates a proposal from a transaction request.
pub(crate) async fn create_send_proposal(
&self,
request: TransactionRequest,
Expand Down Expand Up @@ -147,6 +148,7 @@ impl LightClient {
)
.map_err(ProposeSendError::Proposal)
}

/// The shield operation consumes a proposal that transfers value
/// into the Orchard pool.
///
Expand Down Expand Up @@ -188,7 +190,7 @@ impl LightClient {
Ok(proposed_shield)
}

/// Unstable function to expose the zip317 interface for development
/// Creates and stores a proposal from a transaction request.
pub async fn propose_send(
&self,
request: TransactionRequest,
Expand All @@ -199,8 +201,7 @@ impl LightClient {
Ok(proposal)
}

/// Unstable function to expose the zip317 interface for development
// TOdo: add correct functionality and doc comments / tests
/// Creates and stores a proposal for sending all shielded funds to a given address.
pub async fn propose_send_all(
&self,
address: zcash_keys::address::Address,
Expand Down Expand Up @@ -297,7 +298,7 @@ impl LightClient {
.collect::<Vec<_>>()
}

/// Unstable function to expose the zip317 interface for development
/// Creates and stores a proposal for shielding all transparent funds..
pub async fn propose_shield(
&self,
) -> Result<ProportionalFeeShieldProposal, ProposeShieldError> {
Expand Down
12 changes: 4 additions & 8 deletions zingolib/src/lightclient/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ pub mod send_with_proposal {
}

impl LightClient {
/// Unstable function to expose the zip317 interface for development
// TODO: add correct functionality and doc comments / tests
/// Calculates, signs and broadcasts transactions from a proposal.
async fn complete_and_broadcast<NoteRef>(
&self,
proposal: &Proposal<zcash_primitives::transaction::fees::zip317::FeeRule, NoteRef>,
Expand Down Expand Up @@ -209,8 +208,7 @@ pub mod send_with_proposal {
result
}

/// Unstable function to expose the zip317 interface for development
// TODO: add correct functionality and doc comments / tests
/// Calculates, signs and broadcasts transactions from a stored proposal.
pub async fn complete_and_broadcast_stored_proposal(
&self,
) -> Result<NonEmpty<TxId>, CompleteAndBroadcastStoredProposal> {
Expand All @@ -231,8 +229,7 @@ pub mod send_with_proposal {
}
}

/// Unstable function to expose the zip317 interface for development
// TODO: add correct functionality and doc comments / tests
/// Creates, signs and broadcasts transactions from a transaction request without confirmation.
pub async fn quick_send(
&self,
request: TransactionRequest,
Expand All @@ -241,8 +238,7 @@ pub mod send_with_proposal {
Ok(self.complete_and_broadcast::<NoteId>(&proposal).await?)
}

/// Unstable function to expose the zip317 interface for development
// TODO: add correct functionality and doc comments / tests
/// Shields all transparent funds without confirmation.
zancas marked this conversation as resolved.
Show resolved Hide resolved
pub async fn quick_shield(&self) -> Result<NonEmpty<TxId>, QuickShieldError> {
let proposal = self.create_shield_proposal().await?;
Ok(self.complete_and_broadcast::<Infallible>(&proposal).await?)
Expand Down
Loading
Loading