commands: add a new 'delspendtx' command
This commit is contained in:
parent
d5bd10add8
commit
c73e8a42dd
17
doc/API.md
17
doc/API.md
@ -11,6 +11,7 @@ Commands must be sent as valid JSONRPC 2.0 requests, ending with a `\n`.
|
||||
| [`getinfo`](#getinfo) | Get general information about the daemon |
|
||||
| [`getnewaddress`](#getnewaddress) | Get a new receiving address |
|
||||
| [`listspendtxs`](#listspendtxs) | List all stored Spend transactions |
|
||||
| [`delspendtx`](#delspendtx) | Delete a stored Spend transaction |
|
||||
|
||||
# Reference
|
||||
|
||||
@ -156,3 +157,19 @@ This command does not take any parameter for now.
|
||||
| -------------- | ----------------- | ----------------------------------------------------------------------- |
|
||||
| `psbt` | string | Base64-encoded PSBT of the Spend transaction. |
|
||||
| `change_index` | int or null | Index of the change output in the transaction outputs, if there is one. |
|
||||
|
||||
|
||||
### `delspendtx`
|
||||
|
||||
#### Request
|
||||
|
||||
| Field | Type | Description |
|
||||
| -------- | ------ | --------------------------------------------------- |
|
||||
| `txid` | string | Hex encoded txid of the Spend transaction to delete |
|
||||
|
||||
#### Response
|
||||
|
||||
This command does not return anything for now.
|
||||
|
||||
| Field | Type | Description |
|
||||
| -------------- | --------- | ---------------------------------------------------- |
|
||||
|
||||
@ -431,6 +431,11 @@ impl DaemonControl {
|
||||
.collect();
|
||||
ListSpendResult { spend_txs }
|
||||
}
|
||||
|
||||
pub fn delete_spend(&self, txid: &bitcoin::Txid) {
|
||||
let mut db_conn = self.db.connection();
|
||||
db_conn.delete_spend(txid);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@ -79,6 +79,9 @@ pub trait DatabaseConnection {
|
||||
|
||||
/// List all existing Spend transactions.
|
||||
fn list_spend(&mut self) -> Vec<Psbt>;
|
||||
|
||||
/// Delete a Spend transaction from database.
|
||||
fn delete_spend(&mut self, txid: &bitcoin::Txid);
|
||||
}
|
||||
|
||||
// FIXME: if possible, avoid reallocating.
|
||||
@ -181,6 +184,10 @@ impl DatabaseConnection for SqliteConn {
|
||||
.map(|db_spend| db_spend.psbt)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn delete_spend(&mut self, txid: &bitcoin::Txid) {
|
||||
self.delete_spend(txid)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
||||
@ -392,6 +392,17 @@ impl SqliteConn {
|
||||
)
|
||||
.expect("Db must not fail")
|
||||
}
|
||||
|
||||
pub fn delete_spend(&mut self, txid: &bitcoin::Txid) {
|
||||
db_exec(&mut self.conn, |db_tx| {
|
||||
db_tx.execute(
|
||||
"DELETE FROM spend_transactions WHERE txid = ?1",
|
||||
rusqlite::params![txid.to_vec()],
|
||||
)?;
|
||||
Ok(())
|
||||
})
|
||||
.expect("Db must not fail");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -60,6 +60,18 @@ fn update_spend(control: &DaemonControl, params: Params) -> Result<serde_json::V
|
||||
Ok(serde_json::json!({}))
|
||||
}
|
||||
|
||||
fn delete_spend(control: &DaemonControl, params: Params) -> Result<serde_json::Value, Error> {
|
||||
let txid = params
|
||||
.get(0, "txid")
|
||||
.ok_or(Error::invalid_params("Missing 'txid' parameter."))?
|
||||
.as_str()
|
||||
.and_then(|s| bitcoin::Txid::from_str(&s).ok())
|
||||
.ok_or(Error::invalid_params("Invalid 'feerate' parameter."))?;
|
||||
control.delete_spend(&txid);
|
||||
|
||||
Ok(serde_json::json!({}))
|
||||
}
|
||||
|
||||
/// Handle an incoming JSONRPC2 request.
|
||||
pub fn handle_request(control: &DaemonControl, req: Request) -> Result<Response, Error> {
|
||||
let result = match req.method.as_str() {
|
||||
@ -69,6 +81,12 @@ pub fn handle_request(control: &DaemonControl, req: Request) -> Result<Response,
|
||||
))?;
|
||||
create_spend(control, params)?
|
||||
}
|
||||
"delspendtx" => {
|
||||
let params = req
|
||||
.params
|
||||
.ok_or(Error::invalid_params("Missing 'txid' parameter."))?;
|
||||
delete_spend(control, params)?
|
||||
}
|
||||
"getinfo" => serde_json::json!(&control.get_info()),
|
||||
"getnewaddress" => serde_json::json!(&control.get_new_address()),
|
||||
"listcoins" => serde_json::json!(&control.list_coins()),
|
||||
|
||||
@ -180,6 +180,10 @@ impl DatabaseConnection for DummyDbConn {
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn delete_spend(&mut self, txid: &bitcoin::Txid) {
|
||||
self.db.write().unwrap().spend_txs.remove(txid);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyMinisafe {
|
||||
|
||||
@ -551,6 +551,11 @@ class CTransaction(object):
|
||||
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
|
||||
self.hash = encode(hash256(self.serialize())[::-1], "hex_codec").decode("ascii")
|
||||
|
||||
def txid(self):
|
||||
if self.sha256 is None:
|
||||
self.calc_sha256()
|
||||
return ser_uint256(self.sha256)[::-1]
|
||||
|
||||
def is_valid(self):
|
||||
self.calc_sha256()
|
||||
for tout in self.vout:
|
||||
|
||||
@ -134,6 +134,21 @@ def test_list_spend(minisafed, bitcoind):
|
||||
second_psbt = next(entry for entry in list_res if entry["psbt"] == res_b["psbt"])
|
||||
assert second_psbt["change_index"] is None
|
||||
|
||||
# If we delete the first one, we'll get only the second one.
|
||||
first_psbt = PSBT()
|
||||
first_psbt.deserialize(res["psbt"])
|
||||
minisafed.rpc.delspendtx(first_psbt.tx.txid().hex())
|
||||
list_res = minisafed.rpc.listspendtxs()["spend_txs"]
|
||||
assert len(list_res) == 1
|
||||
assert list_res[0]["psbt"] == res_b["psbt"]
|
||||
|
||||
# If we delete the second one, result will be empty.
|
||||
second_psbt = PSBT()
|
||||
second_psbt.deserialize(res_b["psbt"])
|
||||
minisafed.rpc.delspendtx(second_psbt.tx.txid().hex())
|
||||
list_res = minisafed.rpc.listspendtxs()["spend_txs"]
|
||||
assert len(list_res) == 0
|
||||
|
||||
|
||||
def test_update_spend(minisafed, bitcoind):
|
||||
# Start by creating a Spend PSBT
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user