Browse Source
reserveinputs marks UTXOs reserved for 12 hours, so we won't select them for spending: unreserveinputs marks them available again. Exposes param_psbt() for wider use. Disabled the test_sign_and_send_psbt since we're altering the API; the final patch restores it. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>release-0.9.0
Rusty Russell
5 years ago
9 changed files with 238 additions and 197 deletions
@ -0,0 +1,154 @@ |
|||
/* Dealing with reserving UTXOs */ |
|||
#include <common/json_command.h> |
|||
#include <common/json_helpers.h> |
|||
#include <common/jsonrpc_errors.h> |
|||
#include <lightningd/jsonrpc.h> |
|||
#include <lightningd/lightningd.h> |
|||
#include <wallet/wallet.h> |
|||
#include <wallet/walletrpc.h> |
|||
|
|||
static bool was_reserved(enum output_status oldstatus, |
|||
const u32 *reserved_til, |
|||
u32 current_height) |
|||
{ |
|||
if (oldstatus != output_state_reserved) |
|||
return false; |
|||
|
|||
return *reserved_til > current_height; |
|||
} |
|||
|
|||
static void json_add_reservestatus(struct json_stream *response, |
|||
const struct utxo *utxo, |
|||
enum output_status oldstatus, |
|||
u32 old_res, |
|||
u32 current_height) |
|||
{ |
|||
json_object_start(response, NULL); |
|||
json_add_txid(response, "txid", &utxo->txid); |
|||
json_add_u32(response, "vout", utxo->outnum); |
|||
json_add_bool(response, "was_reserved", |
|||
was_reserved(oldstatus, &old_res, current_height)); |
|||
json_add_bool(response, "reserved", |
|||
is_reserved(utxo, current_height)); |
|||
if (utxo->reserved_til) |
|||
json_add_u32(response, "reserved_to_block", |
|||
*utxo->reserved_til); |
|||
json_object_end(response); |
|||
} |
|||
|
|||
static struct command_result *json_reserveinputs(struct command *cmd, |
|||
const char *buffer, |
|||
const jsmntok_t *obj UNNEEDED, |
|||
const jsmntok_t *params) |
|||
{ |
|||
struct json_stream *response; |
|||
struct wally_psbt *psbt; |
|||
struct utxo **utxos = tal_arr(cmd, struct utxo *, 0); |
|||
|
|||
if (!param(cmd, buffer, params, |
|||
p_req("psbt", param_psbt, &psbt), |
|||
NULL)) |
|||
return command_param_failed(); |
|||
|
|||
for (size_t i = 0; i < psbt->tx->num_inputs; i++) { |
|||
struct bitcoin_txid txid; |
|||
struct utxo *utxo; |
|||
|
|||
wally_tx_input_get_txid(&psbt->tx->inputs[i], &txid); |
|||
utxo = wallet_utxo_get(cmd, cmd->ld->wallet, |
|||
&txid, psbt->tx->inputs[i].index); |
|||
if (!utxo) |
|||
continue; |
|||
if (utxo->status == output_state_spent) |
|||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, |
|||
"%s:%u already spent", |
|||
type_to_string(tmpctx, |
|||
struct bitcoin_txid, |
|||
&utxo->txid), |
|||
utxo->outnum); |
|||
tal_arr_expand(&utxos, utxo); |
|||
} |
|||
|
|||
response = json_stream_success(cmd); |
|||
json_array_start(response, "reservations"); |
|||
for (size_t i = 0; i < tal_count(utxos); i++) { |
|||
enum output_status oldstatus; |
|||
u32 old_res; |
|||
|
|||
oldstatus = utxos[i]->status; |
|||
old_res = utxos[i]->reserved_til ? *utxos[i]->reserved_til : 0; |
|||
|
|||
if (!wallet_reserve_utxo(cmd->ld->wallet, |
|||
utxos[i], |
|||
get_block_height(cmd->ld->topology))) { |
|||
fatal("Unable to reserve %s:%u!", |
|||
type_to_string(tmpctx, |
|||
struct bitcoin_txid, |
|||
&utxos[i]->txid), |
|||
utxos[i]->outnum); |
|||
} |
|||
json_add_reservestatus(response, utxos[i], oldstatus, old_res, |
|||
get_block_height(cmd->ld->topology)); |
|||
} |
|||
json_array_end(response); |
|||
return command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command reserveinputs_command = { |
|||
"reserveinputs", |
|||
"bitcoin", |
|||
json_reserveinputs, |
|||
"Reserve utxos (or increase their reservation)", |
|||
false |
|||
}; |
|||
AUTODATA(json_command, &reserveinputs_command); |
|||
|
|||
static struct command_result *json_unreserveinputs(struct command *cmd, |
|||
const char *buffer, |
|||
const jsmntok_t *obj UNNEEDED, |
|||
const jsmntok_t *params) |
|||
{ |
|||
struct json_stream *response; |
|||
struct wally_psbt *psbt; |
|||
|
|||
if (!param(cmd, buffer, params, |
|||
p_req("psbt", param_psbt, &psbt), |
|||
NULL)) |
|||
return command_param_failed(); |
|||
|
|||
response = json_stream_success(cmd); |
|||
json_array_start(response, "reservations"); |
|||
for (size_t i = 0; i < psbt->tx->num_inputs; i++) { |
|||
struct bitcoin_txid txid; |
|||
struct utxo *utxo; |
|||
enum output_status oldstatus; |
|||
u32 old_res; |
|||
|
|||
wally_tx_input_get_txid(&psbt->tx->inputs[i], &txid); |
|||
utxo = wallet_utxo_get(cmd, cmd->ld->wallet, |
|||
&txid, psbt->tx->inputs[i].index); |
|||
if (!utxo || utxo->status != output_state_reserved) |
|||
continue; |
|||
|
|||
oldstatus = utxo->status; |
|||
old_res = *utxo->reserved_til; |
|||
|
|||
wallet_unreserve_utxo(cmd->ld->wallet, |
|||
utxo, |
|||
get_block_height(cmd->ld->topology)); |
|||
|
|||
json_add_reservestatus(response, utxo, oldstatus, old_res, |
|||
get_block_height(cmd->ld->topology)); |
|||
} |
|||
json_array_end(response); |
|||
return command_success(cmd, response); |
|||
} |
|||
|
|||
static const struct json_command unreserveinputs_command = { |
|||
"unreserveinputs", |
|||
"bitcoin", |
|||
json_unreserveinputs, |
|||
"Unreserve utxos (or at least, reduce their reservation)", |
|||
false |
|||
}; |
|||
AUTODATA(json_command, &unreserveinputs_command); |
Loading…
Reference in new issue