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
|
// Account balance should only contain the first received note
|
||||||
assert_eq!(get_balance(db_data, 0).unwrap(), value);
|
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_select_tx = data.prepare("SELECT id_tx FROM transactions WHERE txid = ?")?;
|
||||||
let mut stmt_mark_spent_note =
|
let mut stmt_mark_spent_note =
|
||||||
data.prepare("UPDATE received_notes SET spent = ? WHERE nf = ?")?;
|
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(
|
let mut stmt_insert_note = data.prepare(
|
||||||
"INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, nf, is_change)
|
"INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, nf, is_change)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
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(
|
let mut stmt_insert_witness = data.prepare(
|
||||||
"INSERT INTO sapling_witnesses (note, block, witness)
|
"INSERT INTO sapling_witnesses (note, block, witness)
|
||||||
VALUES (?, ?, ?)",
|
VALUES (?, ?, ?)",
|
||||||
|
@ -267,21 +274,41 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||||
&JUBJUB,
|
&JUBJUB,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Insert received note into the database.
|
|
||||||
// Assumptions:
|
// Assumptions:
|
||||||
// - A transaction will not contain more than 2^63 shielded outputs.
|
// - A transaction will not contain more than 2^63 shielded outputs.
|
||||||
// - A note value will never exceed 2^63 zatoshis.
|
// - A note value will never exceed 2^63 zatoshis.
|
||||||
stmt_insert_note.execute(&[
|
|
||||||
tx_row.to_sql()?,
|
// First try updating an existing received note into the database.
|
||||||
(output.index as i64).to_sql()?,
|
let note_row = if stmt_update_note.execute(&[
|
||||||
(output.account as i64).to_sql()?,
|
(output.account as i64).to_sql()?,
|
||||||
output.to.diversifier().0.to_sql()?,
|
output.to.diversifier().0.to_sql()?,
|
||||||
(output.note.value as i64).to_sql()?,
|
(output.note.value as i64).to_sql()?,
|
||||||
rcm.as_ref().to_sql()?,
|
rcm.as_ref().to_sql()?,
|
||||||
nf.to_sql()?,
|
nf.to_sql()?,
|
||||||
output.is_change.to_sql()?,
|
output.is_change.to_sql()?,
|
||||||
])?;
|
tx_row.to_sql()?,
|
||||||
let note_row = data.last_insert_rowid();
|
(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()?,
|
||||||
|
(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()?,
|
||||||
|
])?;
|
||||||
|
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.
|
// Save witness for note.
|
||||||
witnesses.push(WitnessRow {
|
witnesses.push(WitnessRow {
|
||||||
|
|
Loading…
Reference in New Issue