zcash_client_sqlite: Reprocess wallet transactions on upgrade to restore additional transparent history.
This commit is contained in:
parent
c22a2a4c92
commit
484659dddb
|
@ -87,8 +87,8 @@ use {
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
zcash_keys::encoding::AddressCodec,
|
|
||||||
zcash_client_backend::wallet::TransparentAddressMetadata,
|
zcash_client_backend::wallet::TransparentAddressMetadata,
|
||||||
|
zcash_keys::encoding::AddressCodec,
|
||||||
zcash_primitives::{legacy::TransparentAddress, transaction::components::OutPoint},
|
zcash_primitives::{legacy::TransparentAddress, transaction::components::OutPoint},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ pub enum WalletMigrationError {
|
||||||
|
|
||||||
/// Reverting the specified migration is not supported.
|
/// Reverting the specified migration is not supported.
|
||||||
CannotRevert(Uuid),
|
CannotRevert(Uuid),
|
||||||
|
|
||||||
|
/// Some other unexpected violation of database business rules occurred
|
||||||
|
Other(SqliteClientError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<rusqlite::Error> for WalletMigrationError {
|
impl From<rusqlite::Error> for WalletMigrationError {
|
||||||
|
@ -79,6 +82,21 @@ impl From<AddressGenerationError> for WalletMigrationError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SqliteClientError> for WalletMigrationError {
|
||||||
|
fn from(value: SqliteClientError) -> Self {
|
||||||
|
match value {
|
||||||
|
SqliteClientError::CorruptedData(err) => WalletMigrationError::CorruptedData(err),
|
||||||
|
SqliteClientError::DbError(err) => WalletMigrationError::DbError(err),
|
||||||
|
SqliteClientError::CommitmentTree(err) => WalletMigrationError::CommitmentTree(err),
|
||||||
|
SqliteClientError::BalanceError(err) => WalletMigrationError::BalanceError(err),
|
||||||
|
SqliteClientError::AddressGeneration(err) => {
|
||||||
|
WalletMigrationError::AddressGeneration(err)
|
||||||
|
}
|
||||||
|
other => WalletMigrationError::Other(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for WalletMigrationError {
|
impl fmt::Display for WalletMigrationError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match &self {
|
match &self {
|
||||||
|
@ -106,6 +124,13 @@ impl fmt::Display for WalletMigrationError {
|
||||||
WalletMigrationError::CannotRevert(uuid) => {
|
WalletMigrationError::CannotRevert(uuid) => {
|
||||||
write!(f, "Reverting migration {} is not supported", uuid)
|
write!(f, "Reverting migration {} is not supported", uuid)
|
||||||
}
|
}
|
||||||
|
WalletMigrationError::Other(err) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Unexpected violation of database business rules: {}",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +142,7 @@ impl std::error::Error for WalletMigrationError {
|
||||||
WalletMigrationError::BalanceError(e) => Some(e),
|
WalletMigrationError::BalanceError(e) => Some(e),
|
||||||
WalletMigrationError::CommitmentTree(e) => Some(e),
|
WalletMigrationError::CommitmentTree(e) => Some(e),
|
||||||
WalletMigrationError::AddressGeneration(e) => Some(e),
|
WalletMigrationError::AddressGeneration(e) => Some(e),
|
||||||
|
WalletMigrationError::Other(e) => Some(e),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,9 @@ pub(super) fn all_migrations<P: consensus::Parameters + 'static>(
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
}),
|
}),
|
||||||
Box::new(spend_key_available::Migration),
|
Box::new(spend_key_available::Migration),
|
||||||
Box::new(tx_retrieval_queue::Migration),
|
Box::new(tx_retrieval_queue::Migration {
|
||||||
|
params: params.clone(),
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,21 @@ use rusqlite::{named_params, Transaction};
|
||||||
use schemer_rusqlite::RusqliteMigration;
|
use schemer_rusqlite::RusqliteMigration;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use zcash_client_backend::data_api::DecryptedTransaction;
|
||||||
use zcash_primitives::transaction::builder::DEFAULT_TX_EXPIRY_DELTA;
|
use zcash_primitives::transaction::builder::DEFAULT_TX_EXPIRY_DELTA;
|
||||||
|
use zcash_protocol::consensus::{self, BlockHeight, BranchId};
|
||||||
|
|
||||||
use crate::wallet::init::WalletMigrationError;
|
use crate::wallet::{self, init::WalletMigrationError};
|
||||||
|
|
||||||
use super::utxos_to_txos;
|
use super::utxos_to_txos;
|
||||||
|
|
||||||
pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xfec02b61_3988_4b4f_9699_98977fac9e7f);
|
pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xfec02b61_3988_4b4f_9699_98977fac9e7f);
|
||||||
|
|
||||||
pub(crate) struct Migration;
|
pub(super) struct Migration<P> {
|
||||||
|
pub(super) params: P,
|
||||||
|
}
|
||||||
|
|
||||||
impl schemer::Migration for Migration {
|
impl<P> schemer::Migration for Migration<P> {
|
||||||
fn id(&self) -> Uuid {
|
fn id(&self) -> Uuid {
|
||||||
MIGRATION_ID
|
MIGRATION_ID
|
||||||
}
|
}
|
||||||
|
@ -28,7 +32,7 @@ impl schemer::Migration for Migration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RusqliteMigration for Migration {
|
impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
|
||||||
type Error = WalletMigrationError;
|
type Error = WalletMigrationError;
|
||||||
|
|
||||||
fn up(&self, transaction: &Transaction) -> Result<(), WalletMigrationError> {
|
fn up(&self, transaction: &Transaction) -> Result<(), WalletMigrationError> {
|
||||||
|
@ -75,6 +79,43 @@ impl RusqliteMigration for Migration {
|
||||||
named_params![":default_expiry_delta": DEFAULT_TX_EXPIRY_DELTA],
|
named_params![":default_expiry_delta": DEFAULT_TX_EXPIRY_DELTA],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Call `decrypt_and_store_transaction` for each transaction known to the wallet to
|
||||||
|
// populate the enhancement queues with any transparent history information that we don't
|
||||||
|
// already have.
|
||||||
|
let mut stmt_transactions =
|
||||||
|
transaction.prepare("SELECT raw, mined_height FROM transactions")?;
|
||||||
|
let mut rows = stmt_transactions.query([])?;
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
let tx_data = row.get::<_, Option<Vec<u8>>>(0)?;
|
||||||
|
let mined_height = row.get::<_, Option<u32>>(1)?.map(BlockHeight::from);
|
||||||
|
|
||||||
|
if let Some(tx_data) = tx_data {
|
||||||
|
let tx = zcash_primitives::transaction::Transaction::read(
|
||||||
|
&tx_data[..],
|
||||||
|
// We assume unmined transactions are created with the current consensus branch ID.
|
||||||
|
mined_height
|
||||||
|
.map_or(BranchId::Sapling, |h| BranchId::for_height(&self.params, h)),
|
||||||
|
)
|
||||||
|
.map_err(|_| {
|
||||||
|
WalletMigrationError::CorruptedData(
|
||||||
|
"Could not read serialized transaction data.".to_owned(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
wallet::store_decrypted_tx(
|
||||||
|
transaction,
|
||||||
|
&self.params,
|
||||||
|
DecryptedTransaction::new(
|
||||||
|
mined_height,
|
||||||
|
&tx,
|
||||||
|
vec![],
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue