db: record whether a coin was received on a change address
So we know what descriptor to use when spending it.
This commit is contained in:
parent
9b04a55147
commit
58a0e57c59
@ -35,7 +35,9 @@ fn update_coins(
|
||||
// Start by fetching newly received coins.
|
||||
let mut received = Vec::new();
|
||||
for utxo in bit.received_coins(previous_tip, descs) {
|
||||
if let Some(derivation_index) = db_conn.derivation_index_by_address(&utxo.address) {
|
||||
if let Some((derivation_index, is_change)) =
|
||||
db_conn.derivation_index_by_address(&utxo.address)
|
||||
{
|
||||
if !curr_coins.contains_key(&utxo.outpoint) {
|
||||
let UTxO {
|
||||
outpoint, amount, ..
|
||||
@ -44,6 +46,7 @@ fn update_coins(
|
||||
outpoint,
|
||||
amount,
|
||||
derivation_index,
|
||||
is_change,
|
||||
block_height: None,
|
||||
block_time: None,
|
||||
spend_txid: None,
|
||||
|
||||
@ -627,6 +627,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(100_000),
|
||||
derivation_index: bip32::ChildNumber::from(13),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
}]);
|
||||
@ -721,6 +722,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(100_000),
|
||||
derivation_index: bip32::ChildNumber::from(13),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
},
|
||||
@ -730,6 +732,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(115_680),
|
||||
derivation_index: bip32::ChildNumber::from(34),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
},
|
||||
|
||||
@ -49,10 +49,11 @@ pub trait DatabaseConnection {
|
||||
|
||||
fn increment_derivation_index(&mut self, secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>);
|
||||
|
||||
/// Get the derivation index for this address, as well as whether this address is change.
|
||||
fn derivation_index_by_address(
|
||||
&mut self,
|
||||
address: &bitcoin::Address,
|
||||
) -> Option<bip32::ChildNumber>;
|
||||
) -> Option<(bip32::ChildNumber, bool)>;
|
||||
|
||||
/// Get all our coins, past or present, spent or not.
|
||||
fn coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
|
||||
@ -154,9 +155,9 @@ impl DatabaseConnection for SqliteConn {
|
||||
fn derivation_index_by_address(
|
||||
&mut self,
|
||||
address: &bitcoin::Address,
|
||||
) -> Option<bip32::ChildNumber> {
|
||||
) -> Option<(bip32::ChildNumber, bool)> {
|
||||
self.db_address(address)
|
||||
.map(|db_addr| db_addr.derivation_index)
|
||||
.map(|db_addr| (db_addr.derivation_index, address == &db_addr.change_address))
|
||||
}
|
||||
|
||||
fn coins_by_outpoints(
|
||||
@ -215,6 +216,7 @@ pub struct Coin {
|
||||
pub block_time: Option<u32>,
|
||||
pub amount: bitcoin::Amount,
|
||||
pub derivation_index: bip32::ChildNumber,
|
||||
pub is_change: bool,
|
||||
pub spend_txid: Option<bitcoin::Txid>,
|
||||
pub spend_block: Option<SpendBlock>,
|
||||
}
|
||||
@ -227,6 +229,7 @@ impl std::convert::From<DbCoin> for Coin {
|
||||
block_time,
|
||||
amount,
|
||||
derivation_index,
|
||||
is_change,
|
||||
spend_txid,
|
||||
spend_block,
|
||||
..
|
||||
@ -237,6 +240,7 @@ impl std::convert::From<DbCoin> for Coin {
|
||||
block_time,
|
||||
amount,
|
||||
derivation_index,
|
||||
is_change,
|
||||
spend_txid,
|
||||
spend_block: spend_block.map(SpendBlock::from),
|
||||
}
|
||||
|
||||
@ -288,14 +288,15 @@ impl SqliteConn {
|
||||
for coin in coins {
|
||||
let deriv_index: u32 = coin.derivation_index.into();
|
||||
db_tx.execute(
|
||||
"INSERT INTO coins (wallet_id, txid, vout, amount_sat, derivation_index) \
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
"INSERT INTO coins (wallet_id, txid, vout, amount_sat, derivation_index, is_change) \
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
|
||||
rusqlite::params![
|
||||
WALLET_ID,
|
||||
coin.outpoint.txid.to_vec(),
|
||||
coin.outpoint.vout,
|
||||
coin.amount.to_sat(),
|
||||
deriv_index,
|
||||
coin.is_change,
|
||||
],
|
||||
)?;
|
||||
}
|
||||
@ -607,6 +608,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(10).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
};
|
||||
@ -618,7 +620,7 @@ mod tests {
|
||||
assert_eq!(coins.len(), 1);
|
||||
assert_eq!(coins[0].outpoint, coin_a.outpoint);
|
||||
|
||||
// Add a second one, we'll get both.
|
||||
// Add a second one (this one is change), we'll get both.
|
||||
let coin_b = Coin {
|
||||
outpoint: bitcoin::OutPoint::from_str(
|
||||
"61db3e276b095e5b05f1849dd6bfffb4e7e5ec1c4a4210099b98fce01571936f:12",
|
||||
@ -628,6 +630,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(1111),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(103).unwrap(),
|
||||
is_change: true,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
};
|
||||
@ -802,6 +805,7 @@ mod tests {
|
||||
block_time: None,
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(10).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
},
|
||||
@ -814,6 +818,7 @@ mod tests {
|
||||
block_time: Some(1_111_899),
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(100).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
},
|
||||
@ -826,6 +831,7 @@ mod tests {
|
||||
block_time: Some(1_121_899),
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(1000).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: Some(
|
||||
bitcoin::Txid::from_str(
|
||||
"0c62a990d20d54429e70859292e82374ba6b1b951a3ab60f26bb65fee5724ff7",
|
||||
@ -846,6 +852,7 @@ mod tests {
|
||||
block_time: Some(1_131_899),
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(10000).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: None,
|
||||
spend_block: None,
|
||||
},
|
||||
@ -858,6 +865,7 @@ mod tests {
|
||||
block_time: Some(1_134_899),
|
||||
amount: bitcoin::Amount::from_sat(98765),
|
||||
derivation_index: bip32::ChildNumber::from_normal_idx(100000).unwrap(),
|
||||
is_change: false,
|
||||
spend_txid: Some(
|
||||
bitcoin::Txid::from_str(
|
||||
"7477017f992cdc7ba08acafb77cb3b5bc0f42ac340d3e1e1da0785bdda20d5f6",
|
||||
|
||||
@ -44,6 +44,7 @@ CREATE TABLE coins (
|
||||
vout INTEGER NOT NULL,
|
||||
amount_sat INTEGER NOT NULL,
|
||||
derivation_index INTEGER NOT NULL,
|
||||
is_change BOOLEAN NOT NULL CHECK (is_change IN (0,1)),
|
||||
spend_txid BLOB,
|
||||
spend_block_height INTEGER,
|
||||
spend_block_time INTEGER,
|
||||
@ -146,6 +147,7 @@ pub struct DbCoin {
|
||||
pub block_time: Option<u32>,
|
||||
pub amount: bitcoin::Amount,
|
||||
pub derivation_index: bip32::ChildNumber,
|
||||
pub is_change: bool,
|
||||
pub spend_txid: Option<bitcoin::Txid>,
|
||||
pub spend_block: Option<DbSpendBlock>,
|
||||
}
|
||||
@ -168,12 +170,13 @@ impl TryFrom<&rusqlite::Row<'_>> for DbCoin {
|
||||
let amount = bitcoin::Amount::from_sat(amount);
|
||||
let der_idx: u32 = row.get(7)?;
|
||||
let derivation_index = bip32::ChildNumber::from(der_idx);
|
||||
let is_change: bool = row.get(8)?;
|
||||
|
||||
let spend_txid: Option<Vec<u8>> = row.get(8)?;
|
||||
let spend_txid: Option<Vec<u8>> = row.get(9)?;
|
||||
let spend_txid =
|
||||
spend_txid.map(|txid| encode::deserialize(&txid).expect("We only store valid txids"));
|
||||
let spend_height: Option<i32> = row.get(9)?;
|
||||
let spend_time: Option<u32> = row.get(10)?;
|
||||
let spend_height: Option<i32> = row.get(10)?;
|
||||
let spend_time: Option<u32> = row.get(11)?;
|
||||
assert_eq!(spend_height.is_none(), spend_time.is_none());
|
||||
let spend_block = spend_height.map(|height| DbSpendBlock {
|
||||
height,
|
||||
@ -188,6 +191,7 @@ impl TryFrom<&rusqlite::Row<'_>> for DbCoin {
|
||||
block_time,
|
||||
amount,
|
||||
derivation_index,
|
||||
is_change,
|
||||
spend_txid,
|
||||
spend_block,
|
||||
})
|
||||
|
||||
@ -187,7 +187,10 @@ impl DatabaseConnection for DummyDbConn {
|
||||
}
|
||||
}
|
||||
|
||||
fn derivation_index_by_address(&mut self, _: &bitcoin::Address) -> Option<bip32::ChildNumber> {
|
||||
fn derivation_index_by_address(
|
||||
&mut self,
|
||||
_: &bitcoin::Address,
|
||||
) -> Option<(bip32::ChildNumber, bool)> {
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user