Add get_spendable_notes method to WalletRead
This commit is contained in:
parent
48f226f8b5
commit
011eda364f
|
@ -165,6 +165,13 @@ pub trait WalletRead {
|
||||||
/// with which they are associated.
|
/// with which they are associated.
|
||||||
fn get_nullifiers(&self) -> Result<Vec<(Nullifier, AccountId)>, Self::Error>;
|
fn get_nullifiers(&self) -> Result<Vec<(Nullifier, AccountId)>, Self::Error>;
|
||||||
|
|
||||||
|
/// Return all spendable notes.
|
||||||
|
fn get_spendable_notes(
|
||||||
|
&self,
|
||||||
|
account: AccountId,
|
||||||
|
anchor_height: BlockHeight,
|
||||||
|
) -> Result<Vec<SpendableNote>, Self::Error>;
|
||||||
|
|
||||||
/// Returns a list of spendable notes sufficient to cover the specified
|
/// Returns a list of spendable notes sufficient to cover the specified
|
||||||
/// target value, if possible.
|
/// target value, if possible.
|
||||||
fn select_spendable_notes(
|
fn select_spendable_notes(
|
||||||
|
|
|
@ -233,6 +233,15 @@ impl<P: consensus::Parameters> WalletRead for WalletDB<P> {
|
||||||
wallet::get_nullifiers(self).map_err(Error::Database)
|
wallet::get_nullifiers(self).map_err(Error::Database)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_spendable_notes(
|
||||||
|
&self,
|
||||||
|
account: AccountId,
|
||||||
|
anchor_height: BlockHeight,
|
||||||
|
) -> Result<Vec<SpendableNote>, Self::Error> {
|
||||||
|
wallet::transact::get_spendable_notes(self, account, anchor_height)
|
||||||
|
.map_err(Error::Database)
|
||||||
|
}
|
||||||
|
|
||||||
fn select_spendable_notes(
|
fn select_spendable_notes(
|
||||||
&self,
|
&self,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
@ -345,6 +354,14 @@ impl<'a, P: consensus::Parameters> WalletRead for DataConnStmtCache<'a, P> {
|
||||||
self.wallet_db.get_nullifiers()
|
self.wallet_db.get_nullifiers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_spendable_notes(
|
||||||
|
&self,
|
||||||
|
account: AccountId,
|
||||||
|
anchor_height: BlockHeight,
|
||||||
|
) -> Result<Vec<SpendableNote>, Self::Error> {
|
||||||
|
self.wallet_db.get_spendable_notes(account, anchor_height)
|
||||||
|
}
|
||||||
|
|
||||||
fn select_spendable_notes(
|
fn select_spendable_notes(
|
||||||
&self,
|
&self,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Functions for creating transactions.
|
//! Functions for creating transactions.
|
||||||
//!
|
//!
|
||||||
use rusqlite::named_params;
|
use rusqlite::{named_params, Row};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
|
@ -18,6 +18,77 @@ use zcash_client_backend::{
|
||||||
|
|
||||||
use crate::{error::SqliteClientError, WalletDB};
|
use crate::{error::SqliteClientError, WalletDB};
|
||||||
|
|
||||||
|
fn to_spendable_note(row: &Row) -> Result<SpendableNote, SqliteClientError> {
|
||||||
|
let diversifier = {
|
||||||
|
let d: Vec<_> = row.get(0)?;
|
||||||
|
if d.len() != 11 {
|
||||||
|
return Err(SqliteClientError::CorruptedData(
|
||||||
|
"Invalid diversifier length".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut tmp = [0; 11];
|
||||||
|
tmp.copy_from_slice(&d);
|
||||||
|
Diversifier(tmp)
|
||||||
|
};
|
||||||
|
|
||||||
|
let note_value = Amount::from_i64(row.get(1)?).unwrap();
|
||||||
|
|
||||||
|
let rseed = {
|
||||||
|
let rcm_bytes: Vec<_> = row.get(2)?;
|
||||||
|
|
||||||
|
// We store rcm directly in the data DB, regardless of whether the note
|
||||||
|
// used a v1 or v2 note plaintext, so for the purposes of spending let's
|
||||||
|
// pretend this is a pre-ZIP 212 note.
|
||||||
|
let rcm = jubjub::Fr::from_repr(
|
||||||
|
rcm_bytes[..]
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| SqliteClientError::InvalidNote)?,
|
||||||
|
)
|
||||||
|
.ok_or(SqliteClientError::InvalidNote)?;
|
||||||
|
Rseed::BeforeZip212(rcm)
|
||||||
|
};
|
||||||
|
|
||||||
|
let witness = {
|
||||||
|
let d: Vec<_> = row.get(3)?;
|
||||||
|
IncrementalWitness::read(&d[..])?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SpendableNote {
|
||||||
|
diversifier,
|
||||||
|
note_value,
|
||||||
|
rseed,
|
||||||
|
witness,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_spendable_notes<P>(
|
||||||
|
wdb: &WalletDB<P>,
|
||||||
|
account: AccountId,
|
||||||
|
anchor_height: BlockHeight,
|
||||||
|
) -> Result<Vec<SpendableNote>, SqliteClientError> {
|
||||||
|
let mut stmt_select_notes = wdb.conn.prepare(
|
||||||
|
"SELECT diversifier, value, rcm, witness
|
||||||
|
FROM received_notes
|
||||||
|
INNER JOIN transactions ON transactions.id_tx = received_notes.tx
|
||||||
|
INNER JOIN sapling_witnesses ON sapling_witnesses.note = received_notes.id_note
|
||||||
|
WHERE account = :account
|
||||||
|
AND spent IS NULL
|
||||||
|
AND transactions.block <= :anchor_height
|
||||||
|
AND sapling_witnesses.block = :anchor_height"
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Select notes
|
||||||
|
let notes = stmt_select_notes.query_and_then_named::<_, SqliteClientError, _>(
|
||||||
|
named_params![
|
||||||
|
":account": &i64::from(account.0),
|
||||||
|
":anchor_height": &u32::from(anchor_height),
|
||||||
|
],
|
||||||
|
to_spendable_note
|
||||||
|
)?;
|
||||||
|
|
||||||
|
notes.collect::<Result<_, _>>()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn select_spendable_notes<P>(
|
pub fn select_spendable_notes<P>(
|
||||||
wdb: &WalletDB<P>,
|
wdb: &WalletDB<P>,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
@ -71,52 +142,10 @@ pub fn select_spendable_notes<P>(
|
||||||
":anchor_height": &u32::from(anchor_height),
|
":anchor_height": &u32::from(anchor_height),
|
||||||
":target_value": &i64::from(target_value),
|
":target_value": &i64::from(target_value),
|
||||||
],
|
],
|
||||||
|row| {
|
to_spendable_note
|
||||||
let diversifier = {
|
|
||||||
let d: Vec<_> = row.get(0)?;
|
|
||||||
if d.len() != 11 {
|
|
||||||
return Err(SqliteClientError::CorruptedData(
|
|
||||||
"Invalid diversifier length".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let mut tmp = [0; 11];
|
|
||||||
tmp.copy_from_slice(&d);
|
|
||||||
Diversifier(tmp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let note_value = Amount::from_i64(row.get(1)?).unwrap();
|
|
||||||
|
|
||||||
let rseed = {
|
|
||||||
let rcm_bytes: Vec<_> = row.get(2)?;
|
|
||||||
|
|
||||||
// We store rcm directly in the data DB, regardless of whether the note
|
|
||||||
// used a v1 or v2 note plaintext, so for the purposes of spending let's
|
|
||||||
// pretend this is a pre-ZIP 212 note.
|
|
||||||
let rcm = jubjub::Fr::from_repr(
|
|
||||||
rcm_bytes[..]
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| SqliteClientError::InvalidNote)?,
|
|
||||||
)
|
|
||||||
.ok_or(SqliteClientError::InvalidNote)?;
|
|
||||||
Rseed::BeforeZip212(rcm)
|
|
||||||
};
|
|
||||||
|
|
||||||
let witness = {
|
|
||||||
let d: Vec<_> = row.get(3)?;
|
|
||||||
IncrementalWitness::read(&d[..])?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(SpendableNote {
|
|
||||||
diversifier,
|
|
||||||
note_value,
|
|
||||||
rseed,
|
|
||||||
witness,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let notes: Vec<SpendableNote> = notes.collect::<Result<_, _>>()?;
|
notes.collect::<Result<_, _>>()
|
||||||
Ok(notes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue