commands: add an 'updated_at' field to listspendtxs entries
This commit is contained in:
parent
6b666e75c0
commit
104c6e1a09
@ -174,6 +174,7 @@ This command does not take any parameter for now.
|
||||
| Field | Type | Description |
|
||||
| -------------- | ----------------- | ----------------------------------------------------------------------- |
|
||||
| `psbt` | string | Base64-encoded PSBT of the Spend transaction. |
|
||||
| `updated_at` | int or null | UNIX timestamp of the last time this PSBT was updated. |
|
||||
|
||||
|
||||
### `delspendtx`
|
||||
|
||||
@ -563,7 +563,7 @@ impl DaemonControl {
|
||||
let spend_txs = db_conn
|
||||
.list_spend()
|
||||
.into_iter()
|
||||
.map(|psbt| ListSpendEntry { psbt })
|
||||
.map(|(psbt, updated_at)| ListSpendEntry { psbt, updated_at })
|
||||
.collect();
|
||||
ListSpendResult { spend_txs }
|
||||
}
|
||||
@ -840,6 +840,7 @@ pub struct CreateSpendResult {
|
||||
pub struct ListSpendEntry {
|
||||
#[serde(serialize_with = "ser_base64", deserialize_with = "deser_base64")]
|
||||
pub psbt: Psbt,
|
||||
pub updated_at: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@ -112,8 +112,8 @@ pub trait DatabaseConnection {
|
||||
/// Insert a new Spend transaction or replace an existing one.
|
||||
fn store_spend(&mut self, psbt: &Psbt);
|
||||
|
||||
/// List all existing Spend transactions.
|
||||
fn list_spend(&mut self) -> Vec<Psbt>;
|
||||
/// List all existing Spend transactions, along with an optional last update timestamp.
|
||||
fn list_spend(&mut self) -> Vec<(Psbt, Option<u32>)>;
|
||||
|
||||
/// Delete a Spend transaction from database.
|
||||
fn delete_spend(&mut self, txid: &bitcoin::Txid);
|
||||
@ -241,10 +241,10 @@ impl DatabaseConnection for SqliteConn {
|
||||
self.store_spend(psbt)
|
||||
}
|
||||
|
||||
fn list_spend(&mut self) -> Vec<Psbt> {
|
||||
fn list_spend(&mut self) -> Vec<(Psbt, Option<u32>)> {
|
||||
self.list_spend()
|
||||
.into_iter()
|
||||
.map(|db_spend| db_spend.psbt)
|
||||
.map(|db_spend| (db_spend.psbt, db_spend.updated_at))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@ -15,8 +15,8 @@ use crate::{
|
||||
sqlite::{
|
||||
schema::{DbAddress, DbCoin, DbSpendTransaction, DbTip, DbWallet, SCHEMA},
|
||||
utils::{
|
||||
create_fresh_db, db_exec, db_query, db_tx_query, db_version, maybe_apply_migration,
|
||||
LOOK_AHEAD_LIMIT,
|
||||
create_fresh_db, curr_timestamp, db_exec, db_query, db_tx_query, db_version,
|
||||
maybe_apply_migration, LOOK_AHEAD_LIMIT,
|
||||
},
|
||||
},
|
||||
Coin, CoinType,
|
||||
@ -500,9 +500,9 @@ impl SqliteConn {
|
||||
|
||||
db_exec(&mut self.conn, |db_tx| {
|
||||
db_tx.execute(
|
||||
"INSERT into spend_transactions (psbt, txid) VALUES (?1, ?2) \
|
||||
"INSERT into spend_transactions (psbt, txid, updated_at) VALUES (?1, ?2, ?3) \
|
||||
ON CONFLICT DO UPDATE SET psbt=excluded.psbt",
|
||||
rusqlite::params![psbt, txid],
|
||||
rusqlite::params![psbt, txid, curr_timestamp()],
|
||||
)?;
|
||||
Ok(())
|
||||
})
|
||||
@ -1463,12 +1463,11 @@ CREATE TABLE spend_transactions (
|
||||
.find(|db_spend| db_spend.psbt == first_psbt)
|
||||
.unwrap();
|
||||
assert!(first_spend.updated_at.is_none());
|
||||
// TODO: update once we update store_spend() to take a timestamp.
|
||||
let second_spend = db_spends
|
||||
.iter()
|
||||
.find(|db_spend| db_spend.psbt == second_psbt)
|
||||
.unwrap();
|
||||
assert!(second_spend.updated_at.is_none());
|
||||
assert!(second_spend.updated_at.is_some());
|
||||
}
|
||||
|
||||
fs::remove_dir_all(tmp_dir).unwrap();
|
||||
|
||||
@ -50,11 +50,14 @@ where
|
||||
.collect::<rusqlite::Result<Vec<T>>>()
|
||||
}
|
||||
|
||||
// Sqlite supports up to i64, thus rusqlite prevents us from inserting u64's.
|
||||
// We use this to panic rather than inserting a truncated integer into the database (as we'd have
|
||||
// done by using `n as u32`).
|
||||
fn timestamp_to_u32(n: u64) -> u32 {
|
||||
n.try_into()
|
||||
/// The current time as the number of seconds since the UNIX epoch, truncated to u32 since SQLite
|
||||
/// only supports i64 integers.
|
||||
pub fn curr_timestamp() -> u32 {
|
||||
time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.expect("System clock went backward the epoch?")
|
||||
.as_secs()
|
||||
.try_into()
|
||||
.expect("Is this the year 2106 yet? Misconfigured system clock.")
|
||||
}
|
||||
|
||||
@ -87,10 +90,7 @@ pub fn create_fresh_db(
|
||||
) -> Result<(), SqliteDbError> {
|
||||
create_db_file(db_path)?;
|
||||
|
||||
let timestamp = time::SystemTime::now()
|
||||
.duration_since(time::UNIX_EPOCH)
|
||||
.map(|dur| timestamp_to_u32(dur.as_secs()))
|
||||
.expect("System clock went backward the epoch?");
|
||||
let timestamp = curr_timestamp();
|
||||
|
||||
// Fill the initial addresses. On a fresh database, the deposit_derivation_index is
|
||||
// necessarily 0.
|
||||
|
||||
@ -120,7 +120,7 @@ struct DummyDbState {
|
||||
change_index: bip32::ChildNumber,
|
||||
curr_tip: Option<BlockChainTip>,
|
||||
coins: HashMap<bitcoin::OutPoint, Coin>,
|
||||
spend_txs: HashMap<bitcoin::Txid, Psbt>,
|
||||
spend_txs: HashMap<bitcoin::Txid, (Psbt, Option<u32>)>,
|
||||
}
|
||||
|
||||
pub struct DummyDatabase {
|
||||
@ -293,14 +293,20 @@ impl DatabaseConnection for DummyDatabase {
|
||||
.write()
|
||||
.unwrap()
|
||||
.spend_txs
|
||||
.insert(txid, psbt.clone());
|
||||
.insert(txid, (psbt.clone(), None));
|
||||
}
|
||||
|
||||
fn spend_tx(&mut self, txid: &bitcoin::Txid) -> Option<Psbt> {
|
||||
self.db.read().unwrap().spend_txs.get(txid).cloned()
|
||||
self.db
|
||||
.read()
|
||||
.unwrap()
|
||||
.spend_txs
|
||||
.get(txid)
|
||||
.cloned()
|
||||
.map(|x| x.0)
|
||||
}
|
||||
|
||||
fn list_spend(&mut self) -> Vec<Psbt> {
|
||||
fn list_spend(&mut self) -> Vec<(Psbt, Option<u32>)> {
|
||||
self.db
|
||||
.read()
|
||||
.unwrap()
|
||||
|
||||
@ -159,6 +159,7 @@ def test_list_spend(lianad, bitcoind):
|
||||
assert "psbt" in res_b
|
||||
|
||||
# Store them both in DB.
|
||||
time_before_update = int(time.time())
|
||||
assert len(lianad.rpc.listspendtxs()["spend_txs"]) == 0
|
||||
lianad.rpc.updatespend(res["psbt"])
|
||||
lianad.rpc.updatespend(res_b["psbt"])
|
||||
@ -168,7 +169,9 @@ def test_list_spend(lianad, bitcoind):
|
||||
list_res = lianad.rpc.listspendtxs()["spend_txs"]
|
||||
assert len(list_res) == 2
|
||||
first_psbt = next(entry for entry in list_res if entry["psbt"] == res["psbt"])
|
||||
assert time_before_update <= first_psbt["updated_at"] <= int(time.time())
|
||||
second_psbt = next(entry for entry in list_res if entry["psbt"] == res_b["psbt"])
|
||||
assert time_before_update <= second_psbt["updated_at"] <= int(time.time())
|
||||
|
||||
# If we delete the first one, we'll get only the second one.
|
||||
first_psbt = PSBT.from_base64(res["psbt"])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user