Skip to content

Commit 9b04a55

Browse files
committed
db: store derivation index also for addresses from the change desc
This doubles the storage required but there is no way around it if we want the poller to detect those coins without grinding.
1 parent 4f3daa7 commit 9b04a55

File tree

3 files changed

+53
-18
lines changed

3 files changed

+53
-18
lines changed

src/database/sqlite/mod.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,17 +238,22 @@ impl SqliteConn {
238238
// Update the address to derivation index mapping.
239239
// TODO: have this as a helper in descriptors.rs
240240
let next_la_index = next_index + LOOK_AHEAD_LIMIT - 1;
241-
let next_la_address = db_wallet
241+
let next_receive_address = db_wallet
242242
.main_descriptor
243243
.receive_descriptor()
244244
.derive(next_la_index.into(), secp)
245245
.address(network);
246-
db_tx
247-
.execute(
248-
"INSERT INTO addresses (address, derivation_index) VALUES (?1, ?2)",
249-
rusqlite::params![next_la_address.to_string(), next_la_index],
250-
)
251-
.map(|_| ())
246+
let next_change_address = db_wallet
247+
.main_descriptor
248+
.change_descriptor()
249+
.derive(next_la_index.into(), secp)
250+
.address(network);
251+
db_tx.execute(
252+
"INSERT INTO addresses (receive_address, change_address, derivation_index) VALUES (?1, ?2, ?3)",
253+
rusqlite::params![next_receive_address.to_string(), next_change_address.to_string(), next_la_index],
254+
)?;
255+
256+
Ok(())
252257
})
253258
.expect("Database must be available")
254259
}
@@ -363,7 +368,7 @@ impl SqliteConn {
363368
pub fn db_address(&mut self, address: &bitcoin::Address) -> Option<DbAddress> {
364369
db_query(
365370
&mut self.conn,
366-
"SELECT * FROM addresses WHERE address = ?1",
371+
"SELECT * FROM addresses WHERE receive_address = ?1 OR change_address = ?1",
367372
rusqlite::params![address.to_string()],
368373
|row| row.try_into(),
369374
)
@@ -721,6 +726,15 @@ mod tests {
721726
let db_addr = conn.db_address(&addr).unwrap();
722727
assert_eq!(db_addr.derivation_index, 0.into());
723728

729+
// And also for the change address
730+
let addr = options
731+
.main_descriptor
732+
.change_descriptor()
733+
.derive(0.into(), &secp)
734+
.address(options.bitcoind_network);
735+
let db_addr = conn.db_address(&addr).unwrap();
736+
assert_eq!(db_addr.derivation_index, 0.into());
737+
724738
// There is the index for the 199th index (look-ahead limit)
725739
let addr = options
726740
.main_descriptor
@@ -742,6 +756,15 @@ mod tests {
742756
conn.increment_derivation_index(&secp);
743757
let db_addr = conn.db_address(&addr).unwrap();
744758
assert_eq!(db_addr.derivation_index, 200.into());
759+
760+
// Same for the change descriptor.
761+
let addr = options
762+
.main_descriptor
763+
.change_descriptor()
764+
.derive(200.into(), &secp)
765+
.address(options.bitcoind_network);
766+
let db_addr = conn.db_address(&addr).unwrap();
767+
assert_eq!(db_addr.derivation_index, 200.into());
745768
}
746769

747770
fs::remove_dir_all(&tmp_dir).unwrap();

src/database/sqlite/schema.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ CREATE TABLE coins (
5757
* we can get the derivation index from the parent descriptor from bitcoind.
5858
*/
5959
CREATE TABLE addresses (
60-
address TEXT NOT NULL UNIQUE,
60+
receive_address TEXT NOT NULL UNIQUE,
61+
change_address TEXT NOT NULL UNIQUE,
6162
derivation_index INTEGER NOT NULL UNIQUE
6263
);
6364
@@ -195,23 +196,30 @@ impl TryFrom<&rusqlite::Row<'_>> for DbCoin {
195196

196197
#[derive(Debug, Clone, PartialEq, Eq)]
197198
pub struct DbAddress {
198-
pub address: bitcoin::Address,
199+
pub receive_address: bitcoin::Address,
200+
pub change_address: bitcoin::Address,
199201
pub derivation_index: bip32::ChildNumber,
200202
}
201203

202204
impl TryFrom<&rusqlite::Row<'_>> for DbAddress {
203205
type Error = rusqlite::Error;
204206

205207
fn try_from(row: &rusqlite::Row) -> Result<Self, Self::Error> {
206-
let address: String = row.get(0)?;
207-
let address = bitcoin::Address::from_str(&address).expect("We only store valid addresses");
208+
let receive_address: String = row.get(0)?;
209+
let receive_address =
210+
bitcoin::Address::from_str(&receive_address).expect("We only store valid addresses");
208211

209-
let derivation_index: u32 = row.get(1)?;
212+
let change_address: String = row.get(1)?;
213+
let change_address =
214+
bitcoin::Address::from_str(&change_address).expect("We only store valid addresses");
215+
216+
let derivation_index: u32 = row.get(2)?;
210217
let derivation_index = bip32::ChildNumber::from(derivation_index);
211218
assert!(derivation_index.is_normal());
212219

213220
Ok(DbAddress {
214-
address,
221+
receive_address,
222+
change_address,
215223
derivation_index,
216224
})
217225
}

src/database/sqlite/utils.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,19 @@ pub fn create_fresh_db(
9595
// necessarily 0.
9696
let mut query = String::with_capacity(100 * LOOK_AHEAD_LIMIT as usize);
9797
for index in 0..LOOK_AHEAD_LIMIT {
98-
// TODO: have this as a helper in descriptors.rs
99-
let address = options
98+
let receive_address = options
10099
.main_descriptor
101100
.receive_descriptor()
102101
.derive(index.into(), secp)
103102
.address(options.bitcoind_network);
103+
let change_address = options
104+
.main_descriptor
105+
.change_descriptor()
106+
.derive(index.into(), secp)
107+
.address(options.bitcoind_network);
104108
query += &format!(
105-
"INSERT INTO addresses (address, derivation_index) VALUES (\"{}\", {});\n",
106-
address, index
109+
"INSERT INTO addresses (receive_address, change_address, derivation_index) VALUES (\"{}\", \"{}\", {});\n",
110+
receive_address, change_address, index
107111
);
108112
}
109113

0 commit comments

Comments
 (0)