zcash_client_backend: Use correct output index for t-addr recipients

`create_spend_to_address` was originally written only for sending to
Sapling addresses. It was later amended to support sending to
transparent addresses, but the assumption about there being a Sapling
output was not removed. This was not an issue for most transactions
because there would be change, but in the case of a z->t transaction
with no change, `create_spend_to_address` would reliably panic.

This commit fixes the bug by setting the output index for transparent
recipients to 0. The `output_index` field of `SentTransaction` is also
documented to correctly reflect its dependency on the type of
`recipient_address`.
This commit is contained in:
Jack Grigg 2021-03-24 18:54:15 +13:00
parent 7c8b29e693
commit cb6a993840
3 changed files with 24 additions and 4 deletions

View File

@ -195,6 +195,12 @@ pub struct ReceivedTransaction<'a> {
pub struct SentTransaction<'a> {
pub tx: &'a Transaction,
pub created: time::OffsetDateTime,
/// The index within the transaction that contains the recipient output.
///
/// - If `recipient_address` is a Sapling address, this is an index into the Sapling
/// outputs of the transaction.
/// - If `recipient_address` is a transparent address, this is an index into the
/// transparent outputs of the transaction.
pub output_index: usize,
pub account: AccountId,
pub recipient_address: &'a RecipientAddress,

View File

@ -229,10 +229,16 @@ where
.build(consensus_branch_id, &prover)
.map_err(Error::Builder)?;
// We only called add_sapling_output() once.
let output_index = match tx_metadata.output_index(0) {
let output_index = match to {
// Sapling outputs are shuffled, so we need to look up where the output ended up.
RecipientAddress::Shielded(_) => match tx_metadata.output_index(0) {
Some(idx) => idx as i64,
None => panic!("Output 0 should exist in the transaction"),
},
// This function only spends shielded notes, so there will only ever be a single
// transparent output in this case (and even if there were more, we don't shuffle
// the transparent outputs).
RecipientAddress::Transparent(_) => 0,
};
wallet_db.store_sent_tx(&SentTransaction {

View File

@ -715,6 +715,14 @@ pub fn put_sent_note<'a, P: consensus::Parameters>(
Ok(())
}
/// Inserts a sent note into the wallet database.
///
/// `output_index` is the index within the transaction that contains the recipient output:
///
/// - If `to` is a Sapling address, this is an index into the Sapling outputs of the
/// transaction.
/// - If `to` is a transparent address, this is an index into the transparent outputs of
/// the transaction.
pub fn insert_sent_note<'a, P: consensus::Parameters>(
stmts: &mut DataConnStmtCache<'a, P>,
tx_ref: i64,