mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
API: txprepare now support mutiple outputs
This commit is contained in:
@@ -60,6 +60,16 @@ bool json_to_sat(const char *buffer, const jsmntok_t *tok,
|
||||
return parse_amount_sat(sat, buffer + tok->start, tok->end - tok->start);
|
||||
}
|
||||
|
||||
bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat *sat)
|
||||
{
|
||||
if (json_tok_streq(buffer, tok, "all")) {
|
||||
*sat = AMOUNT_SAT(-1ULL);
|
||||
return true;
|
||||
}
|
||||
return json_to_sat(buffer, tok, sat);
|
||||
}
|
||||
|
||||
bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok,
|
||||
struct short_channel_id *scid,
|
||||
bool may_be_deprecated_form)
|
||||
|
||||
@@ -32,6 +32,11 @@ bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok,
|
||||
bool json_to_sat(const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat *sat);
|
||||
|
||||
/* Extract a satoshis amount from this */
|
||||
/* If the string is "all", set amonut as AMOUNT_SAT(-1ULL). */
|
||||
bool json_to_sat_or_all(const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat *sat);
|
||||
|
||||
/* Extract a millisatoshis amount from this */
|
||||
bool json_to_msat(const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_msat *msat);
|
||||
|
||||
@@ -183,7 +183,19 @@ struct command_result *param_sat(struct command *cmd, const char *name,
|
||||
return NULL;
|
||||
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%s' should be a satoshi amount, not '%.*s'",
|
||||
name, tok->end - tok->start, buffer + tok->start);
|
||||
"%s should be a satoshi amount, not '%.*s'",
|
||||
name ? name : "amount field",
|
||||
tok->end - tok->start, buffer + tok->start);
|
||||
}
|
||||
|
||||
struct command_result *param_sat_or_all(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat **sat)
|
||||
{
|
||||
if (json_tok_streq(buffer, tok, "all")) {
|
||||
*sat = tal(cmd, struct amount_sat);
|
||||
**sat = AMOUNT_SAT(-1ULL);
|
||||
return NULL;
|
||||
}
|
||||
return param_sat(cmd, name, buffer, tok, sat);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,12 @@ struct command_result *param_sat(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat **sat);
|
||||
|
||||
/* Extract satoshi amount from this string. */
|
||||
/* If the string is "all", set amonut as AMOUNT_SAT(-1ULL). */
|
||||
struct command_result *param_sat_or_all(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct amount_sat **sat);
|
||||
|
||||
/*
|
||||
* Set the address of @out to @tok. Used as a callback by handlers that
|
||||
* want to unmarshal @tok themselves.
|
||||
|
||||
@@ -878,18 +878,18 @@ class LightningRpc(UnixDomainSocketRpc):
|
||||
}
|
||||
return self.call("withdraw", payload)
|
||||
|
||||
def txprepare(self, destination, satoshi, feerate=None, minconf=None):
|
||||
def txprepare(self, outputs, feerate=None, minconf=None):
|
||||
"""
|
||||
Prepare a bitcoin transaction which sends to {destination} address
|
||||
{satoshi} (or "all") amount via Bitcoin transaction. Only select outputs
|
||||
with {minconf} confirmations.
|
||||
Prepare a bitcoin transaction which sends to [outputs].
|
||||
The format of output is like [{address1: amount1},
|
||||
{address2: amount2}], or [{address: "all"}]).
|
||||
Only select outputs with {minconf} confirmations.
|
||||
|
||||
Outputs will be reserved until you call txdiscard or txsend, or
|
||||
lightningd restarts.
|
||||
"""
|
||||
payload = {
|
||||
"destination": destination,
|
||||
"satoshi": satoshi,
|
||||
"outputs": outputs,
|
||||
"feerate": feerate,
|
||||
"minconf": minconf,
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ msgtype,hsm_sign_withdrawal,7
|
||||
msgdata,hsm_sign_withdrawal,satoshi_out,amount_sat,
|
||||
msgdata,hsm_sign_withdrawal,change_out,amount_sat,
|
||||
msgdata,hsm_sign_withdrawal,change_keyindex,u32,
|
||||
msgdata,hsm_sign_withdrawal,scriptpubkey_len,u16,
|
||||
msgdata,hsm_sign_withdrawal,scriptpubkey,u8,scriptpubkey_len
|
||||
msgdata,hsm_sign_withdrawal,num_outputs,u16,
|
||||
msgdata,hsm_sign_withdrawal,outputs,bitcoin_tx_output,num_outputs
|
||||
msgdata,hsm_sign_withdrawal,num_inputs,u16,
|
||||
msgdata,hsm_sign_withdrawal,inputs,utxo,num_inputs
|
||||
|
||||
|
||||
|
@@ -1514,24 +1514,17 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn,
|
||||
struct utxo **utxos;
|
||||
struct bitcoin_tx *tx;
|
||||
struct pubkey changekey;
|
||||
u8 *scriptpubkey;
|
||||
struct bitcoin_tx_output **outputs;
|
||||
|
||||
outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, 0);
|
||||
if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &satoshi_out,
|
||||
&change_out, &change_keyindex,
|
||||
&scriptpubkey, &utxos))
|
||||
&outputs, &utxos))
|
||||
return bad_req(conn, c, msg_in);
|
||||
|
||||
if (!bip32_pubkey(&secretstuff.bip32, &changekey, change_keyindex))
|
||||
return bad_req_fmt(conn, c, msg_in,
|
||||
"Failed to get key %u", change_keyindex);
|
||||
|
||||
struct bitcoin_tx_output *output = tal(outputs,
|
||||
struct bitcoin_tx_output);
|
||||
output->script = tal_steal(output, scriptpubkey);
|
||||
output->amount = satoshi_out;
|
||||
tal_arr_expand(&outputs, output);
|
||||
tx = withdraw_tx(tmpctx, c->chainparams,
|
||||
cast_const2(const struct utxo **, utxos), outputs,
|
||||
&changekey, change_out, NULL, NULL);
|
||||
|
||||
@@ -207,8 +207,7 @@ def test_txprepare(node_factory, bitcoind):
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 10)
|
||||
|
||||
prep = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
Millisatoshi(amount * 3 * 1000))
|
||||
prep = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': Millisatoshi(amount * 3 * 1000)}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx'])
|
||||
assert decode['txid'] == prep['txid']
|
||||
# 4 inputs, 2 outputs.
|
||||
@@ -231,8 +230,7 @@ def test_txprepare(node_factory, bitcoind):
|
||||
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
|
||||
# Now prepare one with no change.
|
||||
prep2 = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep2 = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep2['unsigned_tx'])
|
||||
assert decode['txid'] == prep2['txid']
|
||||
# 6 inputs, 1 outputs.
|
||||
@@ -250,8 +248,7 @@ def test_txprepare(node_factory, bitcoind):
|
||||
assert discard['txid'] == prep['txid']
|
||||
assert discard['unsigned_tx'] == prep['unsigned_tx']
|
||||
|
||||
prep3 = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep3 = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep3['unsigned_tx'])
|
||||
assert decode['txid'] == prep3['txid']
|
||||
# 4 inputs, 1 outputs.
|
||||
@@ -271,8 +268,7 @@ def test_txprepare(node_factory, bitcoind):
|
||||
# Discard everything, we should now spend all inputs.
|
||||
l1.rpc.txdiscard(prep2['txid'])
|
||||
l1.rpc.txdiscard(prep3['txid'])
|
||||
prep4 = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep4 = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep4['unsigned_tx'])
|
||||
assert decode['txid'] == prep4['txid']
|
||||
# 10 inputs, 1 outputs.
|
||||
@@ -299,8 +295,7 @@ def test_txsend(node_factory, bitcoind):
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 10)
|
||||
|
||||
prep = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
Millisatoshi(amount * 3 * 1000))
|
||||
prep = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': Millisatoshi(amount * 3 * 1000)}])
|
||||
out = l1.rpc.txsend(prep['txid'])
|
||||
|
||||
# Cannot discard after send!
|
||||
@@ -343,8 +338,7 @@ def test_txprepare_restart(node_factory, bitcoind):
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: [o['status'] for o in l1.rpc.listfunds()['outputs']] == ['confirmed'] * 10)
|
||||
|
||||
prep = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx'])
|
||||
assert decode['txid'] == prep['txid']
|
||||
# All 10 inputs
|
||||
@@ -359,8 +353,7 @@ def test_txprepare_restart(node_factory, bitcoind):
|
||||
with pytest.raises(RpcError, match=r'not an unreleased txid'):
|
||||
l1.rpc.txdiscard(prep['txid'])
|
||||
|
||||
prep = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx'])
|
||||
assert decode['txid'] == prep['txid']
|
||||
@@ -377,8 +370,7 @@ def test_txprepare_restart(node_factory, bitcoind):
|
||||
for i in decode['vin']:
|
||||
assert l1.daemon.is_in_log('wallet: reserved output {}/{} reset to available'.format(i['txid'], i['vout']))
|
||||
|
||||
prep = l1.rpc.txprepare('bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg',
|
||||
'all')
|
||||
prep = l1.rpc.txprepare([{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': 'all'}])
|
||||
decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx'])
|
||||
assert decode['txid'] == prep['txid']
|
||||
# All 10 inputs
|
||||
|
||||
@@ -216,6 +216,7 @@ class Type(FieldSet):
|
||||
'bitcoin_tx',
|
||||
'wirestring',
|
||||
'per_peer_state',
|
||||
'bitcoin_tx_output',
|
||||
]
|
||||
|
||||
# Some BOLT types are re-typed based on their field name
|
||||
|
||||
@@ -58,8 +58,8 @@ struct unreleased_tx {
|
||||
struct list_node list;
|
||||
/* All the utxos. */
|
||||
struct wallet_tx *wtx;
|
||||
/* Scriptpubkey this pays to. */
|
||||
const u8 *destination;
|
||||
/* Outputs(scriptpubkey and satoshi) this pays to. */
|
||||
struct bitcoin_tx_output **outputs;
|
||||
/* The tx itself (unsigned initially) */
|
||||
struct bitcoin_tx *tx;
|
||||
struct bitcoin_txid txid;
|
||||
|
||||
@@ -93,7 +93,9 @@ static struct command_result *param_bitcoin_address(struct command *cmd,
|
||||
scriptpubkey)) {
|
||||
case ADDRESS_PARSE_UNRECOGNIZED:
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"Could not parse destination address");
|
||||
"Could not parse destination address, "
|
||||
"%s should be a valid address",
|
||||
name ? name : "address field");
|
||||
case ADDRESS_PARSE_WRONG_NETWORK:
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"Destination address is not on network %s",
|
||||
@@ -117,7 +119,8 @@ static struct command_result *broadcast_and_wait(struct command *cmd,
|
||||
utx->wtx->amount,
|
||||
utx->wtx->change,
|
||||
utx->wtx->change_key_index,
|
||||
utx->destination,
|
||||
cast_const2(const struct bitcoin_tx_output **,
|
||||
utx->outputs),
|
||||
utx->wtx->utxos);
|
||||
|
||||
if (!wire_sync_write(cmd->ld->hsm_fd, take(msg)))
|
||||
@@ -152,36 +155,65 @@ static struct command_result *broadcast_and_wait(struct command *cmd,
|
||||
|
||||
/* Common code for withdraw and txprepare.
|
||||
*
|
||||
* Returns NULL on success, and fills in wtx, destination and
|
||||
* Returns NULL on success, and fills in wtx, output and
|
||||
* maybe changekey (owned by cmd). Otherwise, cmd has failed, so don't
|
||||
* access it! (It's been freed). */
|
||||
static struct command_result *json_prepare_tx(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *params,
|
||||
struct unreleased_tx **utx)
|
||||
struct unreleased_tx **utx,
|
||||
bool for_withdraw)
|
||||
{
|
||||
u32 *feerate_per_kw;
|
||||
struct command_result *res;
|
||||
u32 *minconf, maxheight;
|
||||
struct pubkey *changekey;
|
||||
struct bitcoin_tx_output **outputs;
|
||||
const jsmntok_t *outputstok, *t;
|
||||
const u8 *destination = NULL;
|
||||
size_t out_len, i;
|
||||
|
||||
*utx = tal(cmd, struct unreleased_tx);
|
||||
(*utx)->wtx = tal(*utx, struct wallet_tx);
|
||||
wtx_init(cmd, (*utx)->wtx, AMOUNT_SAT(-1ULL));
|
||||
outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, 0);
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("destination", param_bitcoin_address,
|
||||
&(*utx)->destination),
|
||||
p_req("satoshi", param_wtx, (*utx)->wtx),
|
||||
p_opt("feerate", param_feerate, &feerate_per_kw),
|
||||
p_opt_def("minconf", param_number, &minconf, 1),
|
||||
NULL))
|
||||
if (!for_withdraw) {
|
||||
/* From v0.7.3, the new style for *txprepare* use array of outputs
|
||||
* to replace original 'destination' and 'satoshi' parameters.*/
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("outputs", param_array, &outputstok),
|
||||
p_opt("feerate", param_feerate, &feerate_per_kw),
|
||||
p_opt_def("minconf", param_number, &minconf, 1),
|
||||
NULL)) {
|
||||
|
||||
/* For generating help, give new-style. */
|
||||
if (!params || !deprecated_apis)
|
||||
return command_param_failed();
|
||||
|
||||
/* For the old style:
|
||||
* *txprepare* 'destination' 'satoshi' ['feerate'] ['minconf'] */
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("destination", param_bitcoin_address,
|
||||
&destination),
|
||||
p_req("satoshi", param_wtx, (*utx)->wtx),
|
||||
p_opt("feerate", param_feerate, &feerate_per_kw),
|
||||
p_opt_def("minconf", param_number, &minconf, 1),
|
||||
NULL))
|
||||
/* If the parameters mixed the new style and the old style,
|
||||
* fail it. */
|
||||
return command_param_failed();
|
||||
}
|
||||
} else {
|
||||
/* *withdraw* command still use 'destination' and 'satoshi' as parameters. */
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("destination", param_bitcoin_address,
|
||||
&destination),
|
||||
p_req("satoshi", param_wtx, (*utx)->wtx),
|
||||
p_opt("feerate", param_feerate, &feerate_per_kw),
|
||||
p_opt_def("minconf", param_number, &minconf, 1),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
/* Destination is owned by cmd: change that to be owned by utx. */
|
||||
tal_steal(*utx, (*utx)->destination);
|
||||
}
|
||||
|
||||
if (!feerate_per_kw) {
|
||||
res = param_feerate_estimate(cmd, &feerate_per_kw,
|
||||
@@ -191,11 +223,97 @@ static struct command_result *json_prepare_tx(struct command *cmd,
|
||||
}
|
||||
|
||||
maxheight = minconf_to_maxheight(*minconf, cmd->ld);
|
||||
|
||||
/* *withdraw* command or old *txprepare* command.
|
||||
* Support only one output. */
|
||||
if (destination) {
|
||||
outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, 1);
|
||||
outputs[0] = tal(outputs, struct bitcoin_tx_output);
|
||||
outputs[0]->script = tal_steal(outputs[0],
|
||||
cast_const(u8 *, destination));
|
||||
outputs[0]->amount = (*utx)->wtx->amount;
|
||||
out_len = tal_count(outputs[0]->script);
|
||||
|
||||
goto create_tx;
|
||||
}
|
||||
|
||||
if (outputstok->size == 0)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Empty outputs");
|
||||
|
||||
outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, outputstok->size);
|
||||
out_len = 0;
|
||||
(*utx)->wtx->all_funds = false;
|
||||
(*utx)->wtx->amount = AMOUNT_SAT(0);
|
||||
json_for_each_arr(i, t, outputstok) {
|
||||
struct amount_sat *amount;
|
||||
const u8 *destination;
|
||||
enum address_parse_result res;
|
||||
|
||||
/* output format: {destination: amount} */
|
||||
if (t->type != JSMN_OBJECT)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"The output format must be "
|
||||
"{destination: amount}");;
|
||||
|
||||
res = json_tok_address_scriptpubkey(cmd,
|
||||
get_chainparams(cmd->ld),
|
||||
buffer, &t[1],
|
||||
&destination);
|
||||
if (res == ADDRESS_PARSE_UNRECOGNIZED)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Could not parse destination address");
|
||||
else if (res == ADDRESS_PARSE_WRONG_NETWORK)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Destination address is not on network %s",
|
||||
get_chainparams(cmd->ld)->network_name);
|
||||
|
||||
amount = tal(tmpctx, struct amount_sat);
|
||||
if (!json_to_sat_or_all(buffer, &t[2], amount))
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"'%.*s' is a invalid satoshi amount",
|
||||
t[2].end - t[2].start, buffer + t[2].start);
|
||||
|
||||
out_len += tal_count(destination);
|
||||
outputs[i] = tal(outputs, struct bitcoin_tx_output);
|
||||
outputs[i]->amount = *amount;
|
||||
outputs[i]->script = tal_steal(outputs[i],
|
||||
cast_const(u8 *, destination));
|
||||
|
||||
/* In fact, the maximum amount of bitcoin satoshi is 2.1e15.
|
||||
* It can't be equal to/bigger than 2^64.
|
||||
* On the hand, the maximum amount of litoshi is 8.4e15,
|
||||
* which also can't overflow. */
|
||||
/* This means this destination need "all" satoshi we have. */
|
||||
if (amount_sat_eq(*amount, AMOUNT_SAT(-1ULL))) {
|
||||
if (outputstok->size > 1)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"outputs[%zi]: this destination wants"
|
||||
" all satoshi. The count of outputs"
|
||||
" can't be more than 1. ", i);
|
||||
(*utx)->wtx->all_funds = true;
|
||||
/* `AMOUNT_SAT(-1ULL)` is the max permissible for `wallet_select_all`. */
|
||||
(*utx)->wtx->amount = *amount;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!amount_sat_add(&(*utx)->wtx->amount, (*utx)->wtx->amount, *amount))
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"outputs: The sum of first %zi outputs"
|
||||
" overflow. ", i);
|
||||
}
|
||||
|
||||
create_tx:
|
||||
(*utx)->outputs = tal_steal(*utx, outputs);
|
||||
res = wtx_select_utxos((*utx)->wtx, *feerate_per_kw,
|
||||
tal_count((*utx)->destination), maxheight);
|
||||
out_len, maxheight);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Because of the max limit of AMOUNT_SAT(-1ULL),
|
||||
* `(*utx)->wtx->all_funds` won't change in `wtx_select_utxos()` */
|
||||
if ((*utx)->wtx->all_funds)
|
||||
outputs[0]->amount = (*utx)->wtx->amount;
|
||||
|
||||
if (!amount_sat_eq((*utx)->wtx->change, AMOUNT_SAT(0))) {
|
||||
changekey = tal(tmpctx, struct pubkey);
|
||||
if (!bip32_pubkey(cmd->ld->wallet->bip32_base, changekey,
|
||||
@@ -203,15 +321,8 @@ static struct command_result *json_prepare_tx(struct command *cmd,
|
||||
return command_fail(cmd, LIGHTNINGD, "Keys generation failure");
|
||||
} else
|
||||
changekey = NULL;
|
||||
|
||||
struct bitcoin_tx_output *output = tal(outputs,
|
||||
struct bitcoin_tx_output);
|
||||
output->script = tal_dup_arr(output, u8, (*utx)->destination,
|
||||
tal_count((*utx)->destination), 0);
|
||||
output->amount = (*utx)->wtx->amount;
|
||||
tal_arr_expand(&outputs, output);
|
||||
(*utx)->tx = withdraw_tx(*utx, get_chainparams(cmd->ld),
|
||||
(*utx)->wtx->utxos, outputs,
|
||||
(*utx)->wtx->utxos, (*utx)->outputs,
|
||||
changekey, (*utx)->wtx->change,
|
||||
cmd->ld->wallet->bip32_base,
|
||||
&(*utx)->change_outnum);
|
||||
@@ -229,7 +340,7 @@ static struct command_result *json_txprepare(struct command *cmd,
|
||||
struct command_result *res;
|
||||
struct json_stream *response;
|
||||
|
||||
res = json_prepare_tx(cmd, buffer, params, &utx);
|
||||
res = json_prepare_tx(cmd, buffer, params, &utx, false);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
@@ -352,7 +463,7 @@ static struct command_result *json_withdraw(struct command *cmd,
|
||||
struct command_result *res;
|
||||
struct bitcoin_txid txid;
|
||||
|
||||
res = json_prepare_tx(cmd, buffer, params, &utx);
|
||||
res = json_prepare_tx(cmd, buffer, params, &utx, true);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
|
||||
@@ -378,3 +378,14 @@ void fromwire_bip32_key_version(const u8** cursor, size_t *max,
|
||||
version->bip32_pubkey_version = fromwire_u32(cursor, max);
|
||||
version->bip32_privkey_version = fromwire_u32(cursor, max);
|
||||
}
|
||||
|
||||
struct bitcoin_tx_output *fromwire_bitcoin_tx_output(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max)
|
||||
{
|
||||
struct bitcoin_tx_output *output = tal(ctx, struct bitcoin_tx_output);
|
||||
output->amount = fromwire_amount_sat(cursor, max);
|
||||
u16 script_len = fromwire_u16(cursor, max);
|
||||
output->script = tal_arr(output, u8, script_len);
|
||||
fromwire_u8_array(cursor, max, output->script, script_len);
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -249,3 +249,10 @@ void towire_bip32_key_version(u8 **pptr, const struct bip32_key_version *version
|
||||
towire_u32(pptr, version->bip32_pubkey_version);
|
||||
towire_u32(pptr, version->bip32_privkey_version);
|
||||
}
|
||||
|
||||
void towire_bitcoin_tx_output(u8 **pptr, const struct bitcoin_tx_output *output)
|
||||
{
|
||||
towire_amount_sat(pptr, output->amount);
|
||||
towire_u16(pptr, tal_count(output->script));
|
||||
towire_u8_array(pptr, output->script, tal_count(output->script));
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ void towire_wirestring(u8 **pptr, const char *str);
|
||||
void towire_siphash_seed(u8 **cursor, const struct siphash_seed *seed);
|
||||
|
||||
void towire_bip32_key_version(u8 **cursor, const struct bip32_key_version *version);
|
||||
void towire_bitcoin_tx_output(u8 **pptr, const struct bitcoin_tx_output *output);
|
||||
|
||||
const u8 *fromwire(const u8 **cursor, size_t *max, void *copy, size_t n);
|
||||
u8 fromwire_u8(const u8 **cursor, size_t *max);
|
||||
@@ -138,4 +139,6 @@ void fromwire_siphash_seed(const u8 **cursor, size_t *max,
|
||||
struct siphash_seed *seed);
|
||||
void fromwire_bip32_key_version(const u8 **cursor, size_t *max,
|
||||
struct bip32_key_version *version);
|
||||
struct bitcoin_tx_output *fromwire_bitcoin_tx_output(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
#endif /* LIGHTNING_WIRE_WIRE_H */
|
||||
|
||||
Reference in New Issue
Block a user