df-open: pathway for getting a commit back from peer

Goes all the way back to where we save it to the database and return
whatever command kicked this off
This commit is contained in:
niftynei 2020-09-10 14:31:24 -05:00 committed by Rusty Russell
parent 3a405c33e6
commit a7f29f30db
2 changed files with 327 additions and 7 deletions

View File

@ -889,6 +889,122 @@ failed:
tal_free(uc);
}
static void opener_commit_received(struct subd *dualopend,
struct uncommitted_channel *uc,
const int *fds,
const u8 *msg)
{
struct lightningd *ld = dualopend->ld;
struct channel_info channel_info;
struct bitcoin_tx *remote_commit;
struct bitcoin_signature remote_commit_sig;
struct channel_id cid;
struct bitcoin_txid funding_txid;
struct per_peer_state *pps;
struct json_stream *response;
u16 funding_outnum;
u32 feerate;
struct amount_sat total_funding, funding_ours, channel_reserve;
u8 channel_flags, *remote_upfront_shutdown_script,
*local_upfront_shutdown_script, *commitment_msg;
struct penalty_base *pbase;
struct wally_psbt *psbt;
struct channel *channel;
char *err_reason;
/* This is a new channel_info.their_config so set its ID to 0 */
channel_info.their_config.id = 0;
if (!fromwire_dual_open_commit_rcvd(tmpctx, msg,
&channel_info.their_config,
&remote_commit,
&pbase,
&remote_commit_sig,
&psbt,
&cid,
&pps,
&channel_info.theirbase.revocation,
&channel_info.theirbase.payment,
&channel_info.theirbase.htlc,
&channel_info.theirbase.delayed_payment,
&channel_info.remote_per_commit,
&channel_info.remote_fundingkey,
&funding_txid,
&funding_outnum,
&total_funding,
&funding_ours,
&channel_flags,
&feerate,
&commitment_msg,
&channel_reserve,
&local_upfront_shutdown_script,
&remote_upfront_shutdown_script)) {
log_broken(uc->log, "bad WIRE_DUAL_OPEN_COMMIT_RCVD %s",
tal_hex(msg, msg));
err_reason = "bad WIRE_DUAL_OPEN_COMMIT_RCVD";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
close(fds[0]);
close(fds[1]);
close(fds[3]);
goto failed;
}
/* We shouldn't have a commitment message, this is an
* accepter flow item */
assert(!commitment_msg);
per_peer_state_set_fds_arr(pps, fds);
if (peer_active_channel(uc->peer)) {
err_reason = "already have active channel";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
goto failed;
}
/* Our end game is to save the channel to the database, and return the
* command with 'commitments_secured' set to true */
channel = wallet_commit_channel(ld, uc, &cid,
remote_commit,
&remote_commit_sig,
&funding_txid,
funding_outnum,
total_funding,
funding_ours,
channel_flags,
&channel_info,
feerate,
LOCAL,
local_upfront_shutdown_script,
remote_upfront_shutdown_script);
if (!channel) {
err_reason = "commit channel failed";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
goto failed;
}
if (pbase)
wallet_penalty_base_add(ld->wallet, channel->dbid, pbase);
response = json_stream_success(uc->fc->cmd);
json_add_string(response, "channel_id",
type_to_string(tmpctx, struct channel_id, &cid));
json_add_psbt(response, "psbt", psbt);
json_add_bool(response, "commitments_secured", true);
was_pending(command_success(uc->fc->cmd, response));
subd_release_channel(dualopend, uc);
uc->open_daemon = NULL;
tal_free(uc);
return;
failed:
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD,
"%s", err_reason));
subd_release_channel(dualopend, uc);
uc->open_daemon = NULL;
tal_free(uc);
}
static void accepter_psbt_changed(struct subd *dualopend,
const u8 *msg)
{
@ -1127,7 +1243,19 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUAL_OPEN_COMMIT_RCVD:
if (tal_count(fds) != 3)
return 3;
accepter_commit_received(dualopend, uc, fds, msg);
if (uc->fc) {
if (!uc->fc->cmd) {
log_unusual(dualopend->log,
"Unexpected COMMIT_RCVD %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return 0;
}
opener_commit_received(dualopend,
uc, fds, msg);
} else
accepter_commit_received(dualopend,
uc, fds, msg);
return 0;
case WIRE_DUAL_OPEN_FAILED:
case WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY:

View File

@ -1245,12 +1245,18 @@ static u8 *opener_start(struct state *state, u8 *msg)
struct channel_id cid;
char *err_reason;
struct amount_sat total;
struct amount_msat our_msats;
struct wally_psbt *psbt;
struct wally_psbt_output *funding_out;
u8 channel_flags;
const u8 *wscript;
u16 serial_id;
struct sha256 podle;
struct wally_tx_output *direct_outputs[NUM_SIDES];
struct penalty_base *pbase;
u8 channel_flags;
const u8 *wscript;
struct bitcoin_tx *remote_commit, *local_commit;
struct bitcoin_signature remote_sig, local_sig;
secp256k1_ecdsa_signature *htlc_sigs;
if (!fromwire_dual_open_opener_init(state, msg,
&psbt,
@ -1407,15 +1413,201 @@ static u8 *opener_start(struct state *state, u8 *msg)
/* Send our first message, we're opener we initiate here */
if (send_next(state, &psbt))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Must have at least one update to send");
negotiation_failed(state, true,
"Peer error, no updates to send");
/* Figure out what the funding transaction looks like! */
if (!run_tx_interactive(state, &psbt, TX_INITIATOR))
return NULL;
/* FIXME! */
return NULL;
psbt_txid(NULL, psbt, &state->funding_txid, NULL);
/* Figure out the txout */
if (!find_txout(psbt, scriptpubkey_p2wsh(tmpctx, wscript),
&state->funding_txout))
peer_failed(state->pps, &state->channel_id,
"Expected output %s not found on funding tx %s",
tal_hex(tmpctx, scriptpubkey_p2wsh(tmpctx, wscript)),
type_to_string(tmpctx, struct wally_psbt, psbt));
/* Check that their amounts are sane */
if (!check_balances(state, psbt, true, true,
state->feerate_per_kw_funding))
negotiation_failed(state, true, "Insufficient funds");
if (!amount_sat_to_msat(&our_msats, state->opener_funding))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Rounding error, can't convert opener_funding %s"
" to msats",
type_to_string(tmpctx, struct amount_sat,
&state->opener_funding));
/* Ok, we're mostly good now? Let's do this */
state->channel = new_initial_channel(state,
&cid,
&state->funding_txid,
state->funding_txout,
state->minimum_depth,
total,
our_msats,
take(new_fee_states(NULL, LOCAL,
&state->feerate_per_kw)),
&state->localconf,
&state->remoteconf,
&state->our_points,
&state->their_points,
&state->our_funding_pubkey,
&state->their_funding_pubkey,
true, true,
/* Opener is local */
LOCAL);
remote_commit = initial_channel_tx(state, &wscript,
state->channel,
&state->first_per_commitment_point[REMOTE],
REMOTE, direct_outputs, &err_reason);
if (!remote_commit) {
negotiation_failed(state, true,
"Could not meet their fees and reserve: %s",
err_reason);
return NULL;
}
/* We ask the HSM to sign their commitment transaction for us: it knows
* our funding key, it just needs the remote funding key to create the
* witness script. It also needs the amount of the funding output,
* as segwit signatures commit to that as well, even though it doesn't
* explicitly appear in the transaction itself. */
msg = towire_hsmd_sign_remote_commitment_tx(NULL,
remote_commit,
&state->channel->funding_pubkey[REMOTE],
&state->first_per_commitment_point[REMOTE],
true);
wire_sync_write(HSM_FD, take(msg));
msg = wire_sync_read(tmpctx, HSM_FD);
if (!fromwire_hsmd_sign_tx_reply(msg, &local_sig))
status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s",
tal_hex(tmpctx, msg));
/* You can tell this has been a problem before, since there's a debug
* message here: */
status_debug("signature %s on tx %s using key %s",
type_to_string(tmpctx, struct bitcoin_signature, &local_sig),
type_to_string(tmpctx, struct bitcoin_tx, remote_commit),
type_to_string(tmpctx, struct pubkey,
&state->our_funding_pubkey));
assert(local_sig.sighash_type == SIGHASH_ALL);
msg = towire_commitment_signed(tmpctx, &state->channel_id,
&local_sig.s,
NULL);
sync_crypto_write(state->pps, msg);
peer_billboard(false, "channel open: commitment sent, waiting for reply");
/* Wait for the peer to send us our commitment tx signature */
msg = opening_negotiate_msg(tmpctx, state, true);
if (!msg)
return NULL;
remote_sig.sighash_type = SIGHASH_ALL;
if (!fromwire_commitment_signed(tmpctx, msg, &cid,
&remote_sig.s,
&htlc_sigs))
peer_failed(state->pps, &state->channel_id,
"Parsing commitment signed %s",
tal_hex(tmpctx, msg));
if (htlc_sigs != NULL)
peer_failed(state->pps, &state->channel_id,
"Must not send HTLCs with first"
" commitment. %s",
tal_hex(tmpctx, msg));
local_commit = initial_channel_tx(state, &wscript, state->channel,
&state->first_per_commitment_point[LOCAL],
LOCAL, NULL, &err_reason);
/* This shouldn't happen either, AFAICT. */
if (!local_commit) {
negotiation_failed(state, false,
"Could not meet our fees and reserve: %s",
err_reason);
return NULL;
}
/* BOLT #2:
*
* The recipient:
* - if `signature` is incorrect:
* - MUST fail the channel.
*/
if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey,
&remote_sig)) {
/* BOLT #1:
*
* ### The `error` Message
*...
* - when failure was caused by an invalid signature check:
* - SHOULD include the raw, hex-encoded transaction in reply
* to a `funding_created`, `funding_signed`,
* `closing_signed`, or `commitment_signed` message.
*/
/*~ This verbosity is not only useful for our own testing, but
* a courtesy to other implementaters whose brains may be so
* twisted by coding in Go, Scala and Rust that they can no
* longer read C code. */
peer_failed(state->pps,
&state->channel_id,
"Bad signature %s on tx %s using key %s (funding txid %s, psbt %s)",
type_to_string(tmpctx, struct bitcoin_signature,
&remote_sig),
type_to_string(tmpctx, struct bitcoin_tx, local_commit),
type_to_string(tmpctx, struct pubkey,
&state->their_funding_pubkey),
/* This is the first place we'd discover the funding tx
* doesn't match up */
type_to_string(tmpctx, struct bitcoin_txid,
&state->funding_txid),
type_to_string(tmpctx, struct wally_psbt,
psbt));
}
if (direct_outputs[LOCAL])
pbase = penalty_base_new(state, 0, remote_commit,
direct_outputs[LOCAL]);
else
pbase = NULL;
peer_billboard(false, "channel open: commitment received, "
"sending to lightningd to save");
return towire_dual_open_commit_rcvd(state,
&state->remoteconf,
remote_commit,
pbase,
&remote_sig,
psbt,
&state->channel_id,
state->pps,
&state->their_points.revocation,
&state->their_points.payment,
&state->their_points.htlc,
&state->their_points.delayed_payment,
&state->first_per_commitment_point[REMOTE],
&state->their_funding_pubkey,
&state->funding_txid,
state->funding_txout,
total,
state->opener_funding,
channel_flags,
state->feerate_per_kw,
NULL,
state->localconf.channel_reserve,
state->upfront_shutdown_script[LOCAL],
state->upfront_shutdown_script[REMOTE]);
}
/* Memory leak detection is DEVELOPER-only because we go to great lengths to