Skip to content

Commit f2467f1

Browse files
committed
withdraw: add ability to have additional inputs on a tx
Make it such that we can include other inputs on a transaction, sort them, and sign the ones we need. We're going to need this for dual-funded transactions.
1 parent 6a8eb06 commit f2467f1

File tree

11 files changed

+151
-14
lines changed

11 files changed

+151
-14
lines changed

bitcoin/tx.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ struct bitcoin_tx_input {
3939
u8 *script;
4040
u32 sequence_number;
4141

42-
/* Only if BIP141 used. */
42+
/* If BIP141 used, or is external input */
4343
u8 **witness;
44+
45+
/* Needed for external inputs */
46+
struct amount_sat amount;
4447
};
4548

4649
struct bitcoin_tx_output *new_tx_output(const tal_t *ctx,

common/withdraw_tx.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
struct bitcoin_tx *withdraw_tx(const tal_t *ctx,
1414
const struct chainparams *chainparams,
1515
const struct utxo **utxos,
16+
struct bitcoin_tx_input **inputs,
1617
struct bitcoin_tx_output **outputs,
17-
const struct ext_key *bip32_base)
18+
const struct ext_key *bip32_base,
19+
const void **input_map)
1820
{
1921
struct bitcoin_tx *tx;
2022
struct pubkey key;
@@ -41,11 +43,19 @@ struct bitcoin_tx *withdraw_tx(const tal_t *ctx,
4143
utxos[i]->amount, script);
4244
}
4345

46+
/* Add 3rd party inputs */
47+
for (i = 0; i < tal_count(inputs); i++) {
48+
bitcoin_tx_add_input(tx, &inputs[i]->txid,
49+
inputs[i]->index, inputs[i]->sequence_number,
50+
inputs[i]->amount, inputs[i]->script);
51+
}
52+
4453
bitcoin_tx_add_multi_outputs(tx, outputs);
4554
permute_outputs(tx, NULL, (const void **)outputs);
4655

47-
permute_inputs(tx, (const void **)utxos);
56+
permute_inputs(tx, input_map);
4857
elements_tx_add_fee_output(tx);
58+
4959
assert(bitcoin_tx_check(tx));
5060
return tx;
5161
}

common/withdraw_tx.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ struct utxo;
2020
* @ctx: context to tal from.
2121
* @chainparams: (in) the params for the created transaction.
2222
* @utxos: (in/out) tal_arr of UTXO pointers to spend (permuted to match)
23+
* @inputs: (in) tal_arr of inputs for this transaction, in addition to utxos.
2324
* @outputs: (in) tal_arr of bitcoin_tx_output, scriptPubKeys with amount to send to.
2425
* @bip32_base: (in) bip32 base for key derivation, or NULL.
2526
*/
2627
struct bitcoin_tx *withdraw_tx(const tal_t *ctx,
2728
const struct chainparams *chainparams,
2829
const struct utxo **utxos,
30+
struct bitcoin_tx_input **inputs,
2931
struct bitcoin_tx_output **outputs,
30-
const struct ext_key *bip32_base);
32+
const struct ext_key *bip32_base,
33+
const void **input_map);
3134

3235
#endif /* LIGHTNING_COMMON_WITHDRAW_TX_H */

hsmd/hsm_wire.csv

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ msgdata,hsm_node_announcement_sig_reply,signature,secp256k1_ecdsa_signature,
6767

6868
# Sign a withdrawal request
6969
msgtype,hsm_sign_withdrawal,7
70+
msgdata,hsm_sign_withdrawal,num_inputs,u16,
71+
msgdata,hsm_sign_withdrawal,inputs,bitcoin_tx_input,num_inputs
7072
msgdata,hsm_sign_withdrawal,num_outputs,u16,
7173
msgdata,hsm_sign_withdrawal,outputs,bitcoin_tx_output,num_outputs
72-
msgdata,hsm_sign_withdrawal,num_inputs,u16,
73-
msgdata,hsm_sign_withdrawal,inputs,utxo,num_inputs
74+
msgdata,hsm_sign_withdrawal,num_utxos,u16,
75+
msgdata,hsm_sign_withdrawal,utxos,utxo,num_utxos
7476

7577
msgtype,hsm_sign_withdrawal_reply,107
7678
msgdata,hsm_sign_withdrawal_reply,tx,bitcoin_tx,

hsmd/hsmd.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,36 @@ static void sign_all_inputs(struct bitcoin_tx *tx, struct utxo **utxos)
15921592
}
15931593
}
15941594

