Browse Source

hsm: Generate fully signed transactions and return them to caller

So far we have been generating the tx both in the HSM and in the
caller, and had to rely on them generating exactly the same
transaction. This makes it a lot simpler by fully signing and
serializing the TX on the HSM side and the caller just needs to unpack
and broadcast it.

Signed-off-by: Christian Decker <decker.christian@gmail.com>
ppa-0.6.1
Christian Decker 7 years ago
parent
commit
ce845853b0
  1. 23
      hsmd/hsm.c
  2. 3
      hsmd/hsm_client_wire_csv
  3. 40
      wallet/walletrpc.c

23
hsmd/hsm.c

@ -601,8 +601,8 @@ static void sign_withdrawal_tx(struct daemon_conn *master, const u8 *msg)
u32 change_keyindex; u32 change_keyindex;
struct utxo *inutxos; struct utxo *inutxos;
const struct utxo **utxos; const struct utxo **utxos;
secp256k1_ecdsa_signature *sigs;
u8 *wscript; u8 *wscript;
u8 **scriptSigs;
struct bitcoin_tx *tx; struct bitcoin_tx *tx;
struct ext_key ext; struct ext_key ext;
struct pubkey changekey; struct pubkey changekey;
@ -630,13 +630,13 @@ static void sign_withdrawal_tx(struct daemon_conn *master, const u8 *msg)
tmpctx, utxos, scriptpubkey, satoshi_out, tmpctx, utxos, scriptpubkey, satoshi_out,
&changekey, change_out, NULL); &changekey, change_out, NULL);
/* Now generate signatures. */ scriptSigs = tal_arr(tmpctx, u8*, tal_count(utxos));
sigs = tal_arr(tmpctx, secp256k1_ecdsa_signature, tal_count(utxos));
for (size_t i = 0; i < tal_count(utxos); i++) { for (size_t i = 0; i < tal_count(utxos); i++) {
struct pubkey inkey; struct pubkey inkey;
struct privkey inprivkey; struct privkey inprivkey;
const struct utxo *in = utxos[i]; const struct utxo *in = utxos[i];
u8 *subscript; u8 *subscript;
secp256k1_ecdsa_signature sig;
bitcoin_keypair(&inprivkey, &inkey, in->keyindex); bitcoin_keypair(&inprivkey, &inkey, in->keyindex);
if (utxos[i]->is_p2sh) if (utxos[i]->is_p2sh)
@ -645,12 +645,23 @@ static void sign_withdrawal_tx(struct daemon_conn *master, const u8 *msg)
subscript = NULL; subscript = NULL;
wscript = p2wpkh_scriptcode(tmpctx, &inkey); wscript = p2wpkh_scriptcode(tmpctx, &inkey);
sign_tx_input(tx, i, subscript, wscript, sign_tx_input(tx, i, subscript, wscript, &inprivkey, &inkey,
&inprivkey, &inkey, &sigs[i]); &sig);
tx->input[i].witness = bitcoin_witness_p2wpkh(tx, &sig, &inkey);
if (utxos[i]->is_p2sh)
scriptSigs[i] = bitcoin_scriptsig_p2sh_p2wpkh(tx, &inkey);
else
scriptSigs[i] = NULL;
} }
/* Now complete the transaction by attaching the scriptSigs where necessary */
for (size_t i=0; i<tal_count(utxos); i++)
tx->input[i].script = scriptSigs[i];
daemon_conn_send(master, daemon_conn_send(master,
take(towire_hsm_sign_withdrawal_reply(tmpctx, sigs))); take(towire_hsm_sign_withdrawal_reply(tmpctx, tx)));
tal_free(tmpctx); tal_free(tmpctx);
} }

3
hsmd/hsm_client_wire_csv

@ -57,8 +57,7 @@ hsm_sign_withdrawal,,num_inputs,u16
hsm_sign_withdrawal,,inputs,num_inputs*struct utxo hsm_sign_withdrawal,,inputs,num_inputs*struct utxo
hsm_sign_withdrawal_reply,107 hsm_sign_withdrawal_reply,107
hsm_sign_withdrawal_reply,,num_sigs,u16 hsm_sign_withdrawal_reply,,tx,struct bitcoin_tx
hsm_sign_withdrawal_reply,,sig,num_sigs*secp256k1_ecdsa_signature
# Sign an invoice # Sign an invoice
hsm_sign_invoice,8 hsm_sign_invoice,8

40
wallet/walletrpc.c

@ -194,9 +194,6 @@ static void json_withdraw(struct command *cmd,
u32 feerate_per_kw = get_feerate(cmd->ld->topology, FEERATE_NORMAL); u32 feerate_per_kw = get_feerate(cmd->ld->topology, FEERATE_NORMAL);
u64 fee_estimate; u64 fee_estimate;
struct utxo *utxos; struct utxo *utxos;
struct ext_key ext;
struct pubkey changekey;
secp256k1_ecdsa_signature *sigs;
struct bitcoin_tx *tx; struct bitcoin_tx *tx;
bool withdraw_all = false; bool withdraw_all = false;
@ -293,43 +290,12 @@ static void json_withdraw(struct command *cmd,
msg = hsm_sync_read(cmd, cmd->ld); msg = hsm_sync_read(cmd, cmd->ld);
if (!fromwire_hsm_sign_withdrawal_reply(withdraw, msg, NULL, &sigs)) tx = tal(withdraw, struct bitcoin_tx);
if (!fromwire_hsm_sign_withdrawal_reply(msg, NULL, tx))
fatal("HSM gave bad sign_withdrawal_reply %s", fatal("HSM gave bad sign_withdrawal_reply %s",
tal_hex(withdraw, msg)); tal_hex(withdraw, msg));
if (withdraw->changesatoshi) {
if (bip32_key_from_parent(cmd->ld->wallet->bip32_base,
withdraw->change_key_index,
BIP32_FLAG_KEY_PUBLIC, &ext)
!= WALLY_OK) {
command_fail(cmd, "Changekey generation failure");
return;
}
pubkey_from_der(ext.pub_key, sizeof(ext.pub_key), &changekey);
}
tx = withdraw_tx(withdraw, withdraw->utxos, withdraw->destination,
withdraw->amount, &changekey, withdraw->changesatoshi,
cmd->ld->wallet->bip32_base);
if (tal_count(sigs) != tal_count(tx->input))
fatal("HSM gave %zu sigs, needed %zu",
tal_count(sigs), tal_count(tx->input));
/* Create input parts from signatures. */
for (size_t i = 0; i < tal_count(tx->input); i++) {
struct pubkey key;
if (!bip32_pubkey(cmd->ld->wallet->bip32_base,
&key, withdraw->utxos[i]->keyindex))
fatal("Cannot generate BIP32 key for UTXO %u",
withdraw->utxos[i]->keyindex);
/* P2SH inputs have same witness. */
tx->input[i].witness
= bitcoin_witness_p2wpkh(tx, &sigs[i], &key);
}
/* Now broadcast the transaction */ /* Now broadcast the transaction */
withdraw->hextx = tal_hex(withdraw, linearize_tx(cmd, tx)); withdraw->hextx = tal_hex(withdraw, linearize_tx(cmd, tx));
bitcoind_sendrawtx(cmd->ld->topology->bitcoind, withdraw->hextx, bitcoind_sendrawtx(cmd->ld->topology->bitcoind, withdraw->hextx,

Loading…
Cancel
Save