database: change interface from update_der_index to increment_der_index
And take care of updating the (addr->index) mapping in the SQLite implementation.
This commit is contained in:
parent
e74ea4c2d3
commit
3f17e9f0c3
@ -31,7 +31,7 @@ impl DaemonControl {
|
||||
let mut db_conn = self.db.connection();
|
||||
let index = db_conn.derivation_index();
|
||||
// TODO: handle should we wrap around instead of failing?
|
||||
db_conn.update_derivation_index(index.increment().expect("TODO: handle wraparound"));
|
||||
db_conn.increment_derivation_index(&self.secp);
|
||||
let address = self
|
||||
.config
|
||||
.main_descriptor
|
||||
|
||||
@ -13,7 +13,7 @@ use crate::{
|
||||
|
||||
use std::{collections::HashMap, sync};
|
||||
|
||||
use miniscript::bitcoin::{self, util::bip32};
|
||||
use miniscript::bitcoin::{self, secp256k1, util::bip32};
|
||||
|
||||
pub trait DatabaseInterface: Send {
|
||||
fn connection(&self) -> Box<dyn DatabaseConnection>;
|
||||
@ -44,7 +44,7 @@ pub trait DatabaseConnection {
|
||||
|
||||
fn derivation_index(&mut self) -> bip32::ChildNumber;
|
||||
|
||||
fn update_derivation_index(&mut self, index: bip32::ChildNumber);
|
||||
fn increment_derivation_index(&mut self, secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>);
|
||||
|
||||
/// Get all UTxOs.
|
||||
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
|
||||
@ -83,8 +83,8 @@ impl DatabaseConnection for SqliteConn {
|
||||
self.db_wallet().deposit_derivation_index
|
||||
}
|
||||
|
||||
fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
||||
self.update_derivation_index(index)
|
||||
fn increment_derivation_index(&mut self, secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>) {
|
||||
self.increment_derivation_index(secp)
|
||||
}
|
||||
|
||||
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
|
||||
|
||||
@ -14,7 +14,7 @@ use crate::{
|
||||
database::{
|
||||
sqlite::{
|
||||
schema::{DbAddress, DbCoin, DbTip, DbWallet},
|
||||
utils::{create_fresh_db, db_exec, db_query},
|
||||
utils::{create_fresh_db, db_exec, db_query, db_tx_query, LOOK_AHEAD_LIMIT},
|
||||
},
|
||||
Coin,
|
||||
},
|
||||
@ -23,8 +23,8 @@ use crate::{
|
||||
use std::{convert::TryInto, fmt, io, path};
|
||||
|
||||
use miniscript::{
|
||||
bitcoin::{self, secp256k1, util::bip32},
|
||||
Descriptor, DescriptorPublicKey,
|
||||
bitcoin::{self, secp256k1},
|
||||
Descriptor, DescriptorPublicKey, DescriptorTrait, TranslatePk2,
|
||||
};
|
||||
|
||||
const DB_VERSION: i64 = 0;
|
||||
@ -207,15 +207,47 @@ impl SqliteConn {
|
||||
.expect("Database must be available")
|
||||
}
|
||||
|
||||
/// Update the deposit derivation index.
|
||||
pub fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
||||
let new_index: u32 = index.into();
|
||||
pub fn increment_derivation_index(
|
||||
&mut self,
|
||||
secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>,
|
||||
) {
|
||||
let network = self.db_tip().network;
|
||||
|
||||
db_exec(&mut self.conn, |db_tx| {
|
||||
let db_wallet: DbWallet = db_tx_query(
|
||||
&db_tx,
|
||||
"SELECT * FROM wallets",
|
||||
rusqlite::params![],
|
||||
|row| row.try_into(),
|
||||
)
|
||||
.expect("Db must not fail")
|
||||
.pop()
|
||||
.expect("There is always a row in the wallet table");
|
||||
let next_index: u32 = db_wallet
|
||||
.deposit_derivation_index
|
||||
.increment()
|
||||
.expect("Must not get in hardened territory")
|
||||
.into();
|
||||
// NOTE: should be updated if we ever have multi-wallet support
|
||||
db_tx.execute(
|
||||
"UPDATE wallets SET deposit_derivation_index = (?1)",
|
||||
rusqlite::params![next_index],
|
||||
)?;
|
||||
|
||||
// Update the address to derivation index mapping.
|
||||
// TODO: have this as a helper in descriptors.rs
|
||||
let next_la_index = next_index + LOOK_AHEAD_LIMIT - 1;
|
||||
let next_la_address = db_wallet
|
||||
.main_descriptor
|
||||
.derive(next_la_index)
|
||||
.translate_pk2(|xpk| xpk.derive_public_key(secp))
|
||||
.expect("All pubkeys were derived, no wildcard.")
|
||||
.address(network)
|
||||
.expect("It's a wsh() descriptor");
|
||||
db_tx
|
||||
.execute(
|
||||
"UPDATE wallets SET deposit_derivation_index = (?1)",
|
||||
rusqlite::params![new_index],
|
||||
"INSERT INTO addresses (address, derivation_index) VALUES (?1, ?2)",
|
||||
rusqlite::params![next_la_address.to_string(), next_la_index],
|
||||
)
|
||||
.map(|_| ())
|
||||
})
|
||||
@ -311,7 +343,7 @@ mod tests {
|
||||
use crate::testutils::*;
|
||||
use std::{collections::HashSet, fs, path, str::FromStr};
|
||||
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::{hashes::Hash, util::bip32};
|
||||
use miniscript::{DescriptorTrait, TranslatePk2};
|
||||
|
||||
fn dummy_options() -> FreshDbOptions {
|
||||
@ -518,6 +550,11 @@ mod tests {
|
||||
.address(options.bitcoind_network)
|
||||
.expect("Always a P2WSH address");
|
||||
assert!(conn.db_address(&addr).is_none());
|
||||
|
||||
// But if we increment the deposit derivation index, the 200th one will be there.
|
||||
conn.increment_derivation_index(&secp);
|
||||
let db_addr = conn.db_address(&addr).unwrap();
|
||||
assert_eq!(db_addr.derivation_index, 200.into());
|
||||
}
|
||||
|
||||
fs::remove_dir_all(&tmp_dir).unwrap();
|
||||
|
||||
@ -4,7 +4,7 @@ use std::{convert::TryInto, fs, path, time};
|
||||
|
||||
use miniscript::{bitcoin::secp256k1, DescriptorTrait, TranslatePk2};
|
||||
|
||||
const LOOK_AHEAD_LIMIT: u32 = 200;
|
||||
pub const LOOK_AHEAD_LIMIT: u32 = 200;
|
||||
|
||||
/// Perform a set of modifications to the database inside a single transaction
|
||||
pub fn db_exec<F>(conn: &mut rusqlite::Connection, modifications: F) -> Result<(), rusqlite::Error>
|
||||
@ -16,6 +16,27 @@ where
|
||||
tx.commit()
|
||||
}
|
||||
|
||||
/// Internal helper for queries boilerplate
|
||||
pub fn db_tx_query<P, F, T>(
|
||||
tx: &rusqlite::Transaction,
|
||||
stmt_str: &str,
|
||||
params: P,
|
||||
f: F,
|
||||
) -> Result<Vec<T>, rusqlite::Error>
|
||||
where
|
||||
P: IntoIterator + rusqlite::Params,
|
||||
P::Item: rusqlite::ToSql,
|
||||
F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>,
|
||||
{
|
||||
// rustc says 'borrowed value does not live long enough'
|
||||
let x = tx
|
||||
.prepare(stmt_str)?
|
||||
.query_map(params, f)?
|
||||
.collect::<rusqlite::Result<Vec<T>>>();
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
/// Internal helper for queries boilerplate
|
||||
pub fn db_query<P, F, T>(
|
||||
conn: &mut rusqlite::Connection,
|
||||
|
||||
@ -8,7 +8,7 @@ use crate::{
|
||||
use std::{collections::HashMap, env, fs, io, path, process, str::FromStr, sync, thread, time};
|
||||
|
||||
use miniscript::{
|
||||
bitcoin::{self, util::bip32},
|
||||
bitcoin::{self, secp256k1, util::bip32},
|
||||
descriptor,
|
||||
};
|
||||
|
||||
@ -97,8 +97,9 @@ impl DatabaseConnection for DummyDbConn {
|
||||
self.db.read().unwrap().curr_index
|
||||
}
|
||||
|
||||
fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
||||
self.db.write().unwrap().curr_index = index;
|
||||
fn increment_derivation_index(&mut self, _: &secp256k1::Secp256k1<secp256k1::VerifyOnly>) {
|
||||
let next_index = self.db.write().unwrap().curr_index.increment().unwrap();
|
||||
self.db.write().unwrap().curr_index = next_index;
|
||||
}
|
||||
|
||||
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user