Record whether imported accounts have a spending key

This commit is contained in:
Andrew Arnott 2024-07-23 20:36:32 -06:00
parent cc39084de4
commit c9ecc1196a
No known key found for this signature in database
GPG Key ID: 251505B99C25745D
5 changed files with 80 additions and 10 deletions

View File

@ -600,6 +600,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
.map_err(|_| SqliteClientError::KeyDerivationError(account_index))?; .map_err(|_| SqliteClientError::KeyDerivationError(account_index))?;
let ufvk = usk.to_unified_full_viewing_key(); let ufvk = usk.to_unified_full_viewing_key();
let spending_key_available = true;
let account = wallet::add_account( let account = wallet::add_account(
wdb.conn.0, wdb.conn.0,
&wdb.params, &wdb.params,
@ -609,6 +610,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
}, },
wallet::ViewingKey::Full(Box::new(ufvk)), wallet::ViewingKey::Full(Box::new(ufvk)),
birthday, birthday,
spending_key_available,
)?; )?;
Ok((account.id(), usk)) Ok((account.id(), usk))
@ -634,6 +636,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
.map_err(|_| SqliteClientError::KeyDerivationError(account_index))?; .map_err(|_| SqliteClientError::KeyDerivationError(account_index))?;
let ufvk = usk.to_unified_full_viewing_key(); let ufvk = usk.to_unified_full_viewing_key();
let spending_key_available = true;
let account = wallet::add_account( let account = wallet::add_account(
wdb.conn.0, wdb.conn.0,
&wdb.params, &wdb.params,
@ -643,6 +646,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
}, },
wallet::ViewingKey::Full(Box::new(ufvk)), wallet::ViewingKey::Full(Box::new(ufvk)),
birthday, birthday,
spending_key_available,
)?; )?;
Ok((account, usk)) Ok((account, usk))
@ -653,7 +657,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
&mut self, &mut self,
ufvk: &UnifiedFullViewingKey, ufvk: &UnifiedFullViewingKey,
birthday: &AccountBirthday, birthday: &AccountBirthday,
_spending_key_available: bool, spending_key_available: bool,
) -> Result<Self::Account, Self::Error> { ) -> Result<Self::Account, Self::Error> {
self.transactionally(|wdb| { self.transactionally(|wdb| {
wallet::add_account( wallet::add_account(
@ -662,6 +666,7 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
AccountSource::Imported, AccountSource::Imported,
wallet::ViewingKey::Full(Box::new(ufvk.to_owned())), wallet::ViewingKey::Full(Box::new(ufvk.to_owned())),
birthday, birthday,
spending_key_available,
) )
}) })
} }

View File

