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:
parent
3a405c33e6
commit
a7f29f30db
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue