zcash_client_sqlite: Update received note during scan if present
Fixes a bug where rewinding a block that contained a received note would cause a constraint violation.
This commit is contained in:
parent
9363ec36d9
commit
3036064cd0
|
@ -470,5 +470,11 @@ mod tests {
|
|||
|
||||
// Account balance should only contain the first received note
|
||||
assert_eq!(get_balance(db_data, 0).unwrap(), value);
|
||||
|
||||
// Scan the cache again
|
||||
scan_cached_blocks(db_cache, db_data, None).unwrap();
|
||||
|
||||
// Account balance should again reflect both received notes
|
||||
assert_eq!(get_balance(db_data, 0).unwrap(), value + value2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,10 +143,17 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
|
|||
let mut stmt_select_tx = data.prepare("SELECT id_tx FROM transactions WHERE txid = ?")?;
|
||||
let mut stmt_mark_spent_note =
|
||||
data.prepare("UPDATE received_notes SET spent = ? WHERE nf = ?")?;
|
||||
let mut stmt_update_note = data.prepare(
|
||||
"UPDATE received_notes
|
||||
SET account = ?, diversifier = ?, value = ?, rcm = ?, nf = ?, is_change = ?
|
||||
WHERE tx = ? AND output_index = ?",
|
||||
)?;
|
||||
let mut stmt_insert_note = data.prepare(
|
||||
"INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, nf, is_change)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
)?;
|
||||
let mut stmt_select_note =
|
||||
data.prepare("SELECT id_note FROM received_notes WHERE tx = ? AND output_index = ?")?;
|
||||
let mut stmt_insert_witness = data.prepare(
|
||||
"INSERT INTO sapling_witnesses (note, block, witness)
|
||||
VALUES (?, ?, ?)",
|
||||
|
@ -267,10 +274,23 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
|
|||
&JUBJUB,
|
||||
);
|
||||
|
||||
// Insert received note into the database.
|
||||
// Assumptions:
|
||||
// - A transaction will not contain more than 2^63 shielded outputs.
|
||||
// - A note value will never exceed 2^63 zatoshis.
|
||||
|
||||
// First try updating an existing received note into the database.
|
||||
let note_row = if stmt_update_note.execute(&[
|
||||
(output.account as i64).to_sql()?,
|
||||
output.to.diversifier().0.to_sql()?,
|
||||
(output.note.value as i64).to_sql()?,
|
||||
rcm.as_ref().to_sql()?,
|
||||
nf.to_sql()?,
|
||||
output.is_change.to_sql()?,
|
||||
tx_row.to_sql()?,
|
||||
(output.index as i64).to_sql()?,
|
||||
])? == 0
|
||||
{
|
||||
// It isn't there, so insert our note into the database.
|
||||
stmt_insert_note.execute(&[
|
||||
tx_row.to_sql()?,
|
||||
(output.index as i64).to_sql()?,
|
||||
|
@ -281,7 +301,14 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
|
|||
nf.to_sql()?,
|
||||
output.is_change.to_sql()?,
|
||||
])?;
|
||||
let note_row = data.last_insert_rowid();
|
||||
data.last_insert_rowid()
|
||||
} else {
|
||||
// It was there, so grab its row number.
|
||||
stmt_select_note.query_row(
|
||||
&[tx_row.to_sql()?, (output.index as i64).to_sql()?],
|
||||
|row| row.get(0),
|
||||
)?
|
||||
};
|
||||
|
||||
// Save witness for note.
|
||||
witnesses.push(WitnessRow {
|
||||
|
|
Loading…
Reference in New Issue