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 mut db_conn = self.db.connection();
|
||||||
let index = db_conn.derivation_index();
|
let index = db_conn.derivation_index();
|
||||||
// TODO: handle should we wrap around instead of failing?
|
// 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
|
let address = self
|
||||||
.config
|
.config
|
||||||
.main_descriptor
|
.main_descriptor
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use crate::{
|
|||||||
|
|
||||||
use std::{collections::HashMap, sync};
|
use std::{collections::HashMap, sync};
|
||||||
|
|
||||||
use miniscript::bitcoin::{self, util::bip32};
|
use miniscript::bitcoin::{self, secp256k1, util::bip32};
|
||||||
|
|
||||||
pub trait DatabaseInterface: Send {
|
pub trait DatabaseInterface: Send {
|
||||||
fn connection(&self) -> Box<dyn DatabaseConnection>;
|
fn connection(&self) -> Box<dyn DatabaseConnection>;
|
||||||
@ -44,7 +44,7 @@ pub trait DatabaseConnection {
|
|||||||
|
|
||||||
fn derivation_index(&mut self) -> bip32::ChildNumber;
|
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.
|
/// Get all UTxOs.
|
||||||
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
|
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
|
||||||
@ -83,8 +83,8 @@ impl DatabaseConnection for SqliteConn {
|
|||||||
self.db_wallet().deposit_derivation_index
|
self.db_wallet().deposit_derivation_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
fn increment_derivation_index(&mut self, secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>) {
|
||||||
self.update_derivation_index(index)
|
self.increment_derivation_index(secp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
|
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use crate::{
|
|||||||
database::{
|
database::{
|
||||||
sqlite::{
|
sqlite::{
|
||||||
schema::{DbAddress, DbCoin, DbTip, DbWallet},
|
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,
|
Coin,
|
||||||
},
|
},
|
||||||
@ -23,8 +23,8 @@ use crate::{
|
|||||||
use std::{convert::TryInto, fmt, io, path};
|
use std::{convert::TryInto, fmt, io, path};
|
||||||
|
|
||||||
use miniscript::{
|
use miniscript::{
|
||||||
bitcoin::{self, secp256k1, util::bip32},
|
bitcoin::{self, secp256k1},
|
||||||
Descriptor, DescriptorPublicKey,
|
Descriptor, DescriptorPublicKey, DescriptorTrait, TranslatePk2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DB_VERSION: i64 = 0;
|
const DB_VERSION: i64 = 0;
|
||||||
@ -207,15 +207,47 @@ impl SqliteConn {
|
|||||||
.expect("Database must be available")
|
.expect("Database must be available")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the deposit derivation index.
|
pub fn increment_derivation_index(
|
||||||
pub fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
&mut self,
|
||||||
let new_index: u32 = index.into();
|
secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>,
|
||||||
|
) {
|
||||||
|
let network = self.db_tip().network;
|
||||||
|
|
||||||
db_exec(&mut self.conn, |db_tx| {
|
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
|
// 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
|
db_tx
|
||||||
.execute(
|
.execute(
|
||||||
"UPDATE wallets SET deposit_derivation_index = (?1)",
|
"INSERT INTO addresses (address, derivation_index) VALUES (?1, ?2)",
|
||||||
rusqlite::params![new_index],
|
rusqlite::params![next_la_address.to_string(), next_la_index],
|
||||||
)
|
)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
})
|
})
|
||||||
@ -311,7 +343,7 @@ mod tests {
|
|||||||
use crate::testutils::*;
|
use crate::testutils::*;
|
||||||
use std::{collections::HashSet, fs, path, str::FromStr};
|
use std::{collections::HashSet, fs, path, str::FromStr};
|
||||||
|
|
||||||
use bitcoin::hashes::Hash;
|
use bitcoin::{hashes::Hash, util::bip32};
|
||||||
use miniscript::{DescriptorTrait, TranslatePk2};
|
use miniscript::{DescriptorTrait, TranslatePk2};
|
||||||
|
|
||||||
fn dummy_options() -> FreshDbOptions {
|
fn dummy_options() -> FreshDbOptions {
|
||||||
@ -518,6 +550,11 @@ mod tests {
|
|||||||
.address(options.bitcoind_network)
|
.address(options.bitcoind_network)
|
||||||
.expect("Always a P2WSH address");
|
.expect("Always a P2WSH address");
|
||||||
assert!(conn.db_address(&addr).is_none());
|
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();
|
fs::remove_dir_all(&tmp_dir).unwrap();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use std::{convert::TryInto, fs, path, time};
|
|||||||
|
|
||||||
use miniscript::{bitcoin::secp256k1, DescriptorTrait, TranslatePk2};
|
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
|
/// 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>
|
pub fn db_exec<F>(conn: &mut rusqlite::Connection, modifications: F) -> Result<(), rusqlite::Error>
|
||||||
@ -16,6 +16,27 @@ where
|
|||||||
tx.commit()
|
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
|
/// Internal helper for queries boilerplate
|
||||||
pub fn db_query<P, F, T>(
|
pub fn db_query<P, F, T>(
|
||||||
conn: &mut rusqlite::Connection,
|
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 std::{collections::HashMap, env, fs, io, path, process, str::FromStr, sync, thread, time};
|
||||||
|
|
||||||
use miniscript::{
|
use miniscript::{
|
||||||
bitcoin::{self, util::bip32},
|
bitcoin::{self, secp256k1, util::bip32},
|
||||||
descriptor,
|
descriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,8 +97,9 @@ impl DatabaseConnection for DummyDbConn {
|
|||||||
self.db.read().unwrap().curr_index
|
self.db.read().unwrap().curr_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_derivation_index(&mut self, index: bip32::ChildNumber) {
|
fn increment_derivation_index(&mut self, _: &secp256k1::Secp256k1<secp256k1::VerifyOnly>) {
|
||||||
self.db.write().unwrap().curr_index = index;
|
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> {
|
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user