1595+
/* For dual-funded transactions, we don't sign every input. Instead,
1596+
* we find the inputs that correspond with the utxos we have and sign
1597+
* only those
1598+
* */
1599+
static void sign_our_inputs(struct bitcoin_tx *tx, struct utxo **utxos,
1600+
const void **map, size_t map_len)
1601+
{
1602+
size_t i, j;
1603+
int input_index;
1604+
1605+
assert(tx->wtx->num_inputs >= tal_count(utxos));
1606+
assert(tal_count(utxos) <= map_len);
1607+
1608+
/* We add utxos to the tx first, and then any other
1609+
* inputs. Thus, we can iterate through the map from zero upward
1610+
* to find the correct utxo placement to sign */
1611+
for (i = 0; i < tal_count(utxos); i++) {
1612+
struct pubkey inkey;
1613+
struct bitcoin_signature sig;
1614+
1615+
for (j = 0; j < map_len; j++) {
1616+
if (ptr2int(map[j]) == i) {
1617+
input_index = j;
1618+
break;
1619+
}
1620+
}
1621+
sign_input(tx, utxos[i], &inkey, &sig, input_index);
1622+
}
1623+
}
1624+
15951625
/*~ lightningd asks us to sign the transaction to fund a channel; it feeds us
15961626
* the set of inputs and the local and remote pubkeys, and we sign it. */
15971627
static struct io_plan *handle_sign_funding_tx(struct io_conn *conn,
@@ -1642,17 +1672,45 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn,
16421672
{
16431673
struct utxo **utxos;
16441674
struct bitcoin_tx *tx;
1675+
struct bitcoin_tx_input **inputs;
16451676
struct bitcoin_tx_output **outputs;
1677+
size_t input_count, i, j;
1678+
int input_index;
16461679

16471680
if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in,
1648-
&outputs, &utxos))
1681+
&inputs, &outputs,
1682+
&utxos))
16491683
return bad_req(conn, c, msg_in);
16501684

1685+
input_count = tal_count(utxos) + tal_count(inputs);
1686+
const void *map[input_count];
1687+
for (i = 0; i < input_count; i++)
1688+
map[i] = int2ptr(i);
1689+
16511690
tx = withdraw_tx(tmpctx, c->chainparams,
16521691
cast_const2(const struct utxo **, utxos),
1653-
outputs, NULL);
1654-
1655-
sign_all_inputs(tx, utxos);
1692+
inputs, outputs, NULL,
1693+
(const void **)&map);
1694+
1695+
/* Put our signatures on the transaction */
1696+
sign_our_inputs(tx, utxos, (const void **)&map, input_count);
1697+
1698+
/* Add any 3rd party signatures */
1699+
for (i = 0; i < tal_count(inputs); i++) {
1700+
if (inputs[i]->witness) {
1701+
size_t offset = tal_count(utxos) + i;
1702+
1703+
/* Find the index */
1704+
for (j = 0; j < input_count; j++) {
1705+
if (ptr2int(map[j]) == offset) {
1706+
input_index = j;
1707+
break;
1708+
}
1709+
}
1710+
bitcoin_tx_input_set_witness(tx, input_index,
1711+
inputs[i]->witness);
1712+
}
1713+
}
16561714

16571715
return req_reply(conn, c,
16581716
take(towire_hsm_sign_withdrawal_reply(NULL, tx)));

tools/generate-wire.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ class Type(FieldSet):
221221
'per_peer_state',
222222
'bitcoin_tx_output',
223223
'exclude_entry',
224+
'bitcoin_tx_input',
224225
]
225226

226227
# Some BOLT types are re-typed based on their field name

