commands: make listcoins return all coins by default

We'll add some parameters to filter by status and/or outpoints later on.
But for now also list coins that were spent or are being spent.
This commit is contained in:
Antoine Poinsot 2022-10-14 17:27:15 +02:00
parent e9e4acd69d
commit 92f7ef1225
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
6 changed files with 26 additions and 29 deletions

View File

@ -70,7 +70,7 @@ This command does not take any parameter for now.
### `listcoins`
List our current Unspent Transaction Outputs.
List all our transaction outputs, regardless of their state (unspent or not).
#### Request
@ -83,7 +83,7 @@ This command does not take any parameter for now.
| Field | Type | Description |
| -------------- | ------------- | ---------------------------------------------------------------- |
| `amount` | int | Value of the UTxO in satoshis |
| `amount` | int | Value of the TxO in satoshis |
| `outpoint` | string | Transaction id and output index of this coin |
| `block_height` | int or null | Blockheight the transaction was confirmed at, or `null` |

View File

@ -28,7 +28,7 @@ fn update_coins(
previous_tip: &BlockChainTip,
) -> UpdatedCoins {
// Start by fetching newly received coins.
let curr_coins = db_conn.unspent_coins();
let curr_coins = db_conn.coins();
let mut received = Vec::new();
for utxo in bit.received_coins(previous_tip) {
if let Some(derivation_index) = db_conn.derivation_index_by_address(&utxo.address) {

View File

@ -193,11 +193,11 @@ impl DaemonControl {
GetAddressResult { address }
}
/// Get a list of all currently unspent coins.
/// Get a list of all known coins.
pub fn list_coins(&self) -> ListCoinsResult {
let mut db_conn = self.db.connection();
let coins: Vec<ListCoinsEntry> = db_conn
.unspent_coins()
.coins()
// Can't use into_values as of Rust 1.48
.into_iter()
.map(|(_, coin)| {

View File

@ -54,8 +54,8 @@ pub trait DatabaseConnection {
address: &bitcoin::Address,
) -> Option<bip32::ChildNumber>;
/// Get all UTxOs.
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
/// Get all our coins, past or present, spent or not.
fn coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
/// List coins that are being spent and whose spending transaction is still unconfirmed.
fn list_spending_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin>;
@ -121,8 +121,8 @@ impl DatabaseConnection for SqliteConn {
self.increment_derivation_index(secp)
}
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
self.unspent_coins()
fn coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
self.coins()
.into_iter()
.map(|db_coin| (db_coin.outpoint, db_coin.into()))
.collect()

View File

@ -252,11 +252,11 @@ impl SqliteConn {
.expect("Database must be available")
}
/// Get all UTxOs.
pub fn unspent_coins(&mut self) -> Vec<DbCoin> {
/// Get all the coins from DB.
pub fn coins(&mut self) -> Vec<DbCoin> {
db_query(
&mut self.conn,
"SELECT * FROM coins WHERE spend_txid is NULL",
"SELECT * FROM coins",
rusqlite::params![],
|row| row.try_into(),
)
@ -589,7 +589,7 @@ mod tests {
let mut conn = db.connection().unwrap();
// Necessarily empty at first.
assert!(conn.unspent_coins().is_empty());
assert!(conn.coins().is_empty());
// Add one, we'll get it.
let coin_a = Coin {
@ -605,7 +605,7 @@ mod tests {
spend_block: None,
};
conn.new_unspent_coins(&[coin_a]);
assert_eq!(conn.unspent_coins()[0].outpoint, coin_a.outpoint);
assert_eq!(conn.coins()[0].outpoint, coin_a.outpoint);
// We can query it by its outpoint
let coins = conn.db_coins(&[coin_a.outpoint]);
@ -626,11 +626,8 @@ mod tests {
spend_block: None,
};
conn.new_unspent_coins(&[coin_b]);
let outpoints: HashSet<bitcoin::OutPoint> = conn
.unspent_coins()
.into_iter()
.map(|c| c.outpoint)
.collect();
let outpoints: HashSet<bitcoin::OutPoint> =
conn.coins().into_iter().map(|c| c.outpoint).collect();
assert!(outpoints.contains(&coin_a.outpoint));
assert!(outpoints.contains(&coin_b.outpoint));
@ -650,24 +647,24 @@ mod tests {
let height = 174500;
let time = 174500;
conn.confirm_coins(&[(coin_a.outpoint, height, time)]);
let coins = conn.unspent_coins();
let coins = conn.coins();
assert_eq!(coins[0].block_height, Some(height));
assert_eq!(coins[0].block_time, Some(time));
assert!(coins[1].block_height.is_none());
assert!(coins[1].block_time.is_none());
// Now if we spend one, we'll only get the other one.
// Now if we spend one, it'll be marked as such.
conn.spend_coins(&[(
coin_a.outpoint,
bitcoin::Txid::from_slice(&[0; 32][..]).unwrap(),
)]);
let outpoints: HashSet<bitcoin::OutPoint> = conn
.unspent_coins()
.into_iter()
.map(|c| c.outpoint)
.collect();
assert!(!outpoints.contains(&coin_a.outpoint));
assert!(outpoints.contains(&coin_b.outpoint));
let coins_map: HashMap<bitcoin::OutPoint, DbCoin> =
conn.coins().into_iter().map(|c| (c.outpoint, c)).collect();
assert!(coins_map
.get(&coin_a.outpoint)
.unwrap()
.spend_txid
.is_some());
let outpoints: HashSet<bitcoin::OutPoint> = conn
.list_spending_coins()

View File

@ -124,7 +124,7 @@ impl DatabaseConnection for DummyDbConn {
self.db.write().unwrap().curr_index = next_index;
}
fn unspent_coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
fn coins(&mut self) -> HashMap<bitcoin::OutPoint, Coin> {
self.db.read().unwrap().coins.clone()
}