@ -344,6 +344,7 @@ pub(crate) fn add_account<P: consensus::Parameters>(
kind: AccountSource, kind: AccountSource,
viewing_key: ViewingKey, viewing_key: ViewingKey,
birthday: &AccountBirthday, birthday: &AccountBirthday,
spending_key_available: bool,
) -> Result<Account, SqliteClientError> { ) -> Result<Account, SqliteClientError> {
let (hd_seed_fingerprint, hd_account_index) = match kind { let (hd_seed_fingerprint, hd_account_index) = match kind {
AccountSource::Derived { AccountSource::Derived {
@ -381,14 +382,16 @@ pub(crate) fn add_account<P: consensus::Parameters>(
ufvk, uivk, ufvk, uivk,
orchard_fvk_item_cache, sapling_fvk_item_cache, p2pkh_fvk_item_cache, orchard_fvk_item_cache, sapling_fvk_item_cache, p2pkh_fvk_item_cache,
birthday_height, birthday_sapling_tree_size, birthday_orchard_tree_size, birthday_height, birthday_sapling_tree_size, birthday_orchard_tree_size,
recover_until_height recover_until_height,
has_spend_key
) )
VALUES ( VALUES (
:account_kind, :hd_seed_fingerprint, :hd_account_index, :account_kind, :hd_seed_fingerprint, :hd_account_index,
:ufvk, :uivk, :ufvk, :uivk,
:orchard_fvk_item_cache, :sapling_fvk_item_cache, :p2pkh_fvk_item_cache, :orchard_fvk_item_cache, :sapling_fvk_item_cache, :p2pkh_fvk_item_cache,
:birthday_height, :birthday_sapling_tree_size, :birthday_orchard_tree_size, :birthday_height, :birthday_sapling_tree_size, :birthday_orchard_tree_size,
:recover_until_height :recover_until_height,
:has_spend_key
) )
RETURNING id; RETURNING id;
"#, "#,
@ -404,7 +407,8 @@ pub(crate) fn add_account<P: consensus::Parameters>(
":birthday_height": u32::from(birthday.height()), ":birthday_height": u32::from(birthday.height()),
":birthday_sapling_tree_size": birthday_sapling_tree_size, ":birthday_sapling_tree_size": birthday_sapling_tree_size,
":birthday_orchard_tree_size": birthday_orchard_tree_size, ":birthday_orchard_tree_size": birthday_orchard_tree_size,
":recover_until_height": birthday.recover_until().map(u32::from) ":recover_until_height": birthday.recover_until().map(u32::from),
":has_spend_key": spending_key_available as i64,
], ],
|row| Ok(AccountId(row.get(0)?)), |row| Ok(AccountId(row.get(0)?)),
) )

View File

@ -36,6 +36,7 @@ CREATE TABLE "accounts" (
birthday_sapling_tree_size INTEGER, birthday_sapling_tree_size INTEGER,
birthday_orchard_tree_size INTEGER, birthday_orchard_tree_size INTEGER,
recover_until_height INTEGER, recover_until_height INTEGER,
has_spend_key INTEGER NOT NULL DEFAULT 1,
CHECK ( CHECK (
( (
account_kind = 0 account_kind = 0

View File

@ -14,6 +14,7 @@ mod receiving_key_scopes;
mod sapling_memo_consistency; mod sapling_memo_consistency;
mod sent_notes_to_internal; mod sent_notes_to_internal;
mod shardtree_support; mod shardtree_support;
mod spend_key_available;
mod ufvk_support; mod ufvk_support;
mod utxos_table; mod utxos_table;
mod utxos_to_txos; mod utxos_to_txos;
@ -63,8 +64,8 @@ pub(super) fn all_migrations<P: consensus::Parameters + 'static>(
// \ \ | v_transactions_note_uniqueness // \ \ | v_transactions_note_uniqueness
// \ \ | / // \ \ | /
// -------------------- full_account_ids // -------------------- full_account_ids
// | // | \
// orchard_received_notes // orchard_received_notes spend_key_available
// / \ // / \
// ensure_orchard_ua_receiver utxos_to_txos // ensure_orchard_ua_receiver utxos_to_txos
// | // |
@ -122,6 +123,7 @@ pub(super) fn all_migrations<P: consensus::Parameters + 'static>(
Box::new(ephemeral_addresses::Migration { Box::new(ephemeral_addresses::Migration {
params: params.clone(), params: params.clone(),
}), }),
Box::new(spend_key_available::Migration),
] ]
} }

View File

@ -0,0 +1,58 @@
//! The migration that records ephemeral addresses for each account.
use std::collections::HashSet;
use rusqlite;
use schemer;
use schemer_rusqlite::RusqliteMigration;
use uuid::Uuid;
use crate::wallet::init::WalletMigrationError;
use super::full_account_ids;
pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x07610aac_b0e3_4ba8_aaa6_cda606f0fd7b);
const DEPENDENCIES: [Uuid; 1] = [full_account_ids::MIGRATION_ID];
#[allow(dead_code)]
pub(super) struct Migration;
impl schemer::Migration for Migration {
fn id(&self) -> Uuid {
MIGRATION_ID
}
fn dependencies(&self) -> HashSet<Uuid> {
DEPENDENCIES.into_iter().collect()
}
fn description(&self) -> &'static str {
"Track which accounts have associated spending keys."
}
}
impl RusqliteMigration for Migration {
type Error = WalletMigrationError;
fn up(&self, transaction: &rusqlite::Transaction) -> Result<(), WalletMigrationError> {
transaction.execute_batch(
"ALTER TABLE accounts ADD COLUMN has_spend_key INTEGER NOT NULL DEFAULT 1",
)?;
Ok(())
}
fn down(&self, transaction: &rusqlite::Transaction) -> Result<(), WalletMigrationError> {
transaction.execute_batch("ALTER TABLE accounts DROP COLUMN has_spend_key")?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::wallet::init::migrations::tests::test_migrate;
#[test]
fn migrate() {
test_migrate(&[super::MIGRATION_ID]);
}
}