Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

commands: indicate in listcoins response whether coin is from self #1483

Merged
merged 7 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ A coin may have one of the following four statuses:
| `spend_info` | object | Information about the transaction spending this coin. See [Spending transaction info](#spending_transaction_info). |
| `is_immature` | bool | Whether this coin was created by a coinbase transaction that is still immature. |
| `is_change` | bool | Whether the coin deposit address was derived from the change descriptor. |
| `is_from_self` | bool | Whether the coin and all its unconfirmed ancestors, if any, are outputs of transactions from this wallet. |


##### Spending transaction info
Expand Down
4 changes: 4 additions & 0 deletions liana-gui/src/app/state/coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ mod tests {
address: dummy_address.clone(),
derivation_index: 0.into(),
is_change: false,
is_from_self: false,
},
Coin {
outpoint: bitcoin::OutPoint { txid, vout: 3 },
Expand All @@ -236,6 +237,7 @@ mod tests {
address: dummy_address.clone(),
derivation_index: 1.into(),
is_change: false,
is_from_self: false,
},
Coin {
outpoint: bitcoin::OutPoint { txid, vout: 0 },
Expand All @@ -246,6 +248,7 @@ mod tests {
address: dummy_address.clone(),
derivation_index: 2.into(),
is_change: false,
is_from_self: false,
},
Coin {
outpoint: bitcoin::OutPoint { txid, vout: 1 },
Expand All @@ -256,6 +259,7 @@ mod tests {
address: dummy_address,
derivation_index: 3.into(),
is_change: false,
is_from_self: false,
},
]);

Expand Down
1 change: 1 addition & 0 deletions liana-gui/src/app/state/psbt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ mod tests {
"derivation_index": 0,
"is_immature": false,
"is_change": false,
"is_from_self": false,

}]})),
),
Expand Down
3 changes: 3 additions & 0 deletions liana-gui/src/lianalite/client/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ impl Daemon for BackendWalletClient {
txid: info.txid,
height: info.height,
}),
is_from_self: false, // FIXME: use value from backend
})
.collect(),
})
Expand Down Expand Up @@ -1133,6 +1134,7 @@ fn history_tx_from_api(value: api::Transaction, network: Network) -> HistoryTran
txid: info.txid,
height: info.height,
}),
is_from_self: false, // FIXME: use value from backend
});
}
}
Expand Down Expand Up @@ -1188,6 +1190,7 @@ fn spend_tx_from_api(
txid: info.txid,
height: info.height,
}),
is_from_self: false, // FIXME: use value from backend
});
}
}
Expand Down
4 changes: 4 additions & 0 deletions lianad/src/bitcoin/poller/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ fn update_coins(
block_info: None,
spend_txid: None,
spend_block: None,
is_from_self: false,
};
received.push(coin);
}
Expand Down Expand Up @@ -315,6 +316,9 @@ fn updates(
db_conn.unspend_coins(&updated_coins.expired_spending);
db_conn.spend_coins(&updated_coins.spending);
db_conn.confirm_spend(&updated_coins.spent);
// Update info about which coins are from self only after
// coins have been inserted & updated above.
db_conn.update_coins_from_self(current_tip.height);
if latest_tip != current_tip {
db_conn.update_tip(&latest_tip);
log::debug!("New tip: '{}'", latest_tip);
Expand Down
20 changes: 20 additions & 0 deletions lianad/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ impl DaemonControl {
spend_block,
is_immature,
is_change,
is_from_self,
derivation_index,
..
} = coin;
Expand All @@ -445,6 +446,7 @@ impl DaemonControl {
spend_info,
is_immature,
is_change,
is_from_self,
}
})
.collect();
Expand Down Expand Up @@ -1229,6 +1231,10 @@ pub struct ListCoinsEntry {
pub is_immature: bool,
/// Whether the coin deposit address was derived from the change descriptor.
pub is_change: bool,
/// Whether the coin is the output of a transaction whose inputs are all from
/// this same wallet. If the coin is unconfirmed, it also means that all its
/// unconfirmed ancestors, if any, are also from self.
pub is_from_self: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -1491,6 +1497,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
// If we try to use coin selection, the unconfirmed non-change coin will not be used
// as a candidate and so we get a coin selection error due to insufficient funds.
Expand Down Expand Up @@ -1733,6 +1740,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
assert_eq!(
control.create_spend(&destinations, &[dummy_op_dup], 1_001, None),
Expand All @@ -1755,6 +1763,7 @@ mod tests {
is_change: true,
spend_txid: None,
spend_block: None,
is_from_self: false,
};
db_conn.new_unspent_coins(&[unconfirmed_coin]);
// Coin selection error due to insufficient funds.
Expand Down Expand Up @@ -1786,6 +1795,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
// First, create a transaction using auto coin selection.
let psbt = if let CreateSpendResult::Success { psbt, .. } =
Expand Down Expand Up @@ -1921,6 +1931,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
let empty_dest = &HashMap::<bitcoin::Address<address::NetworkUnchecked>, u64>::new();
assert!(matches!(
Expand Down Expand Up @@ -1960,6 +1971,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
assert_eq!(
control.create_spend(&destinations, &[imma_op], 1_001, None),
Expand Down Expand Up @@ -2005,6 +2017,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
},
Coin {
outpoint: dummy_op_b,
Expand All @@ -2015,6 +2028,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
},
]);

Expand Down Expand Up @@ -2162,6 +2176,7 @@ mod tests {
height: 184500,
time: 184500,
}),
is_from_self: false,
}]);
// The coin is spent so we cannot RBF.
assert_eq!(
Expand Down Expand Up @@ -2273,6 +2288,7 @@ mod tests {
derivation_index: ChildNumber::from(0),
amount: bitcoin::Amount::from_sat(100_000_000),
spend_txid: Some(spend_tx.txid()),
is_from_self: false,
},
// Deposit 2
Coin {
Expand All @@ -2287,6 +2303,7 @@ mod tests {
derivation_index: ChildNumber::from(1),
amount: bitcoin::Amount::from_sat(2000),
spend_txid: None,
is_from_self: false,
},
// This coin is a change output.
Coin {
Expand All @@ -2298,6 +2315,7 @@ mod tests {
derivation_index: ChildNumber::from(2),
amount: bitcoin::Amount::from_sat(100_000_000 - 4000 - 1000),
spend_txid: None,
is_from_self: false,
},
// Deposit 3
Coin {
Expand All @@ -2312,6 +2330,7 @@ mod tests {
derivation_index: ChildNumber::from(3),
amount: bitcoin::Amount::from_sat(3000),
spend_txid: None,
is_from_self: false,
},
]);

Expand Down Expand Up @@ -2532,6 +2551,7 @@ mod tests {
is_change: false,
spend_txid: None,
spend_block: None,
is_from_self: false,
}]);
}
}
Expand Down
12 changes: 12 additions & 0 deletions lianad/src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ pub trait DatabaseConnection {
/// Store transactions in database, ignoring any that already exist.
fn new_txs(&mut self, txs: &[bitcoin::Transaction]);

/// For all unconfirmed coins and those confirmed after `prev_tip_height`,
/// update whether the coin is from self or not.
fn update_coins_from_self(&mut self, prev_tip_height: i32);

/// Retrieve a list of transactions and their corresponding block heights and times.
fn list_wallet_transactions(
&mut self,
Expand Down Expand Up @@ -379,6 +383,11 @@ impl DatabaseConnection for SqliteConn {
self.new_txs(txs)
}

fn update_coins_from_self(&mut self, prev_tip_height: i32) {
self.update_coins_from_self(prev_tip_height)
.expect("must not fail")
}

fn list_wallet_transactions(
&mut self,
txids: &[bitcoin::Txid],
Expand Down Expand Up @@ -421,6 +430,7 @@ pub struct Coin {
pub is_change: bool,
pub spend_txid: Option<bitcoin::Txid>,
pub spend_block: Option<BlockInfo>,
pub is_from_self: bool,
}

impl std::convert::From<DbCoin> for Coin {
Expand All @@ -434,6 +444,7 @@ impl std::convert::From<DbCoin> for Coin {
is_change,
spend_txid,
spend_block,
is_from_self,
..
} = db_coin;
Coin {
Expand All @@ -445,6 +456,7 @@ impl std::convert::From<DbCoin> for Coin {
is_change,
spend_txid,
spend_block: spend_block.map(BlockInfo::from),
is_from_self,
}
}
}
Expand Down
Loading
Loading