Add an `InPoint` type to the Orchard wallet to fix incorrect conflict data.

This commit is contained in:
Kris Nuttycombe 2022-03-07 16:39:09 -07:00
parent 97895a6f6d
commit c9ef5cd45a
1 changed files with 32 additions and 23 deletions

View File

@ -30,12 +30,20 @@ pub struct LastObserved {
block_tx_idx: Option<usize>,
}
/// A pointer to a particular action in an Orchard transaction output.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct OutPoint {
txid: TxId,
action_idx: usize,
}
/// A pointer to a previous output being spent in an Orchard action.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InPoint {
txid: TxId,
action_idx: usize,
}
#[derive(Debug, Clone)]
pub struct DecryptedNote {
note: Note,
@ -137,12 +145,12 @@ pub struct Wallet {
locked_notes: BTreeSet<OutPoint>,
/// Notes marked as spent as a consequence of their nullifiers having been
/// observed in bundle action inputs. The keys of this map are the outpoints
/// where the spent notes were created, and the values are the outpoints
/// where the spent notes were created, and the values are the inpoints
/// identifying the actions in which they are spent.
spent_notes: BTreeMap<OutPoint, OutPoint>,
spent_notes: BTreeMap<OutPoint, InPoint>,
/// For each nullifier which appears more than once in transactions that this
/// wallet has observed, the set of outpoints corresponding to those nullifiers.
conflicts: BTreeMap<Nullifier, BTreeSet<OutPoint>>,
conflicts: BTreeMap<Nullifier, BTreeSet<InPoint>>,
}
#[derive(Debug, Clone)]
@ -300,17 +308,30 @@ impl Wallet {
// Check for spends of our notes by matching against the nullifiers
// we're tracking, and when we detect one, associate the current
// txid as spending the note.
// txid and action as spending the note.
for (action_idx, action) in bundle.actions().iter().enumerate() {
let nf = action.nullifier();
// find the outpoint where the note being spent in this action was created
if let Some(outpoint) = self.nullifiers.get(nf) {
self.spent_notes.insert(
*outpoint,
OutPoint {
txid: *txid,
action_idx,
},
);
let inpoint = InPoint {
txid: *txid,
action_idx,
};
// If we already have an entry for this nullifier that does not correspond
// to the current inpoint, then add the existing inpoint and the current
// inpoint to the conflicts map. (The existing inpoint will already be
// present if this is not the first detected conflict for this nullifier.)
if let Some(cur_inpoint) = self.spent_notes.get(outpoint) {
if cur_inpoint != &inpoint {
let conflicts = self.conflicts.entry(*nf).or_insert_with(BTreeSet::new);
conflicts.insert(*cur_inpoint);
conflicts.insert(inpoint);
}
}
// optimistically consider the latest inpoint to be the correct one
self.spent_notes.insert(*outpoint, inpoint);
}
}
@ -331,18 +352,6 @@ impl Wallet {
// that we can detect when the note is later spent.
if let Some(fvk) = self.key_store.viewing_keys.get(&ivk) {
let nf = note.nullifier(fvk);
// If we already have an entry for this nullifier that does not correspond
// to the current outpoint, then add the existing outpoint and the current
// outpoint to the conflicts map. (The existing output will already be
// present if this is not the first detected conflict for this nullifier.)
if let Some(op) = self.nullifiers.get(&nf) {
if op != &outpoint {
let conflicts = self.conflicts.entry(nf).or_insert_with(BTreeSet::new);
conflicts.insert(*op);
conflicts.insert(outpoint);
};
}
self.nullifiers.insert(nf, outpoint);
}