Fix indexing error in checkpoint determination.
This commit is contained in:
parent
d65b129b43
commit
8fa3a08c0b
|
@ -235,9 +235,9 @@ pub(crate) fn scan_block_with_runner<
|
||||||
initial_commitment_tree_meta.map(|m| (m.sapling_tree_size() + 1).into())
|
initial_commitment_tree_meta.map(|m| (m.sapling_tree_size() + 1).into())
|
||||||
};
|
};
|
||||||
|
|
||||||
for tx in block.vtx.into_iter() {
|
let block_tx_count = block.vtx.len();
|
||||||
|
for (tx_idx, tx) in block.vtx.into_iter().enumerate() {
|
||||||
let txid = tx.txid();
|
let txid = tx.txid();
|
||||||
let index = tx.index as usize;
|
|
||||||
|
|
||||||
// Check for spent notes. The only step that is not constant-time is
|
// Check for spent notes. The only step that is not constant-time is
|
||||||
// the filter() at the end.
|
// the filter() at the end.
|
||||||
|
@ -338,9 +338,20 @@ pub(crate) fn scan_block_with_runner<
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (index, ((_, output), dec_output)) in decoded.iter().zip(decrypted).enumerate() {
|
for (output_idx, ((_, output), dec_output)) in decoded.iter().zip(decrypted).enumerate()
|
||||||
|
{
|
||||||
// Collect block note commitments
|
// Collect block note commitments
|
||||||
let node = sapling::Node::from_cmu(&output.cmu);
|
let node = sapling::Node::from_cmu(&output.cmu);
|
||||||
|
let is_checkpoint = output_idx + 1 == decoded.len() && tx_idx + 1 == block_tx_count;
|
||||||
|
let retention = match (dec_output.is_some(), is_checkpoint) {
|
||||||
|
(is_marked, true) => Retention::Checkpoint {
|
||||||
|
id: block_height,
|
||||||
|
is_marked,
|
||||||
|
},
|
||||||
|
(true, false) => Retention::Marked,
|
||||||
|
(false, false) => Retention::Ephemeral,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some((note, account, nk)) = dec_output {
|
if let Some((note, account, nk)) = dec_output {
|
||||||
// A note is marked as "change" if the account that received it
|
// A note is marked as "change" if the account that received it
|
||||||
// also spent notes in the same transaction. This will catch,
|
// also spent notes in the same transaction. This will catch,
|
||||||
|
@ -351,11 +362,11 @@ pub(crate) fn scan_block_with_runner<
|
||||||
let is_change = spent_from_accounts.contains(&account);
|
let is_change = spent_from_accounts.contains(&account);
|
||||||
let note_commitment_tree_position = sapling_tree_position
|
let note_commitment_tree_position = sapling_tree_position
|
||||||
.ok_or(SyncError::SaplingTreeSizeUnknown(block_height))?
|
.ok_or(SyncError::SaplingTreeSizeUnknown(block_height))?
|
||||||
+ index.try_into().unwrap();
|
+ output_idx.try_into().unwrap();
|
||||||
let nf = K::sapling_nf(&nk, ¬e, note_commitment_tree_position);
|
let nf = K::sapling_nf(&nk, ¬e, note_commitment_tree_position);
|
||||||
|
|
||||||
shielded_outputs.push(WalletSaplingOutput::from_parts(
|
shielded_outputs.push(WalletSaplingOutput::from_parts(
|
||||||
index,
|
output_idx,
|
||||||
output.cmu,
|
output.cmu,
|
||||||
output.ephemeral_key.clone(),
|
output.ephemeral_key.clone(),
|
||||||
account,
|
account,
|
||||||
|
@ -364,38 +375,16 @@ pub(crate) fn scan_block_with_runner<
|
||||||
note_commitment_tree_position,
|
note_commitment_tree_position,
|
||||||
nf,
|
nf,
|
||||||
));
|
));
|
||||||
|
|
||||||
sapling_note_commitments.push((
|
|
||||||
node,
|
|
||||||
if index == decoded.len() - 1 {
|
|
||||||
Retention::Checkpoint {
|
|
||||||
id: block_height,
|
|
||||||
is_marked: true,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Retention::Marked
|
|
||||||
},
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
sapling_note_commitments.push((
|
|
||||||
node,
|
|
||||||
if index == decoded.len() - 1 {
|
|
||||||
Retention::Checkpoint {
|
|
||||||
id: block_height,
|
|
||||||
is_marked: false,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Retention::Ephemeral
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sapling_note_commitments.push((node, retention));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(shielded_spends.is_empty() && shielded_outputs.is_empty()) {
|
if !(shielded_spends.is_empty() && shielded_outputs.is_empty()) {
|
||||||
wtxs.push(WalletTx {
|
wtxs.push(WalletTx {
|
||||||
txid,
|
txid,
|
||||||
index,
|
index: tx.index as usize,
|
||||||
sapling_spends: shielded_spends,
|
sapling_spends: shielded_spends,
|
||||||
sapling_outputs: shielded_outputs,
|
sapling_outputs: shielded_outputs,
|
||||||
});
|
});
|
||||||
|
@ -423,6 +412,7 @@ mod tests {
|
||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
GroupEncoding,
|
GroupEncoding,
|
||||||
};
|
};
|
||||||
|
use incrementalmerkletree::Retention;
|
||||||
use rand_core::{OsRng, RngCore};
|
use rand_core::{OsRng, RngCore};
|
||||||
use zcash_note_encryption::Domain;
|
use zcash_note_encryption::Domain;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
@ -613,6 +603,21 @@ mod tests {
|
||||||
assert_eq!(tx.sapling_outputs[0].index(), 0);
|
assert_eq!(tx.sapling_outputs[0].index(), 0);
|
||||||
assert_eq!(tx.sapling_outputs[0].account(), account);
|
assert_eq!(tx.sapling_outputs[0].account(), account);
|
||||||
assert_eq!(tx.sapling_outputs[0].note().value().inner(), 5);
|
assert_eq!(tx.sapling_outputs[0].note().value().inner(), 5);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pruned_block
|
||||||
|
.sapling_commitments
|
||||||
|
.iter()
|
||||||
|
.map(|(_, retention)| *retention)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
Retention::Ephemeral,
|
||||||
|
Retention::Checkpoint {
|
||||||
|
id: pruned_block.block_height,
|
||||||
|
is_marked: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
go(false);
|
go(false);
|
||||||
|
|
Loading…
Reference in New Issue