wallet/wallet.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ struct unreleased_tx {
6060
struct wallet_tx *wtx;
6161
/* Outputs(scriptpubkey and satoshi) this pays to. */
6262
struct bitcoin_tx_output **outputs;
63+
/* Non-utxo inputs for this tx (i.e. not our wallet) */
64+
struct bitcoin_tx_input **inputs;
6365
/* The tx itself (unsigned initially) */
6466
struct bitcoin_tx *tx;
6567
struct bitcoin_txid txid;

wallet/walletrpc.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ static struct command_result *broadcast_and_wait(struct command *cmd,
8181
struct bitcoin_tx *signed_tx;
8282
struct bitcoin_txid signed_txid;
8383

84+
/* Build input set */
85+
if (!utx->inputs)
86+
utx->inputs = tal_arr(utx, struct bitcoin_tx_input *, 0);
87+
8488
/* FIXME: hsm will sign almost anything, but it should really
8589
* fail cleanly (not abort!) and let us report the error here. */
8690
u8 *msg = towire_hsm_sign_withdrawal(cmd,
91+
cast_const2(const struct bitcoin_tx_input **,
92+
utx->inputs),
8793
cast_const2(const struct bitcoin_tx_output **,
8894
utx->outputs),
8995
utx->wtx->utxos);
@@ -394,8 +400,10 @@ static struct command_result *json_prepare_tx(struct command *cmd,
394400
(*utx)->outputs = tal_steal(*utx, outputs);
395401
(*utx)->tx = withdraw_tx(*utx, get_chainparams(cmd->ld),
396402
(*utx)->wtx->utxos,
403+
(*utx)->inputs,
397404
(*utx)->outputs,
398-
cmd->ld->wallet->bip32_base);
405+
cmd->ld->wallet->bip32_base,
406+
NULL);
399407

400408
bitcoin_txid((*utx)->tx, &(*utx)->txid);
401409

wire/fromwire.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,12 @@ void fromwire_bip32_key_version(const u8** cursor, size_t *max,
384384
struct bitcoin_tx_output *fromwire_bitcoin_tx_output(const tal_t *ctx,
385385
const u8 **cursor, size_t *max)
386386
{
387+
u16 script_len;
388+
387389
struct bitcoin_tx_output *output = tal(ctx, struct bitcoin_tx_output);
388390
output->amount = fromwire_amount_sat(cursor, max);
389-
u16 script_len = fromwire_u16(cursor, max);
390-
output->script = tal_arr(output, u8, script_len);
391+
script_len = fromwire_u16(cursor, max);
392+
output->script = script_len ? tal_arr(output, u8, script_len) : NULL;
391393
fromwire_u8_array(cursor, max, output->script, script_len);
392394
return output;
393395
}
@@ -399,3 +401,30 @@ void fromwire_chainparams(const u8 **cursor, size_t *max,
399401
fromwire_bitcoin_blkid(cursor, max, &genesis);
400402
*chainparams = chainparams_by_chainhash(&genesis);
401403
}
404+
405+
struct bitcoin_tx_input *fromwire_bitcoin_tx_input(const tal_t *ctx,
406+
const u8 **cursor, size_t *max)
407+
{
408+
u16 script_len;
409+
u16 witness_count;
410+
u16 witness_len;
411+
412+
struct bitcoin_tx_input *input = tal(ctx, struct bitcoin_tx_input);
413+
414+
fromwire_bitcoin_txid(cursor, max, &input->txid);
415+
input->index = fromwire_u32(cursor, max);
416+
script_len = fromwire_u16(cursor, max);
417+
input->script = script_len ? tal_arr(input, u8, script_len) : NULL;
418+
fromwire_u8_array(cursor, max, input->script, script_len);
419+
input->sequence_number = fromwire_u32(cursor, max);
420+
421+
witness_count = fromwire_u16(cursor, max);
422+
input->witness = witness_count ? tal_arr(input, u8 *, witness_count) : NULL;
423+
for (size_t i = 0; i < witness_count; i++) {
424+
witness_len = fromwire_u16(cursor, max);
425+
input->witness[i] = witness_len ? tal_arr(input->witness, u8, witness_len) : NULL;
426+
fromwire_u8_array(cursor, max, input->witness[i], witness_len);
427+
}
428+
input->amount = fromwire_amount_sat(cursor, max);
429+
return input;
430+
}

wire/towire.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,22 @@ void towire_chainparams(u8 **cursor, const struct chainparams *chainparams)
261261
{
262262
towire_bitcoin_blkid(cursor, &chainparams->genesis_blockhash);
263263
}
264+
265+
void towire_bitcoin_tx_input(u8 **pptr, const struct bitcoin_tx_input *input)
266+
{
267+
u16 script_len = tal_count(input->script);
268+
u16 witness_len;
269+
270+
towire_bitcoin_txid(pptr, &input->txid);
271+
towire_u32(pptr, input->index);
272+
towire_u16(pptr, script_len);
273+
towire_u8_array(pptr, input->script, script_len);
274+
towire_u32(pptr, input->sequence_number);
275+
towire_u16(pptr, tal_count(input->witness));
276+
for (size_t i = 0; i < tal_count(input->witness); i++) {
277+
witness_len = tal_count(input->witness[i]);
278+
towire_u16(pptr, witness_len);
279+
towire_u8_array(pptr, input->witness[i], witness_len);
280+
}
281+
towire_amount_sat(pptr, input->amount);
282+
}

0 commit comments

Comments
 (0)