/* FIXME: We don't relay from gossipd at all here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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) { 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(); /* Wait for them to say something interesting */ while ((msg = read_peer_msg(tmpctx, cs, gossip_index, channel_id, sync_crypto_write_arg, status_fail_io, NULL)) == NULL) clean_tmpctx(); if (!fromwire_channel_reestablish(msg, &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(msg)), tal_hex(tmpctx, msg)); } 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; 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; 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)) 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); 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); /* Now apply the one constraint from above (other is inside loop). */ adjust_feerange(&cs, gossip_index, &channel_id, &feerange, offer[!whose_turn], !whose_turn); /* Now any extra rounds required. */ while (offer[LOCAL] != offer[REMOTE]) { /* If they differ, adjust feerate. */ adjust_feerange(&cs, gossip_index, &channel_id, &feerange, offer[whose_turn], whose_turn); /* Now its the other side's turn. */ 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); } } 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); tal_free(tmpctx); return 0; }