zcash_client_backend: Remove account from `UnifiedFullViewingKey`
The account number is not stored in the ZIP 316 UFVK encoding, and in general won't necessarily be known (e.g. if a UFVK is being imported into a wallet). `zcash_client_sqlite::wallet::init::init_accounts_table` reverts to its previous behaviour of requiring the provided `&[UnifiedFullViewingKey]` to be indexed by account number.
This commit is contained in:
parent
1ce289e568
commit
d8b860207d
|
@ -107,7 +107,6 @@ impl UnifiedSpendingKey {
|
||||||
|
|
||||||
pub fn to_unified_full_viewing_key(&self) -> UnifiedFullViewingKey {
|
pub fn to_unified_full_viewing_key(&self) -> UnifiedFullViewingKey {
|
||||||
UnifiedFullViewingKey {
|
UnifiedFullViewingKey {
|
||||||
account: self.account,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent: Some(self.transparent.to_account_pubkey()),
|
transparent: Some(self.transparent.to_account_pubkey()),
|
||||||
sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling)),
|
sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling)),
|
||||||
|
@ -137,7 +136,6 @@ impl UnifiedSpendingKey {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct UnifiedFullViewingKey {
|
pub struct UnifiedFullViewingKey {
|
||||||
account: AccountId,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent: Option<legacy::AccountPubKey>,
|
transparent: Option<legacy::AccountPubKey>,
|
||||||
// TODO: This type is invalid for a UFVK; create a `sapling::DiversifiableFullViewingKey`
|
// TODO: This type is invalid for a UFVK; create a `sapling::DiversifiableFullViewingKey`
|
||||||
|
@ -149,7 +147,6 @@ pub struct UnifiedFullViewingKey {
|
||||||
impl UnifiedFullViewingKey {
|
impl UnifiedFullViewingKey {
|
||||||
/// Construct a new unified full viewing key, if the required components are present.
|
/// Construct a new unified full viewing key, if the required components are present.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
account: AccountId,
|
|
||||||
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
|
#[cfg(feature = "transparent-inputs")] transparent: Option<legacy::AccountPubKey>,
|
||||||
sapling: Option<sapling::ExtendedFullViewingKey>,
|
sapling: Option<sapling::ExtendedFullViewingKey>,
|
||||||
) -> Option<UnifiedFullViewingKey> {
|
) -> Option<UnifiedFullViewingKey> {
|
||||||
|
@ -157,7 +154,6 @@ impl UnifiedFullViewingKey {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(UnifiedFullViewingKey {
|
Some(UnifiedFullViewingKey {
|
||||||
account,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent,
|
transparent,
|
||||||
sapling,
|
sapling,
|
||||||
|
@ -167,11 +163,7 @@ impl UnifiedFullViewingKey {
|
||||||
|
|
||||||
/// Attempts to decode the given string as an encoding of a `UnifiedFullViewingKey`
|
/// Attempts to decode the given string as an encoding of a `UnifiedFullViewingKey`
|
||||||
/// for the given network.
|
/// for the given network.
|
||||||
pub fn decode<P: consensus::Parameters>(
|
pub fn decode<P: consensus::Parameters>(params: &P, encoding: &str) -> Result<Self, String> {
|
||||||
params: &P,
|
|
||||||
encoding: &str,
|
|
||||||
account: AccountId,
|
|
||||||
) -> Result<Self, String> {
|
|
||||||
encoding
|
encoding
|
||||||
.strip_prefix("DONOTUSEUFVK")
|
.strip_prefix("DONOTUSEUFVK")
|
||||||
.and_then(|data| hex::decode(data).ok())
|
.and_then(|data| hex::decode(data).ok())
|
||||||
|
@ -199,7 +191,6 @@ impl UnifiedFullViewingKey {
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
account,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent,
|
transparent,
|
||||||
sapling,
|
sapling,
|
||||||
|
@ -227,12 +218,6 @@ impl UnifiedFullViewingKey {
|
||||||
format!("DONOTUSEUFVK{}", hex::encode(&ufvk))
|
format!("DONOTUSEUFVK{}", hex::encode(&ufvk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the ZIP32 account identifier to which all component
|
|
||||||
/// keys are related.
|
|
||||||
pub fn account(&self) -> AccountId {
|
|
||||||
self.account
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the transparent component of the unified key at the
|
/// Returns the transparent component of the unified key at the
|
||||||
/// BIP44 path `m/44'/<coin_type>'/<account>'`.
|
/// BIP44 path `m/44'/<coin_type>'/<account>'`.
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
@ -370,7 +355,6 @@ mod tests {
|
||||||
let transparent = { None };
|
let transparent = { None };
|
||||||
|
|
||||||
let ufvk = UnifiedFullViewingKey::new(
|
let ufvk = UnifiedFullViewingKey::new(
|
||||||
account,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
transparent,
|
transparent,
|
||||||
sapling,
|
sapling,
|
||||||
|
@ -378,8 +362,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let encoding = ufvk.encode(&MAIN_NETWORK);
|
let encoding = ufvk.encode(&MAIN_NETWORK);
|
||||||
let decoded = UnifiedFullViewingKey::decode(&MAIN_NETWORK, &encoding, account).unwrap();
|
let decoded = UnifiedFullViewingKey::decode(&MAIN_NETWORK, &encoding).unwrap();
|
||||||
assert_eq!(decoded.account, ufvk.account);
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
decoded.transparent.map(|t| t.serialize()),
|
decoded.transparent.map(|t| t.serialize()),
|
||||||
|
|
|
@ -802,7 +802,6 @@ mod tests {
|
||||||
let taddr = None;
|
let taddr = None;
|
||||||
|
|
||||||
let ufvk = UnifiedFullViewingKey::new(
|
let ufvk = UnifiedFullViewingKey::new(
|
||||||
account,
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
tkey,
|
tkey,
|
||||||
Some(extfvk.clone()),
|
Some(extfvk.clone()),
|
||||||
|
|
|
@ -208,7 +208,7 @@ pub(crate) fn get_unified_full_viewing_keys<P: consensus::Parameters>(
|
||||||
let acct: u32 = row.get(0)?;
|
let acct: u32 = row.get(0)?;
|
||||||
let account = AccountId::from(acct);
|
let account = AccountId::from(acct);
|
||||||
let ufvk_str: String = row.get(1)?;
|
let ufvk_str: String = row.get(1)?;
|
||||||
let ufvk = UnifiedFullViewingKey::decode(&wdb.params, &ufvk_str, account)
|
let ufvk = UnifiedFullViewingKey::decode(&wdb.params, &ufvk_str)
|
||||||
.map_err(SqliteClientError::CorruptedData);
|
.map_err(SqliteClientError::CorruptedData);
|
||||||
|
|
||||||
Ok((account, ufvk))
|
Ok((account, ufvk))
|
||||||
|
@ -240,7 +240,7 @@ pub fn is_valid_account_extfvk<P: consensus::Parameters>(
|
||||||
.prepare("SELECT ufvk FROM accounts WHERE account = ?")?
|
.prepare("SELECT ufvk FROM accounts WHERE account = ?")?
|
||||||
.query_row(&[u32::from(account).to_sql()?], |row| {
|
.query_row(&[u32::from(account).to_sql()?], |row| {
|
||||||
row.get(0).map(|ufvk_str: String| {
|
row.get(0).map(|ufvk_str: String| {
|
||||||
UnifiedFullViewingKey::decode(&wdb.params, &ufvk_str, account)
|
UnifiedFullViewingKey::decode(&wdb.params, &ufvk_str)
|
||||||
.map_err(SqliteClientError::CorruptedData)
|
.map_err(SqliteClientError::CorruptedData)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -180,7 +180,7 @@ pub fn init_wallet_db<P>(wdb: &WalletDb<P>) -> Result<(), rusqlite::Error> {
|
||||||
/// let account = AccountId::from(0);
|
/// let account = AccountId::from(0);
|
||||||
/// let extsk = sapling::spending_key(&seed, Network::TestNetwork.coin_type(), account);
|
/// let extsk = sapling::spending_key(&seed, Network::TestNetwork.coin_type(), account);
|
||||||
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
|
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
/// let ufvk = UnifiedFullViewingKey::new(account, None, Some(extfvk)).unwrap();
|
/// let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
|
||||||
/// init_accounts_table(&db_data, &[ufvk]).unwrap();
|
/// init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -199,7 +199,7 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
||||||
|
|
||||||
// Insert accounts atomically
|
// Insert accounts atomically
|
||||||
wdb.conn.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
|
wdb.conn.execute("BEGIN IMMEDIATE", NO_PARAMS)?;
|
||||||
for key in keys.iter() {
|
for (account, key) in (0u32..).zip(keys) {
|
||||||
let ufvk_str: String = key.encode(&wdb.params);
|
let ufvk_str: String = key.encode(&wdb.params);
|
||||||
let address_str: String = key.default_address().0.encode(&wdb.params);
|
let address_str: String = key.default_address().0.encode(&wdb.params);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
@ -214,12 +214,7 @@ pub fn init_accounts_table<P: consensus::Parameters>(
|
||||||
wdb.conn.execute(
|
wdb.conn.execute(
|
||||||
"INSERT INTO accounts (account, ufvk, address, transparent_address)
|
"INSERT INTO accounts (account, ufvk, address, transparent_address)
|
||||||
VALUES (?, ?, ?, ?)",
|
VALUES (?, ?, ?, ?)",
|
||||||
params![
|
params![account, ufvk_str, address_str, taddress_str],
|
||||||
u32::from(key.account()),
|
|
||||||
ufvk_str,
|
|
||||||
address_str,
|
|
||||||
taddress_str,
|
|
||||||
],
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
wdb.conn.execute("COMMIT", NO_PARAMS)?;
|
wdb.conn.execute("COMMIT", NO_PARAMS)?;
|
||||||
|
@ -328,7 +323,6 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk = UnifiedFullViewingKey::new(
|
let ufvk = UnifiedFullViewingKey::new(
|
||||||
account,
|
|
||||||
Some(
|
Some(
|
||||||
transparent::AccountPrivKey::from_seed(&network(), &seed, account)
|
transparent::AccountPrivKey::from_seed(&network(), &seed, account)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -339,7 +333,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(account, Some(extfvk)).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
|
||||||
|
|
||||||
init_accounts_table(&db_data, &[ufvk.clone()]).unwrap();
|
init_accounts_table(&db_data, &[ufvk.clone()]).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -219,24 +219,14 @@ mod tests {
|
||||||
transparent::AccountPrivKey::from_seed(&network(), &[1u8; 32], AccountId::from(1))
|
transparent::AccountPrivKey::from_seed(&network(), &[1u8; 32], AccountId::from(1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
[
|
[
|
||||||
UnifiedFullViewingKey::new(
|
UnifiedFullViewingKey::new(Some(tsk0.to_account_pubkey()), Some(extfvk0)).unwrap(),
|
||||||
AccountId::from(0),
|
UnifiedFullViewingKey::new(Some(tsk1.to_account_pubkey()), Some(extfvk1)).unwrap(),
|
||||||
Some(tsk0.to_account_pubkey()),
|
|
||||||
Some(extfvk0),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
UnifiedFullViewingKey::new(
|
|
||||||
AccountId::from(1),
|
|
||||||
Some(tsk1.to_account_pubkey()),
|
|
||||||
Some(extfvk1),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvks = [
|
let ufvks = [
|
||||||
UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk0)).unwrap(),
|
UnifiedFullViewingKey::new(Some(extfvk0)).unwrap(),
|
||||||
UnifiedFullViewingKey::new(AccountId::from(1), Some(extfvk1)).unwrap(),
|
UnifiedFullViewingKey::new(Some(extfvk1)).unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
init_accounts_table(&db_data, &ufvks).unwrap();
|
init_accounts_table(&db_data, &ufvks).unwrap();
|
||||||
|
@ -288,9 +278,9 @@ mod tests {
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk)).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk)).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
let to = extsk.default_address().1.into();
|
let to = extsk.default_address().1.into();
|
||||||
|
|
||||||
|
@ -331,9 +321,9 @@ mod tests {
|
||||||
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk)).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap();
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk)).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
let to = extsk.default_address().1.into();
|
let to = extsk.default_address().1.into();
|
||||||
|
|
||||||
|
@ -379,10 +369,9 @@ mod tests {
|
||||||
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk =
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
|
||||||
UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk.clone())).unwrap();
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk.clone())).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
|
@ -523,10 +512,9 @@ mod tests {
|
||||||
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk =
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
|
||||||
UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk.clone())).unwrap();
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk.clone())).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
|
@ -653,10 +641,9 @@ mod tests {
|
||||||
let extsk = sapling::spending_key(&[0u8; 32], network.coin_type(), AccountId::from(0));
|
let extsk = sapling::spending_key(&[0u8; 32], network.coin_type(), AccountId::from(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk =
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
|
||||||
UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk.clone())).unwrap();
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk.clone())).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
|
@ -764,10 +751,9 @@ mod tests {
|
||||||
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0));
|
||||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let ufvk =
|
let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap();
|
||||||
UnifiedFullViewingKey::new(AccountId::from(0), None, Some(extfvk.clone())).unwrap();
|
|
||||||
#[cfg(not(feature = "transparent-inputs"))]
|
#[cfg(not(feature = "transparent-inputs"))]
|
||||||
let ufvk = UnifiedFullViewingKey::new(AccountId::from(0), Some(extfvk.clone())).unwrap();
|
let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap();
|
||||||
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
init_accounts_table(&db_data, &[ufvk]).unwrap();
|
||||||
|
|
||||||
// Add funds to the wallet in a single note
|
// Add funds to the wallet in a single note
|
||||||
|
|
Loading…
Reference in New Issue