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:
Antoine Poinsot 2022-08-16 15:43:16 +02:00
parent e74ea4c2d3
commit 3f17e9f0c3
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
5 changed files with 77 additions and 18 deletions

View File

@ -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

View File

@ -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> {

View File

@ -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();

View File

@ -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,

View File

@ -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> {