mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-01 03:24:41 +01:00
d2b4e09e27
d822ba1ee
accidentally removed this case, which is important: if the
other side didn't get our final matching closing_signed, it will
reconnect and try again. We consider the channel no longer "active"
and thus ignore it, and get upset when it send the
`channel_reestablish` message.
We could just consider CLOSINGD_COMPLETE to be active, but then we'd
have to wait for the closing transaction to be mined before we'd allow
another connection.
We can't special case it when the peer reconnects, because there
could be (in theory) multiple channels for that peer in CLOSINGD_COMPLETE,
and we don't know which one to reestablish.
So, we need to catch this when they send the reestablish, and hand
that msg to closingd to do negotiation again. We already have code
to note that we're in CLOSINGD_COMPLETE and thus ignore any result
it gives us.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
597 lines
17 KiB
C
597 lines
17 KiB
C
/* FIXME: We don't relay from gossipd at all here. */
|
|
#include <bitcoin/script.h>
|
|
#include <ccan/structeq/structeq.h>
|
|
#include <closingd/gen_closing_wire.h>
|
|
#include <common/close_tx.h>
|
|
#include <common/crypto_sync.h>
|
|
#include <common/derive_basepoints.h>
|
|
#include <common/htlc.h>
|
|
#include <common/peer_billboard.h>
|
|
#include <common/peer_failed.h>
|
|
#include <common/read_peer_msg.h>
|
|
#include <common/status.h>
|
|
#include <common/subdaemon.h>
|
|
#include <common/type_to_string.h>
|
|
#include <common/utils.h>
|
|
#include <common/version.h>
|
|
#include <common/wire_error.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <wire/peer_wire.h>
|
|
#include <wire/wire_sync.h>
|
|
|
|
/* stdin == requests, 3 == peer, 4 = gossip */
|
|
#define REQ_FD STDIN_FILENO
|
|
#define PEER_FD 3
|
|
#define GOSSIP_FD 4
|
|
|
|
static struct bitcoin_tx *close_tx(const tal_t *ctx,
|
|
struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
u8 *scriptpubkey[NUM_SIDES],
|
|
const struct bitcoin_txid *funding_txid,
|
|
unsigned int funding_txout,
|
|
u64 funding_satoshi,
|
|
const u64 satoshi_out[NUM_SIDES],
|
|
enum side funder,
|
|
uint64_t fee,
|
|
uint64_t dust_limit)
|
|
{
|
|
struct bitcoin_tx *tx;
|
|
|
|
if (satoshi_out[funder] < fee)
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"Funder cannot afford fee %"PRIu64
|
|
" (%"PRIu64" and %"PRIu64")",
|
|
fee, satoshi_out[LOCAL],
|
|
satoshi_out[REMOTE]);
|
|
|
|
status_trace("Making close tx at = %"PRIu64"/%"PRIu64" fee %"PRIu64,
|
|
satoshi_out[LOCAL], satoshi_out[REMOTE], fee);
|
|
|
|
/* FIXME: We need to allow this! */
|
|
tx = create_close_tx(ctx,
|
|
scriptpubkey[LOCAL], scriptpubkey[REMOTE],
|
|
funding_txid,
|
|
funding_txout,
|
|
funding_satoshi,
|
|
satoshi_out[LOCAL] - (funder == LOCAL ? fee : 0),
|
|
satoshi_out[REMOTE] - (funder == REMOTE ? fee : 0),
|
|
dust_limit);
|
|
if (!tx)
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"Both outputs below dust limit:"
|
|
" funding = %"PRIu64
|
|
" fee = %"PRIu64
|
|
" dust_limit = %"PRIu64
|
|
" LOCAL = %"PRIu64
|
|
" REMOTE = %"PRIu64,
|
|
funding_satoshi,
|
|
fee,
|
|
dust_limit,
|
|
satoshi_out[LOCAL],
|
|
satoshi_out[REMOTE]);
|
|
return tx;
|
|
}
|
|
|
|
static void do_reconnect(struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
const u64 next_index[NUM_SIDES],
|
|
u64 revocations_received,
|
|
const u8 *channel_reestablish)
|
|
{
|
|
u8 *msg;
|
|
struct channel_id their_channel_id;
|
|
u64 next_local_commitment_number, next_remote_revocation_number;
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* On reconnection, a node MUST transmit `channel_reestablish` for
|
|
* each channel, and MUST wait for to receive the other node's
|
|
* `channel_reestablish` message before sending any other messages for
|
|
* that channel. The sending node MUST set
|
|
* `next_local_commitment_number` to the commitment number of the next
|
|
* `commitment_signed` it expects to receive, and MUST set
|
|
* `next_remote_revocation_number` to the commitment number of the
|
|
* next `revoke_and_ack` message it expects to receive.
|
|
*/
|
|
msg = towire_channel_reestablish(NULL, channel_id,
|
|
next_index[LOCAL],
|
|
revocations_received);
|
|
if (!sync_crypto_write(cs, PEER_FD, take(msg)))
|
|
peer_failed_connection_lost();
|
|
|
|
/* They might have already send reestablish, which triggered us */
|
|
while (!channel_reestablish) {
|
|
clean_tmpctx();
|
|
|
|
/* Wait for them to say something interesting */
|
|
channel_reestablish
|
|
= read_peer_msg(tmpctx, cs, gossip_index, channel_id,
|
|
sync_crypto_write_arg,
|
|
status_fail_io,
|
|
NULL);
|
|
}
|
|
|
|
if (!fromwire_channel_reestablish(channel_reestablish, &their_channel_id,
|
|
&next_local_commitment_number,
|
|
&next_remote_revocation_number)) {
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"bad reestablish msg: %s %s",
|
|
wire_type_name(fromwire_peektype(channel_reestablish)),
|
|
tal_hex(tmpctx, channel_reestablish));
|
|
}
|
|
status_trace("Got reestablish commit=%"PRIu64" revoke=%"PRIu64,
|
|
next_local_commitment_number,
|
|
next_remote_revocation_number);
|
|
|
|
/* FIXME: Spec says to re-xmit funding_locked here if we haven't
|
|
* done any updates. */
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* On reconnection if the node has sent a previous `closing_signed` it
|
|
* MUST send another `closing_signed`
|
|
*/
|
|
|
|
/* Since we always transmit closing_signed immediately, if
|
|
* we're reconnecting we consider ourselves to have transmitted once,
|
|
* and we'll immediately do the retransmit now anyway. */
|
|
}
|
|
|
|
static void send_offer(struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
const struct pubkey funding_pubkey[NUM_SIDES],
|
|
const u8 *funding_wscript,
|
|
u8 *scriptpubkey[NUM_SIDES],
|
|
const struct bitcoin_txid *funding_txid,
|
|
unsigned int funding_txout,
|
|
u64 funding_satoshi,
|
|
const u64 satoshi_out[NUM_SIDES],
|
|
enum side funder,
|
|
uint64_t our_dust_limit,
|
|
const struct secrets *secrets,
|
|
uint64_t fee_to_offer)
|
|
{
|
|
struct bitcoin_tx *tx;
|
|
secp256k1_ecdsa_signature our_sig;
|
|
u8 *msg;
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* The sender MUST set `signature` to the Bitcoin signature of
|
|
* the close transaction as specified in [BOLT
|
|
* #3](03-transactions.md#closing-transaction).
|
|
*/
|
|
tx = close_tx(tmpctx, cs, gossip_index, channel_id,
|
|
scriptpubkey,
|
|
funding_txid,
|
|
funding_txout,
|
|
funding_satoshi,
|
|
satoshi_out,
|
|
funder, fee_to_offer, our_dust_limit);
|
|
|
|
/* BOLT #3:
|
|
*
|
|
* ## Closing Transaction
|
|
*...
|
|
* Each node offering a signature... MAY also eliminate its
|
|
* own output.
|
|
*/
|
|
/* (We don't do this). */
|
|
sign_tx_input(tx, 0, NULL, funding_wscript,
|
|
&secrets->funding_privkey,
|
|
&funding_pubkey[LOCAL],
|
|
&our_sig);
|
|
|
|
status_trace("sending fee offer %"PRIu64, fee_to_offer);
|
|
|
|
msg = towire_closing_signed(NULL, channel_id, fee_to_offer, &our_sig);
|
|
if (!sync_crypto_write(cs, PEER_FD, take(msg)))
|
|
peer_failed_connection_lost();
|
|
}
|
|
|
|
static void tell_master_their_offer(const secp256k1_ecdsa_signature *their_sig,
|
|
const struct bitcoin_tx *tx)
|
|
{
|
|
u8 *msg = towire_closing_received_signature(NULL, their_sig, tx);
|
|
if (!wire_sync_write(REQ_FD, take(msg)))
|
|
status_failed(STATUS_FAIL_MASTER_IO,
|
|
"Writing received to master: %s",
|
|
strerror(errno));
|
|
|
|
/* Wait for master to ack, to make sure it's in db. */
|
|
msg = wire_sync_read(NULL, REQ_FD);
|
|
if (!fromwire_closing_received_signature_reply(msg))
|
|
master_badmsg(WIRE_CLOSING_RECEIVED_SIGNATURE_REPLY, msg);
|
|
tal_free(msg);
|
|
}
|
|
|
|
/* Returns fee they offered. */
|
|
static uint64_t receive_offer(struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
const struct pubkey funding_pubkey[NUM_SIDES],
|
|
const u8 *funding_wscript,
|
|
u8 *scriptpubkey[NUM_SIDES],
|
|
const struct bitcoin_txid *funding_txid,
|
|
unsigned int funding_txout,
|
|
u64 funding_satoshi,
|
|
const u64 satoshi_out[NUM_SIDES],
|
|
enum side funder,
|
|
uint64_t our_dust_limit,
|
|
u64 min_fee_to_accept)
|
|
{
|
|
u8 *msg;
|
|
struct channel_id their_channel_id;
|
|
u64 received_fee;
|
|
secp256k1_ecdsa_signature their_sig;
|
|
struct bitcoin_tx *tx;
|
|
|
|
/* Wait for them to say something interesting */
|
|
do {
|
|
clean_tmpctx();
|
|
|
|
msg = read_peer_msg(tmpctx, cs, gossip_index, channel_id,
|
|
sync_crypto_write_arg,
|
|
status_fail_io,
|
|
NULL);
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* On reconnection, a node MUST ignore a redundant
|
|
* `funding_locked` if it receives one.
|
|
*/
|
|
/* This should only happen if we've made no commitments, but
|
|
* we don't have to check that: it's their problem. */
|
|
if (msg && fromwire_peektype(msg) == WIRE_FUNDING_LOCKED)
|
|
msg = tal_free(msg);
|
|
/* BOLT #2:
|
|
*
|
|
* ...if the node has sent a previous `shutdown` it MUST
|
|
* retransmit it.
|
|
*/
|
|
else if (msg && fromwire_peektype(msg) == WIRE_SHUTDOWN)
|
|
msg = tal_free(msg);
|
|
} while (!msg);
|
|
|
|
if (!fromwire_closing_signed(msg, &their_channel_id,
|
|
&received_fee, &their_sig))
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"Expected closing_signed: %s",
|
|
tal_hex(tmpctx, msg));
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* The receiver MUST check `signature` is valid for either
|
|
* variant of close transaction specified in [BOLT
|
|
* #3](03-transactions.md#closing-transaction), and MUST fail
|
|
* the connection if it is not.
|
|
*/
|
|
tx = close_tx(tmpctx, cs, gossip_index, channel_id,
|
|
scriptpubkey,
|
|
funding_txid,
|
|
funding_txout,
|
|
funding_satoshi,
|
|
satoshi_out, funder, received_fee, our_dust_limit);
|
|
|
|
if (!check_tx_sig(tx, 0, NULL, funding_wscript,
|
|
&funding_pubkey[REMOTE], &their_sig)) {
|
|
/* Trim it by reducing their output to minimum */
|
|
struct bitcoin_tx *trimmed;
|
|
u64 trimming_satoshi_out[NUM_SIDES];
|
|
|
|
if (funder == REMOTE)
|
|
trimming_satoshi_out[REMOTE] = received_fee;
|
|
else
|
|
trimming_satoshi_out[REMOTE] = 0;
|
|
trimming_satoshi_out[LOCAL] = satoshi_out[LOCAL];
|
|
|
|
/* BOLT #3:
|
|
*
|
|
* Each node offering a signature MUST subtract the fee given
|
|
* by `fee_satoshis` from the output to the funder; it MUST
|
|
* then remove any output below its own `dust_limit_satoshis`,
|
|
* and MAY also eliminate its own output.
|
|
*/
|
|
trimmed = close_tx(tmpctx, cs, gossip_index, channel_id,
|
|
scriptpubkey,
|
|
funding_txid,
|
|
funding_txout,
|
|
funding_satoshi,
|
|
trimming_satoshi_out,
|
|
funder, received_fee, our_dust_limit);
|
|
if (!trimmed
|
|
|| !check_tx_sig(trimmed, 0, NULL, funding_wscript,
|
|
&funding_pubkey[REMOTE], &their_sig)) {
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"Bad closing_signed signature for"
|
|
" %s (and trimmed version %s)",
|
|
type_to_string(tmpctx,
|
|
struct bitcoin_tx,
|
|
tx),
|
|
trimmed ?
|
|
type_to_string(tmpctx,
|
|
struct bitcoin_tx,
|
|
trimmed)
|
|
: "NONE");
|
|
}
|
|
tx = trimmed;
|
|
}
|
|
|
|
status_trace("Received fee offer %"PRIu64, received_fee);
|
|
|
|
/* Master sorts out what is best offer, we just tell it any above min */
|
|
if (received_fee >= min_fee_to_accept) {
|
|
status_trace("...offer is reasonable");
|
|
tell_master_their_offer(&their_sig, tx);
|
|
}
|
|
|
|
return received_fee;
|
|
}
|
|
|
|
struct feerange {
|
|
enum side higher_side;
|
|
u64 min, max;
|
|
|
|
bool allow_mistakes;
|
|
};
|
|
|
|
static void init_feerange(struct feerange *feerange,
|
|
u64 commitment_fee,
|
|
const u64 offer[NUM_SIDES])
|
|
{
|
|
feerange->min = 0;
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* - MUST set `fee_satoshis` less than or equal to the base
|
|
* fee of the final commitment transaction, as calculated
|
|
* in [BOLT #3](03-transactions.md#fee-calculation).
|
|
*/
|
|
feerange->max = commitment_fee;
|
|
feerange->allow_mistakes = false;
|
|
|
|
if (offer[LOCAL] > offer[REMOTE])
|
|
feerange->higher_side = LOCAL;
|
|
else
|
|
feerange->higher_side = REMOTE;
|
|
|
|
status_trace("Feerange init %"PRIu64"-%"PRIu64", %s higher",
|
|
feerange->min, feerange->max,
|
|
feerange->higher_side == LOCAL ? "local" : "remote");
|
|
}
|
|
|
|
static void adjust_feerange(struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
struct feerange *feerange,
|
|
u64 offer, enum side side)
|
|
{
|
|
if (offer < feerange->min || offer > feerange->max) {
|
|
if (!feerange->allow_mistakes || side != REMOTE)
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"%s offer %"PRIu64
|
|
" not between %"PRIu64" and %"PRIu64,
|
|
side == LOCAL ? "local" : "remote",
|
|
offer, feerange->min, feerange->max);
|
|
|
|
status_trace("Allowing deprecated out-of-range fee");
|
|
return;
|
|
}
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* ...otherwise it MUST propose a value strictly between the received
|
|
* `fee_satoshis` and its previously-sent `fee_satoshis`.
|
|
*/
|
|
if (side == feerange->higher_side)
|
|
feerange->max = offer - 1;
|
|
else
|
|
feerange->min = offer + 1;
|
|
|
|
status_trace("Feerange %s update %"PRIu64": now %"PRIu64"-%"PRIu64,
|
|
side == LOCAL ? "local" : "remote",
|
|
offer, feerange->min, feerange->max);
|
|
}
|
|
|
|
/* Figure out what we should offer now. */
|
|
static u64 adjust_offer(struct crypto_state *cs,
|
|
u64 gossip_index,
|
|
const struct channel_id *channel_id,
|
|
const struct feerange *feerange,
|
|
u64 remote_offer,
|
|
u64 min_fee_to_accept)
|
|
{
|
|
/* Within 1 satoshi? Agree. */
|
|
if (feerange->min + 1 >= feerange->max)
|
|
return remote_offer;
|
|
|
|
/* Max is below our minimum acceptable? */
|
|
if (feerange->max < min_fee_to_accept)
|
|
peer_failed(cs, gossip_index, channel_id,
|
|
"Feerange %"PRIu64"-%"PRIu64
|
|
" below minimum acceptable %"PRIu64,
|
|
feerange->min, feerange->max,
|
|
min_fee_to_accept);
|
|
|
|
/* Bisect between our minimum and max. */
|
|
if (feerange->min > min_fee_to_accept)
|
|
min_fee_to_accept = feerange->min;
|
|
|
|
return (feerange->max + min_fee_to_accept)/2;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct crypto_state cs;
|
|
const tal_t *ctx = tal(NULL, char);
|
|
u8 *msg;
|
|
struct privkey seed;
|
|
struct pubkey funding_pubkey[NUM_SIDES];
|
|
struct bitcoin_txid funding_txid;
|
|
u16 funding_txout;
|
|
u64 funding_satoshi, satoshi_out[NUM_SIDES];
|
|
u64 our_dust_limit;
|
|
u64 min_fee_to_accept, commitment_fee, offer[NUM_SIDES];
|
|
struct feerange feerange;
|
|
enum side funder;
|
|
u8 *scriptpubkey[NUM_SIDES], *funding_wscript;
|
|
struct channel_id channel_id;
|
|
struct secrets secrets;
|
|
bool reconnected;
|
|
u64 next_index[NUM_SIDES], revocations_received;
|
|
u64 gossip_index;
|
|
enum side whose_turn;
|
|
bool deprecated_api;
|
|
u8 *channel_reestablish;
|
|
|
|
subdaemon_setup(argc, argv);
|
|
|
|
status_setup_sync(REQ_FD);
|
|
|
|
msg = wire_sync_read(tmpctx, REQ_FD);
|
|
if (!fromwire_closing_init(ctx, msg,
|
|
&cs, &gossip_index, &seed,
|
|
&funding_txid, &funding_txout,
|
|
&funding_satoshi,
|
|
&funding_pubkey[REMOTE],
|
|
&funder,
|
|
&satoshi_out[LOCAL],
|
|
&satoshi_out[REMOTE],
|
|
&our_dust_limit,
|
|
&min_fee_to_accept, &commitment_fee,
|
|
&offer[LOCAL],
|
|
&scriptpubkey[LOCAL],
|
|
&scriptpubkey[REMOTE],
|
|
&reconnected,
|
|
&next_index[LOCAL],
|
|
&next_index[REMOTE],
|
|
&revocations_received,
|
|
&deprecated_api,
|
|
&channel_reestablish))
|
|
master_badmsg(WIRE_CLOSING_INIT, msg);
|
|
|
|
status_trace("satoshi_out = %"PRIu64"/%"PRIu64,
|
|
satoshi_out[LOCAL], satoshi_out[REMOTE]);
|
|
status_trace("dustlimit = %"PRIu64, our_dust_limit);
|
|
status_trace("fee = %"PRIu64, offer[LOCAL]);
|
|
derive_channel_id(&channel_id, &funding_txid, funding_txout);
|
|
derive_basepoints(&seed, &funding_pubkey[LOCAL], NULL,
|
|
&secrets, NULL);
|
|
|
|
funding_wscript = bitcoin_redeem_2of2(ctx,
|
|
&funding_pubkey[LOCAL],
|
|
&funding_pubkey[REMOTE]);
|
|
|
|
if (reconnected)
|
|
do_reconnect(&cs, gossip_index, &channel_id,
|
|
next_index, revocations_received,
|
|
channel_reestablish);
|
|
|
|
peer_billboard(true, "Negotiating closing fee between %"PRIu64
|
|
" and %"PRIu64" satoshi (ideal %"PRIu64")",
|
|
min_fee_to_accept, commitment_fee, offer[LOCAL]);
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* The funding node:
|
|
* - after `shutdown` has been received, AND no HTLCs remain in either
|
|
* commitment transaction:
|
|
* - SHOULD send a `closing_signed` message.
|
|
*/
|
|
whose_turn = funder;
|
|
for (size_t i = 0; i < 2; i++, whose_turn = !whose_turn) {
|
|
if (whose_turn == LOCAL) {
|
|
send_offer(&cs, gossip_index,
|
|
&channel_id, funding_pubkey,
|
|
funding_wscript,
|
|
scriptpubkey, &funding_txid, funding_txout,
|
|
funding_satoshi, satoshi_out, funder,
|
|
our_dust_limit, &secrets, offer[LOCAL]);
|
|
} else {
|
|
if (i == 0)
|
|
peer_billboard(false, "Waiting for their initial"
|
|
" closing fee offer");
|
|
else
|
|
peer_billboard(false, "Waiting for their initial"
|
|
" closing fee offer:"
|
|
" ours was %"PRIu64" satoshi",
|
|
offer[LOCAL]);
|
|
offer[REMOTE]
|
|
= receive_offer(&cs, gossip_index,
|
|
&channel_id, funding_pubkey,
|
|
funding_wscript,
|
|
scriptpubkey, &funding_txid,
|
|
funding_txout, funding_satoshi,
|
|
satoshi_out, funder,
|
|
our_dust_limit,
|
|
min_fee_to_accept);
|
|
}
|
|
}
|
|
|
|
/* Now we have first two points, we can init fee range. */
|
|
init_feerange(&feerange, commitment_fee, offer);
|
|
|
|
/* Apply (and check) funder offer now. */
|
|
adjust_feerange(&cs, gossip_index, &channel_id,
|
|
&feerange, offer[funder], funder);
|
|
|
|
/* Older spec clients would make offers independently, so allow */
|
|
feerange.allow_mistakes = deprecated_api;
|
|
|
|
/* Now any extra rounds required. */
|
|
while (offer[LOCAL] != offer[REMOTE]) {
|
|
/* Still don't agree: adjust feerange based on previous offer */
|
|
adjust_feerange(&cs, gossip_index, &channel_id,
|
|
&feerange,
|
|
offer[!whose_turn], !whose_turn);
|
|
|
|
if (whose_turn == LOCAL) {
|
|
offer[LOCAL] = adjust_offer(&cs, gossip_index,
|
|
&channel_id,
|
|
&feerange, offer[REMOTE],
|
|
min_fee_to_accept);
|
|
send_offer(&cs, gossip_index, &channel_id,
|
|
funding_pubkey,
|
|
funding_wscript,
|
|
scriptpubkey, &funding_txid, funding_txout,
|
|
funding_satoshi, satoshi_out, funder,
|
|
our_dust_limit, &secrets, offer[LOCAL]);
|
|
} else {
|
|
peer_billboard(false, "Waiting for another"
|
|
" closing fee offer:"
|
|
" ours was %"PRIu64" satoshi,"
|
|
" theirs was %"PRIu64" satoshi,",
|
|
offer[LOCAL], offer[REMOTE]);
|
|
offer[REMOTE]
|
|
= receive_offer(&cs, gossip_index, &channel_id,
|
|
funding_pubkey,
|
|
funding_wscript,
|
|
scriptpubkey, &funding_txid,
|
|
funding_txout, funding_satoshi,
|
|
satoshi_out, funder,
|
|
our_dust_limit,
|
|
min_fee_to_accept);
|
|
}
|
|
|
|
whose_turn = !whose_turn;
|
|
}
|
|
|
|
peer_billboard(true, "We agreed on a closing fee of %"PRIu64" satoshi",
|
|
offer[LOCAL]);
|
|
|
|
/* We're done! */
|
|
wire_sync_write(REQ_FD,
|
|
take(towire_closing_complete(NULL, gossip_index)));
|
|
tal_free(ctx);
|
|
daemon_shutdown();
|
|
|
|
return 0;
|
|
}
|