From aeb8c8830b886c6c7b0062c72d8c1400f9870de9 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:04:17 -0500 Subject: [PATCH 001/131] amount: helper method for adding sats to an msat amount see title. --- common/amount.c | 12 ++++++++++++ common/amount.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/common/amount.c b/common/amount.c index 71eee872c66e..e2a6e1299b08 100644 --- a/common/amount.c +++ b/common/amount.c @@ -283,6 +283,18 @@ WARN_UNUSED_RESULT bool amount_sat_sub_msat(struct amount_msat *val, return amount_msat_sub(val, msata, b); } +WARN_UNUSED_RESULT bool amount_msat_add_sat(struct amount_msat *val, + struct amount_msat a, + struct amount_sat b) +{ + struct amount_msat msatb; + + if (!amount_sat_to_msat(&msatb, b)) + return false; + + return amount_msat_add(val, a, msatb); +} + bool amount_sat_eq(struct amount_sat a, struct amount_sat b) { return a.satoshis == b.satoshis; diff --git a/common/amount.h b/common/amount.h index c401d272e8b7..f5d9ef7f123a 100644 --- a/common/amount.h +++ b/common/amount.h @@ -70,6 +70,9 @@ WARN_UNUSED_RESULT bool amount_sat_sub(struct amount_sat *val, WARN_UNUSED_RESULT bool amount_msat_sub_sat(struct amount_msat *val, struct amount_msat a, struct amount_sat b); +WARN_UNUSED_RESULT bool amount_msat_add_sat(struct amount_msat *val, + struct amount_msat a, + struct amount_sat b); WARN_UNUSED_RESULT bool amount_sat_sub_msat(struct amount_msat *val, struct amount_sat a, struct amount_msat b); From 009b1e7ef70dff62582c688894f144260897d58b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 9 Sep 2019 11:11:24 -0500 Subject: [PATCH 002/131] df: rename 'funder' to 'opener' Previously we've used the term 'funder' to refer to the peer paying the fees for a transaction; v2 of openchannel will make this no longer true. Instead we rename this to 'opener', or the peer sending the 'open_channel' message, since this will be universally true in a dual-funding world. --- channeld/channel_wire.csv | 2 +- channeld/channeld.c | 26 +++++++-------- channeld/commit_tx.c | 4 +-- channeld/commit_tx.h | 4 +-- channeld/full_channel.c | 56 ++++++++++++++++---------------- channeld/full_channel.h | 12 +++---- channeld/test/run-commit_tx.c | 4 +-- channeld/test/run-full_channel.c | 2 +- closingd/closingd.c | 34 +++++++++---------- common/initial_channel.c | 16 ++++----- common/initial_channel.h | 6 ++-- common/initial_commit_tx.c | 18 +++++----- lightningd/channel.c | 6 ++-- lightningd/channel.h | 4 +-- lightningd/channel_control.c | 8 ++--- lightningd/closing_control.c | 4 +-- lightningd/onchain_control.c | 2 +- lightningd/opening_control.c | 2 +- lightningd/peer_control.c | 18 +++++----- lightningd/peer_htlcs.c | 12 +++---- onchaind/onchain_wire.csv | 2 +- onchaind/onchaind.c | 10 +++--- openingd/openingd.c | 36 ++++++++++---------- wallet/test/run-wallet.c | 6 ++-- wallet/wallet.c | 2 +- 25 files changed, 148 insertions(+), 148 deletions(-) diff --git a/channeld/channel_wire.csv b/channeld/channel_wire.csv index 3f36ac80e5d0..cf87f8a1aa26 100644 --- a/channeld/channel_wire.csv +++ b/channeld/channel_wire.csv @@ -24,7 +24,7 @@ msgdata,channel_init,remote_fundingkey,pubkey, msgdata,channel_init,remote_basepoints,basepoints, msgdata,channel_init,remote_per_commit,pubkey, msgdata,channel_init,old_remote_per_commit,pubkey, -msgdata,channel_init,funder,enum side, +msgdata,channel_init,opener,enum side, msgdata,channel_init,fee_base,u32, msgdata,channel_init,fee_proportional,u32, msgdata,channel_init,local_msatoshi,amount_msat, diff --git a/channeld/channeld.c b/channeld/channeld.c index 24b037fd5be7..ce1aacbfcca8 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -669,10 +669,10 @@ static void handle_peer_feechange(struct peer *peer, const u8 *msg) * - if the sender is not responsible for paying the Bitcoin fee: * - MUST fail the channel. */ - if (peer->channel->funder != REMOTE) + if (peer->channel->opener != REMOTE) peer_failed(peer->pps, &peer->channel_id, - "update_fee from non-funder?"); + "update_fee from non-opener?"); status_debug("update_fee %u, range %u-%u", feerate, peer->feerate_min, peer->feerate_max); @@ -975,7 +975,7 @@ static void send_commit(struct peer *peer) } /* If we wanted to update fees, do it now. */ - if (peer->channel->funder == LOCAL) { + if (peer->channel->opener == LOCAL) { u32 feerate, max = approx_max_feerate(peer->channel); feerate = peer->desired_feerate; @@ -1240,11 +1240,11 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) } /* We were supposed to check this was affordable as we go. */ - if (peer->channel->funder == REMOTE) { + if (peer->channel->opener == REMOTE) { status_debug("Feerates are %u/%u", channel_feerate(peer->channel, LOCAL), channel_feerate(peer->channel, REMOTE)); - assert(can_funder_afford_feerate(peer->channel, + assert(can_opener_afford_feerate(peer->channel, channel_feerate(peer->channel, LOCAL))); } @@ -1432,7 +1432,7 @@ static void handle_peer_revoke_and_ack(struct peer *peer, const u8 *msg) peer->old_remote_per_commit = peer->remote_per_commit; peer->remote_per_commit = next_per_commit; status_debug("revoke_and_ack %s: remote_per_commit = %s, old_remote_per_commit = %s", - side_to_str(peer->channel->funder), + side_to_str(peer->channel->opener), type_to_string(tmpctx, struct pubkey, &peer->remote_per_commit), type_to_string(tmpctx, struct pubkey, @@ -2107,7 +2107,7 @@ static void resend_commitment(struct peer *peer, const struct changed_htlc *last } /* Make sure they have the correct fee. */ - if (peer->channel->funder == LOCAL) { + if (peer->channel->opener == LOCAL) { msg = towire_update_fee(NULL, &peer->channel_id, channel_feerate(peer->channel, REMOTE)); sync_crypto_write(peer->pps, take(msg)); @@ -2812,7 +2812,7 @@ static void handle_feerates(struct peer *peer, const u8 *inmsg) * sufficient (by a significant margin) for timely processing of the * commitment transaction. */ - if (peer->channel->funder == LOCAL) { + if (peer->channel->opener == LOCAL) { peer->desired_feerate = feerate; /* Don't do this for the first feerate, wait until something else * happens. LND seems to get upset in some cases otherwise: @@ -3067,7 +3067,7 @@ static void init_channel(struct peer *peer) struct pubkey funding_pubkey[NUM_SIDES]; struct channel_config conf[NUM_SIDES]; struct bitcoin_txid funding_txid; - enum side funder; + enum side opener; struct existing_htlc **htlcs; bool reconnected; u8 *funding_signed; @@ -3102,7 +3102,7 @@ static void init_channel(struct peer *peer) &points[REMOTE], &peer->remote_per_commit, &peer->old_remote_per_commit, - &funder, + &opener, &peer->fee_base, &peer->fee_per_satoshi, &local_msat, @@ -3148,7 +3148,7 @@ static void init_channel(struct peer *peer) " next_idx_remote = %"PRIu64 " revocations_received = %"PRIu64 " feerates %s range %u-%u", - side_to_str(funder), + side_to_str(opener), type_to_string(tmpctx, struct pubkey, &peer->remote_per_commit), type_to_string(tmpctx, struct pubkey, @@ -3197,7 +3197,7 @@ static void init_channel(struct peer *peer) &funding_pubkey[LOCAL], &funding_pubkey[REMOTE], option_static_remotekey, - funder); + opener); if (!channel_force_htlcs(peer->channel, cast_const2(const struct existing_htlc **, htlcs))) @@ -3211,7 +3211,7 @@ static void init_channel(struct peer *peer) &peer->node_ids[REMOTE]); /* Default desired feerate is the feerate we set for them last. */ - if (peer->channel->funder == LOCAL) + if (peer->channel->opener == LOCAL) peer->desired_feerate = channel_feerate(peer->channel, REMOTE); /* from now we need keep watch over WIRE_CHANNEL_FUNDING_DEPTH */ diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 44be92c563fc..bd75f411dccc 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -85,7 +85,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, struct amount_sat funding, - enum side funder, + enum side opener, u16 to_self_delay, const struct keyset *keyset, u32 feerate_per_kw, @@ -131,7 +131,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * 3. Subtract this base fee from the funder (either `to_local` or * `to_remote`), with a floor of 0 (see [Fee Payment](#fee-payment)). */ - try_subtract_fee(funder, side, base_fee, &self_pay, &other_pay); + try_subtract_fee(opener, side, base_fee, &self_pay, &other_pay); #ifdef PRINT_ACTUAL_FEE { diff --git a/channeld/commit_tx.h b/channeld/commit_tx.h index 6b01208c554d..56fc6c765fe4 100644 --- a/channeld/commit_tx.h +++ b/channeld/commit_tx.h @@ -28,7 +28,7 @@ size_t commit_tx_num_untrimmed(const struct htlc **htlcs, * commit_tx: create (unsigned) commitment tx to spend the funding tx output * @ctx: context to allocate transaction and @htlc_map from. * @funding_txid, @funding_out, @funding: funding outpoint. - * @funder: is the LOCAL or REMOTE paying the fee? + * @opener: is the LOCAL or REMOTE paying the fee? * @keyset: keys derived for this commit tx. * @feerate_per_kw: feerate to use * @dust_limit: dust limit below which to trim outputs. @@ -47,7 +47,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, struct amount_sat funding, - enum side funder, + enum side opener, u16 to_self_delay, const struct keyset *keyset, u32 feerate_per_kw, diff --git a/channeld/full_channel.c b/channeld/full_channel.c index fe8cf2b2f655..ecb1180ea17a 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -101,7 +101,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, - enum side funder) + enum side opener) { struct channel *channel = new_initial_channel(ctx, funding_txid, @@ -116,7 +116,7 @@ struct channel *new_full_channel(const tal_t *ctx, local_funding_pubkey, remote_funding_pubkey, option_static_remotekey, - funder); + opener); if (channel) { channel->htlcs = tal(channel, struct htlc_map); @@ -295,7 +295,7 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx, txs = tal_arr(ctx, struct bitcoin_tx *, 1); txs[0] = commit_tx( ctx, &channel->funding_txid, channel->funding_txout, - channel->funding, channel->funder, + channel->funding, channel->opener, channel->config[!side].to_self_delay, &keyset, channel_feerate(channel, side), channel->config[side].dust_limit, channel->view[side].owed[side], @@ -418,7 +418,7 @@ static bool local_funder_has_fee_headroom(const struct channel *channel, size_t untrimmed; struct amount_sat fee; - assert(channel->funder == LOCAL); + assert(channel->opener == LOCAL); /* How many untrimmed at current feerate? Increasing feerate can * only *reduce* this number, so use current feerate here! */ @@ -540,7 +540,7 @@ static enum channel_add_err add_htlc(struct channel *channel, */ /* Also we should not add more htlc's than sender or recipient * configured. This mitigates attacks in which a peer can force the - * funder of the channel to pay unnecessary onchain fees during a fee + * opener of the channel to pay unnecessary onchain fees during a fee * spike with large commitment transactions. */ min_concurrent_htlcs = channel->config[recipient].max_accepted_htlcs; @@ -614,7 +614,7 @@ static enum channel_add_err add_htlc(struct channel *channel, &remainder)) return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED; - if (channel->funder == sender) { + if (channel->opener== sender) { if (amount_msat_less_sat(remainder, fee)) { status_debug("Cannot afford fee %s with %s above reserve", type_to_string(tmpctx, struct amount_sat, @@ -634,12 +634,12 @@ static enum channel_add_err add_htlc(struct channel *channel, } } - /* Try not to add a payment which will take funder into fees + /* Try not to add a payment which will take opener into fees * on either our side or theirs. */ if (sender == LOCAL) { if (!get_room_above_reserve(channel, view, adding, removing, - channel->funder, + channel->opener, &remainder)) return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED; /* Should be able to afford both their own commit tx @@ -649,7 +649,7 @@ static enum channel_add_err add_htlc(struct channel *channel, committed, adding, removing, - channel->funder); + channel->opener); /* set fee output pointer if given */ if (htlc_fee && amount_sat_greater(fee, *htlc_fee)) *htlc_fee = fee; @@ -667,7 +667,7 @@ static enum channel_add_err add_htlc(struct channel *channel, committed, adding, removing, - !channel->funder); + !channel->opener); /* set fee output pointer if given */ if (htlc_fee && amount_sat_greater(fee, *htlc_fee)) *htlc_fee = fee; @@ -970,7 +970,7 @@ u32 approx_max_feerate(const struct channel *channel) struct amount_sat avail; const struct htlc **committed, **adding, **removing; - gather_htlcs(tmpctx, channel, !channel->funder, + gather_htlcs(tmpctx, channel, !channel->opener, &committed, &removing, &adding); /* Assume none are trimmed; this gives lower bound on feerate. */ @@ -1001,28 +1001,28 @@ u32 approx_max_feerate(const struct channel *channel) /* We should never go below reserve. */ if (!amount_sat_sub(&avail, - amount_msat_to_sat_round_down(channel->view[!channel->funder].owed[channel->funder]), - channel->config[!channel->funder].channel_reserve)) + amount_msat_to_sat_round_down(channel->view[!channel->opener].owed[channel->opener]), + channel->config[!channel->opener].channel_reserve)) avail = AMOUNT_SAT(0); return avail.satoshis / weight * 1000; /* Raw: once-off reverse feerate*/ } -bool can_funder_afford_feerate(const struct channel *channel, u32 feerate_per_kw) +bool can_opener_afford_feerate(const struct channel *channel, u32 feerate_per_kw) { struct amount_sat needed, fee; - struct amount_sat dust_limit = channel->config[!channel->funder].dust_limit; + struct amount_sat dust_limit = channel->config[!channel->opener].dust_limit; size_t untrimmed; const struct htlc **committed, **adding, **removing; - gather_htlcs(tmpctx, channel, !channel->funder, + gather_htlcs(tmpctx, channel, !channel->opener, &committed, &removing, &adding); untrimmed = commit_tx_num_untrimmed(committed, feerate_per_kw, dust_limit, - !channel->funder) + !channel->opener) + commit_tx_num_untrimmed(adding, feerate_per_kw, dust_limit, - !channel->funder) + !channel->opener) - commit_tx_num_untrimmed(removing, feerate_per_kw, dust_limit, - !channel->funder); + !channel->opener); fee = commit_tx_base_fee(feerate_per_kw, untrimmed); @@ -1032,38 +1032,38 @@ bool can_funder_afford_feerate(const struct channel *channel, u32 feerate_per_kw * node's current commitment transaction: * - SHOULD fail the channel */ - /* Note: sender == funder */ + /* Note: sender == opener */ /* How much does it think it has? Must be >= reserve + fee */ if (!amount_sat_add(&needed, fee, - channel->config[!channel->funder].channel_reserve)) + channel->config[!channel->opener].channel_reserve)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Cannot add fee %s and reserve %s", type_to_string(tmpctx, struct amount_sat, &fee), type_to_string(tmpctx, struct amount_sat, - &channel->config[!channel->funder].channel_reserve)); + &channel->config[!channel->opener].channel_reserve)); status_debug("We need %s at feerate %u for %zu untrimmed htlcs: we have %s/%s", type_to_string(tmpctx, struct amount_sat, &needed), feerate_per_kw, untrimmed, type_to_string(tmpctx, struct amount_msat, - &channel->view[LOCAL].owed[channel->funder]), + &channel->view[LOCAL].owed[channel->opener]), type_to_string(tmpctx, struct amount_msat, - &channel->view[REMOTE].owed[channel->funder])); - return amount_msat_greater_eq_sat(channel->view[!channel->funder].owed[channel->funder], + &channel->view[REMOTE].owed[channel->opener])); + return amount_msat_greater_eq_sat(channel->view[!channel->opener].owed[channel->opener], needed); } bool channel_update_feerate(struct channel *channel, u32 feerate_per_kw) { - if (!can_funder_afford_feerate(channel, feerate_per_kw)) + if (!can_opener_afford_feerate(channel, feerate_per_kw)) return false; status_debug("Setting %s feerate to %u", - side_to_str(!channel->funder), feerate_per_kw); + side_to_str(!channel->opener), feerate_per_kw); - start_fee_update(channel->fee_states, channel->funder, feerate_per_kw); + start_fee_update(channel->fee_states, channel->opener, feerate_per_kw); return true; } diff --git a/channeld/full_channel.h b/channeld/full_channel.h index e7fa565c7e8e..7d618ec9ca23 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -25,7 +25,7 @@ struct existing_htlc; * @local_fundingkey: local funding key * @remote_fundingkey: remote funding key * @option_static_remotekey: use `option_static_remotekey`. - * @funder: which side initiated it. + * @opener: which side initiated it. * * Returns state, or NULL if malformed. */ @@ -43,7 +43,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, - enum side funder); + enum side opener); /** * channel_txs: Get the current commitment and htlc txs for the channel. @@ -151,7 +151,7 @@ enum channel_remove_err channel_fulfill_htlc(struct channel *channel, struct htlc **htlcp); /** - * approx_max_feerate: what's the max funder could raise fee rate to? + * approx_max_feerate: what's the max opener could raise fee rate to? * @channel: The channel state * * This is not exact! To check if their offer is valid, try @@ -160,14 +160,14 @@ enum channel_remove_err channel_fulfill_htlc(struct channel *channel, u32 approx_max_feerate(const struct channel *channel); /** - * can_funder_afford_feerate: could the funder pay the fee? + * can_opener_afford_feerate: could the opener pay the fee? * @channel: The channel state * @feerate: The feerate in satoshi per 1000 bytes. */ -bool can_funder_afford_feerate(const struct channel *channel, u32 feerate); +bool can_opener_afford_feerate(const struct channel *channel, u32 feerate); /** - * channel_update_feerate: Change fee rate on non-funder side. + * channel_update_feerate: Change fee rate on non-opener side. * @channel: The channel * @feerate_per_kw: fee in satoshi per 1000 bytes. * diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index df054f090b6c..48c3945b015b 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -938,7 +938,7 @@ int main(void) tx = newtx; } while (tx->wtx->num_outputs > 1); - /* Now make sure we cover case where funder can't afford the fee; + /* Now make sure we cover case where opener can't afford the fee; * its output cannot go negative! */ for (;;) { struct amount_sat base_fee @@ -959,7 +959,7 @@ int main(void) assert(feerate_per_kw == 9651936); printf("\n" - "name: commitment tx with fee greater than funder amount\n" + "name: commitment tx with fee greater than opener amount\n" "to_local_msat: %"PRIu64"\n" "to_remote_msat: %"PRIu64"\n" "local_feerate_per_kw: %u\n", diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 4a4c2f8b28a5..2fac4d079711 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -314,7 +314,7 @@ static void update_feerate(struct channel *channel, u32 feerate) ret = channel_update_feerate(channel, feerate); assert(ret); - if (channel->funder == LOCAL) { + if (channel->opener == LOCAL) { ret = channel_sending_commit(channel, NULL); assert(ret); ret = channel_rcvd_revoke_and_ack(channel, NULL); diff --git a/closingd/closingd.c b/closingd/closingd.c index 578a3755a64b..505d968d35c0 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -40,7 +40,7 @@ static struct bitcoin_tx *close_tx(const tal_t *ctx, unsigned int funding_txout, struct amount_sat funding, const struct amount_sat out[NUM_SIDES], - enum side funder, + enum side opener, struct amount_sat fee, struct amount_sat dust_limit) { @@ -49,7 +49,7 @@ static struct bitcoin_tx *close_tx(const tal_t *ctx, out_minus_fee[LOCAL] = out[LOCAL]; out_minus_fee[REMOTE] = out[REMOTE]; - if (!amount_sat_sub(&out_minus_fee[funder], out[funder], fee)) + if (!amount_sat_sub(&out_minus_fee[opener], out[opener], fee)) peer_failed(pps, channel_id, "Funder cannot afford fee %s (%s and %s)", type_to_string(tmpctx, struct amount_sat, &fee), @@ -243,7 +243,7 @@ static void send_offer(struct per_peer_state *pps, unsigned int funding_txout, struct amount_sat funding, const struct amount_sat out[NUM_SIDES], - enum side funder, + enum side opener, struct amount_sat our_dust_limit, struct amount_sat fee_to_offer) { @@ -263,7 +263,7 @@ static void send_offer(struct per_peer_state *pps, funding_txout, funding, out, - funder, fee_to_offer, our_dust_limit); + opener, fee_to_offer, our_dust_limit); /* BOLT #3: * @@ -321,7 +321,7 @@ receive_offer(struct per_peer_state *pps, unsigned int funding_txout, struct amount_sat funding, const struct amount_sat out[NUM_SIDES], - enum side funder, + enum side opener, struct amount_sat our_dust_limit, struct amount_sat min_fee_to_accept, struct bitcoin_txid *closing_txid) @@ -372,7 +372,7 @@ receive_offer(struct per_peer_state *pps, funding_txid, funding_txout, funding, - out, funder, received_fee, our_dust_limit); + out, opener, received_fee, our_dust_limit); if (!check_tx_sig(tx, 0, NULL, funding_wscript, &funding_pubkey[REMOTE], &their_sig)) { @@ -380,7 +380,7 @@ receive_offer(struct per_peer_state *pps, struct bitcoin_tx *trimmed; struct amount_sat trimming_out[NUM_SIDES]; - if (funder == REMOTE) + if (opener == REMOTE) trimming_out[REMOTE] = received_fee; else trimming_out[REMOTE] = AMOUNT_SAT(0); @@ -402,7 +402,7 @@ receive_offer(struct per_peer_state *pps, funding_txout, funding, trimming_out, - funder, received_fee, our_dust_limit); + opener, received_fee, our_dust_limit); if (!trimmed || !check_tx_sig(trimmed, 0, NULL, funding_wscript, &funding_pubkey[REMOTE], &their_sig)) { @@ -603,7 +603,7 @@ int main(int argc, char *argv[]) struct amount_sat our_dust_limit; struct amount_sat min_fee_to_accept, commitment_fee, offer[NUM_SIDES]; struct feerange feerange; - enum side funder; + enum side opener; u8 *scriptpubkey[NUM_SIDES], *funding_wscript; u64 fee_negotiation_step; u8 fee_negotiation_step_unit; @@ -627,7 +627,7 @@ int main(int argc, char *argv[]) &funding, &funding_pubkey[LOCAL], &funding_pubkey[REMOTE], - &funder, + &opener, &out[LOCAL], &out[REMOTE], &our_dust_limit, @@ -692,13 +692,13 @@ int main(int argc, char *argv[]) * commitment transaction: * - SHOULD send a `closing_signed` message. */ - whose_turn = funder; + whose_turn = opener; for (size_t i = 0; i < 2; i++, whose_turn = !whose_turn) { if (whose_turn == LOCAL) { send_offer(pps, chainparams, &channel_id, funding_pubkey, scriptpubkey, &funding_txid, funding_txout, - funding, out, funder, + funding, out, opener, our_dust_limit, offer[LOCAL]); } else { @@ -718,7 +718,7 @@ int main(int argc, char *argv[]) funding_wscript, scriptpubkey, &funding_txid, funding_txout, funding, - out, funder, + out, opener, our_dust_limit, min_fee_to_accept, &closing_txid); @@ -728,8 +728,8 @@ int main(int argc, char *argv[]) /* 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(&feerange, offer[funder], funder); + /* Apply (and check) opener offer now. */ + adjust_feerange(&feerange, offer[opener], opener); /* Now any extra rounds required. */ while (!amount_sat_eq(offer[LOCAL], offer[REMOTE])) { @@ -747,7 +747,7 @@ int main(int argc, char *argv[]) send_offer(pps, chainparams, &channel_id, funding_pubkey, scriptpubkey, &funding_txid, funding_txout, - funding, out, funder, + funding, out, opener, our_dust_limit, offer[LOCAL]); } else { @@ -762,7 +762,7 @@ int main(int argc, char *argv[]) funding_wscript, scriptpubkey, &funding_txid, funding_txout, funding, - out, funder, + out, opener, our_dust_limit, min_fee_to_accept, &closing_txid); diff --git a/common/initial_channel.c b/common/initial_channel.c index 6074ee585f81..718b9a9cf511 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -24,7 +24,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, - enum side funder) + enum side opener) { struct channel *channel = tal(ctx, struct channel); struct amount_msat remote_msatoshi; @@ -37,7 +37,7 @@ struct channel *new_initial_channel(const tal_t *ctx, channel->funding, local_msatoshi)) return tal_free(channel); - channel->funder = funder; + channel->opener = opener; channel->config[LOCAL] = *local; channel->config[REMOTE] = *remote; channel->funding_pubkey[LOCAL] = *local_funding_pubkey; @@ -58,8 +58,8 @@ struct channel *new_initial_channel(const tal_t *ctx, channel->basepoints[REMOTE] = *remote_basepoints; channel->commitment_number_obscurer - = commit_number_obscurer(&channel->basepoints[funder].payment, - &channel->basepoints[!funder].payment); + = commit_number_obscurer(&channel->basepoints[opener].payment, + &channel->basepoints[!opener].payment); channel->option_static_remotekey = option_static_remotekey; return channel; @@ -95,7 +95,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, &channel->funding_txid, channel->funding_txout, channel->funding, - channel->funder, + channel->opener, /* They specify our to_self_delay and v.v. */ channel->config[!side].to_self_delay, &keyset, @@ -111,7 +111,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, u32 channel_feerate(const struct channel *channel, enum side side) { - return get_feerate(channel->fee_states, channel->funder, side); + return get_feerate(channel->fee_states, channel->opener, side); } static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) @@ -128,12 +128,12 @@ static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) static char *fmt_channel(const tal_t *ctx, const struct channel *channel) { return tal_fmt(ctx, "{ funding=%s," - " funder=%s," + " opener=%s," " local=%s," " remote=%s }", type_to_string(tmpctx, struct amount_sat, &channel->funding), - side_to_str(channel->funder), + side_to_str(channel->opener), fmt_channel_view(ctx, &channel->view[LOCAL]), fmt_channel_view(ctx, &channel->view[REMOTE])); } diff --git a/common/initial_channel.h b/common/initial_channel.h index cf202127ef82..b68f7fe58575 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -39,7 +39,7 @@ struct channel { u32 minimum_depth; /* Who is paying fees. */ - enum side funder; + enum side opener; /* Limits and settings on this channel. */ struct channel_config config[NUM_SIDES]; @@ -78,7 +78,7 @@ struct channel { * @remote_basepoints: remote basepoints. * @local_fundingkey: local funding key * @remote_fundingkey: remote funding key - * @funder: which side initiated it. + * @opener: which side initiated it. * * Returns channel, or NULL if malformed. */ @@ -96,7 +96,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, - enum side funder); + enum side opener); /** diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index f1a451cca062..3c68ec6b0a27 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -30,22 +30,22 @@ u64 commit_number_obscurer(const struct pubkey *opener_payment_basepoint, return be64_to_cpu(obscurer); } -bool try_subtract_fee(enum side funder, enum side side, +bool try_subtract_fee(enum side opener, enum side side, struct amount_sat base_fee, struct amount_msat *self, struct amount_msat *other) { - struct amount_msat *funder_amount; + struct amount_msat *opener_amount; - if (funder == side) - funder_amount = self; + if (opener == side) + opener_amount = self; else - funder_amount = other; + opener_amount = other; - if (amount_msat_sub_sat(funder_amount, *funder_amount, base_fee)) + if (amount_msat_sub_sat(opener_amount, *opener_amount, base_fee)) return true; - *funder_amount = AMOUNT_MSAT(0); + *opener_amount = AMOUNT_MSAT(0); return false; } @@ -62,7 +62,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, struct amount_sat funding, - enum side funder, + enum side opener, u16 to_self_delay, const struct keyset *keyset, u32 feerate_per_kw, @@ -104,7 +104,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, * 3. Subtract this base fee from the funder (either `to_local` or * `to_remote`), with a floor of 0 (see [Fee Payment](#fee-payment)). */ - if (!try_subtract_fee(funder, side, base_fee, &self_pay, &other_pay)) { + if (!try_subtract_fee(opener, side, base_fee, &self_pay, &other_pay)) { /* BOLT #2: * * The receiving node MUST fail the channel if: diff --git a/lightningd/channel.c b/lightningd/channel.c index 94687ea0d4b5..33dcb13d0065 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -145,7 +145,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, /* NULL or stolen */ struct wallet_shachain *their_shachain, enum channel_state state, - enum side funder, + enum side opener, /* NULL or stolen */ struct log *log, const char *transient_billboard TAKES, @@ -204,7 +204,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, shachain_init(&channel->their_shachain.chain); } channel->state = state; - channel->funder = funder; + channel->opener = opener; channel->owner = NULL; memset(&channel->billboard, 0, sizeof(channel->billboard)); channel->billboard.transient = tal_strdup(channel, transient_billboard); @@ -427,7 +427,7 @@ void channel_fail_forget(struct channel *channel, const char *fmt, ...) char *why; struct channel_id cid; - assert(channel->funder == REMOTE && + assert(channel->opener == REMOTE && channel->state == CHANNELD_AWAITING_LOCKIN); va_start(ap, fmt); why = tal_vfmt(tmpctx, fmt, ap); diff --git a/lightningd/channel.h b/lightningd/channel.h index f7f5ab7bc2ae..9fc5c432fdf1 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -34,7 +34,7 @@ struct channel { enum channel_state state; /* Which side offered channel? */ - enum side funder; + enum side opener; /* Is there a single subdaemon responsible for us? */ struct subd *owner; @@ -135,7 +135,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, /* NULL or stolen */ struct wallet_shachain *their_shachain STEALS, enum channel_state state, - enum side funder, + enum side opener, /* NULL or stolen */ struct log *log STEALS, const char *transient_billboard TAKES, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 9fba5eb7e2df..6d0f7dbaaa9b 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -481,7 +481,7 @@ void peer_start_channeld(struct channel *channel, &channel->channel_info.theirbase, &channel->channel_info.remote_per_commit, &channel->channel_info.old_remote_per_commit, - channel->funder, + channel->opener, channel->feerate_base, channel->feerate_ppm, channel->our_msat, @@ -523,7 +523,7 @@ void peer_start_channeld(struct channel *channel, subd_send_msg(channel->owner, take(initmsg)); /* On restart, feerate might not be what we expect: adjust now. */ - if (channel->funder == LOCAL) + if (channel->opener == LOCAL) try_update_feerates(ld, channel); } @@ -583,7 +583,7 @@ is_fundee_should_forget(struct lightningd *ld, */ /* Only applies if we are fundee. */ - if (channel->funder == LOCAL) + if (channel->opener == LOCAL) return false; /* Does not apply if we already saw the funding tx. */ @@ -746,7 +746,7 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, buffer + cidtok->start); } - if (cancel_channel->funder == REMOTE) + if (cancel_channel->opener == REMOTE) return command_fail(cmd, LIGHTNINGD, "Cannot cancel channel that was " "initiated by peer"); diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index d69310495346..353d95b0ad40 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -217,7 +217,7 @@ void peer_start_closingd(struct channel *channel, * [BOLT #3](03-transactions.md#fee-calculation). */ final_commit_feerate = get_feerate(channel->channel_info.fee_states, - channel->funder, LOCAL); + channel->opener, LOCAL); feelimit = commit_tx_base_fee(final_commit_feerate, 0); /* Pick some value above slow feerate (or min possible if unknown) */ @@ -283,7 +283,7 @@ void peer_start_closingd(struct channel *channel, channel->funding, &channel->local_funding_pubkey, &channel->channel_info.remote_fundingkey, - channel->funder, + channel->opener, amount_msat_to_sat_round_down(channel->our_msat), amount_msat_to_sat_round_down(their_msat), channel->our_config.dust_limit, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index d6f0d03364f9..4102b5802e72 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -560,7 +560,7 @@ enum watch_result onchaind_funding_spent(struct channel *channel, channel->shutdown_scriptpubkey[LOCAL], channel->shutdown_scriptpubkey[REMOTE], &final_key, - channel->funder, + channel->opener, &channel->local_basepoints, &channel->channel_info.theirbase, tx, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 9224c3efb4d2..a19b437510ff 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -64,7 +64,7 @@ struct uncommitted_channel { /* These are *not* filled in by new_uncommitted_channel: */ - /* Minimum funding depth (if funder == REMOTE). */ + /* Minimum funding depth (if opener == REMOTE). */ u32 minimum_depth; /* Our channel config. */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index b3e0db5b7cb7..a737f9652f6f 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -424,7 +424,7 @@ void channel_errmsg(struct channel *channel, /* We should immediately forget the channel if we receive error during * CHANNELD_AWAITING_LOCKIN if we are fundee. */ - if (!err_for_them && channel->funder == REMOTE + if (!err_for_them && channel->opener == REMOTE && channel->state == CHANNELD_AWAITING_LOCKIN) channel_fail_forget(channel, "%s: %s ERROR %s", channel->owner->name, @@ -453,7 +453,7 @@ static void json_add_htlcs(struct lightningd *ld, const struct htlc_out *hout; struct htlc_out_map_iter outi; u32 local_feerate = get_feerate(channel->channel_info.fee_states, - channel->funder, LOCAL); + channel->opener, LOCAL); /* FIXME: Add more fields. */ json_array_start(response, "htlcs"); @@ -526,7 +526,7 @@ static struct amount_sat commit_txfee(const struct channel *channel, struct lightningd *ld = channel->peer->ld; size_t num_untrimmed_htlcs = 0; u32 feerate = get_feerate(channel->channel_info.fee_states, - channel->funder, side); + channel->opener, side); struct amount_sat dust_limit; if (side == LOCAL) dust_limit = channel->our_config.dust_limit; @@ -656,7 +656,7 @@ static void json_add_channel(struct lightningd *ld, // FIXME @conscott : Modify this when dual-funded channels // are implemented json_object_start(response, "funding_allocation_msat"); - if (channel->funder == LOCAL) { + if (channel->opener == LOCAL) { json_add_u64(response, node_id_to_hexstr(tmpctx, &p->id), 0); json_add_u64(response, node_id_to_hexstr(tmpctx, &ld->id), channel->funding.satoshis * 1000); /* Raw: raw JSON field */ @@ -668,7 +668,7 @@ static void json_add_channel(struct lightningd *ld, json_object_end(response); json_object_start(response, "funding_msat"); - if (channel->funder == LOCAL) { + if (channel->opener == LOCAL) { json_add_sat_only(response, node_id_to_hexstr(tmpctx, &p->id), AMOUNT_SAT(0)); @@ -735,8 +735,8 @@ static void json_add_channel(struct lightningd *ld, /* Take away any currently-offered HTLCs. */ subtract_offered_htlcs(channel, &spendable); - /* If we're funder, subtract txfees we'll need to spend this */ - if (channel->funder == LOCAL) { + /* If we're opener, subtract txfees we'll need to spend this */ + if (channel->opener == LOCAL) { if (!amount_msat_sub_sat(&spendable, spendable, commit_txfee(channel, spendable, LOCAL))) @@ -767,8 +767,8 @@ static void json_add_channel(struct lightningd *ld, /* Take away any currently-offered HTLCs. */ subtract_received_htlcs(channel, &receivable); - /* If they're funder, subtract txfees they'll need to spend this */ - if (channel->funder == REMOTE) { + /* If they're opener, subtract txfees they'll need to spend this */ + if (channel->opener == REMOTE) { if (!amount_msat_sub_sat(&receivable, receivable, commit_txfee(channel, receivable, REMOTE))) diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index b71513b80aa6..ffc154785bf7 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1676,7 +1676,7 @@ void peer_sending_commitsig(struct channel *channel, const u8 *msg) &fee_states, &changed_htlcs, &commit_sig, &htlc_sigs) - || !fee_states_valid(fee_states, channel->funder)) { + || !fee_states_valid(fee_states, channel->opener)) { channel_internal_error(channel, "bad channel_sending_commitsig %s", tal_hex(channel, msg)); return; @@ -1716,7 +1716,7 @@ void peer_sending_commitsig(struct channel *channel, const u8 *msg) channel->channel_info.fee_states = tal_steal(channel, fee_states); adjust_channel_feerate_bounds(channel, get_feerate(fee_states, - channel->funder, + channel->opener, REMOTE)); if (!peer_save_commitsig_sent(channel, commitnum)) @@ -1871,7 +1871,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) &failed, &changed, &tx) - || !fee_states_valid(fee_states, channel->funder)) { + || !fee_states_valid(fee_states, channel->opener)) { channel_internal_error(channel, "bad fromwire_channel_got_commitsig %s", tal_hex(channel, msg)); @@ -1901,7 +1901,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) log_debug(channel->log, "got commitsig %"PRIu64 ": feerate %u, %zu added, %zu fulfilled, %zu failed, %zu changed", - commitnum, get_feerate(fee_states, channel->funder, LOCAL), + commitnum, get_feerate(fee_states, channel->opener, LOCAL), tal_count(added), tal_count(fulfilled), tal_count(failed), tal_count(changed)); @@ -1934,7 +1934,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) channel->channel_info.fee_states = tal_steal(channel, fee_states); adjust_channel_feerate_bounds(channel, get_feerate(fee_states, - channel->funder, + channel->opener, LOCAL)); /* Since we're about to send revoke, bump state again. */ @@ -1982,7 +1982,7 @@ void peer_got_revoke(struct channel *channel, const u8 *msg) &next_per_commitment_point, &fee_states, &changed) - || !fee_states_valid(fee_states, channel->funder)) { + || !fee_states_valid(fee_states, channel->opener)) { channel_internal_error(channel, "bad fromwire_channel_got_revoke %s", tal_hex(channel, msg)); return; diff --git a/onchaind/onchain_wire.csv b/onchaind/onchain_wire.csv index ebff07fe6b5e..298646d5f342 100644 --- a/onchaind/onchain_wire.csv +++ b/onchaind/onchain_wire.csv @@ -27,7 +27,7 @@ msgdata,onchain_init,remote_scriptpubkey_len,u16, msgdata,onchain_init,remote_scriptpubkey,u8,remote_scriptpubkey_len msgdata,onchain_init,ourwallet_pubkey,pubkey, # We need these two for commit number obscurer -msgdata,onchain_init,funder,enum side, +msgdata,onchain_init,opener,enum side, msgdata,onchain_init,local_basepoints,basepoints, msgdata,onchain_init,remote_basepoints,basepoints, msgdata,onchain_init,tx,bitcoin_tx, diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index c2522ad6737f..830cd2726076 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -705,7 +705,7 @@ static void unknown_spend(struct tracked_output *out, } static u64 unmask_commit_number(const struct bitcoin_tx *tx, - enum side funder, + enum side opener, const struct pubkey *local_payment_basepoint, const struct pubkey *remote_payment_basepoint) { @@ -718,7 +718,7 @@ static u64 unmask_commit_number(const struct bitcoin_tx *tx, * * The 48-bit commitment number is obscured by `XOR` with the lower 48 bits of... */ - obscurer = commit_number_obscurer(keys[funder], keys[!funder]); + obscurer = commit_number_obscurer(keys[opener], keys[!opener]); /* BOLT #3: * @@ -2648,7 +2648,7 @@ int main(int argc, char *argv[]) const tal_t *ctx = tal(NULL, char); u8 *msg; struct pubkey remote_per_commit_point, old_remote_per_commit_point; - enum side funder; + enum side opener; struct basepoints basepoints[NUM_SIDES]; struct shachain shachain; struct bitcoin_tx *tx; @@ -2686,7 +2686,7 @@ int main(int argc, char *argv[]) &scriptpubkey[LOCAL], &scriptpubkey[REMOTE], &our_wallet_pubkey, - &funder, + &opener, &basepoints[LOCAL], &basepoints[REMOTE], &tx, @@ -2763,7 +2763,7 @@ int main(int argc, char *argv[]) * *latest commitment transaction*. */ struct secret revocation_preimage; - commit_num = unmask_commit_number(tx, funder, + commit_num = unmask_commit_number(tx, opener, &basepoints[LOCAL].payment, &basepoints[REMOTE].payment); diff --git a/openingd/openingd.c b/openingd/openingd.c index 46e33f315cee..b5e69071dc56 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -129,8 +129,8 @@ static u8 *dev_upfront_shutdown_script(const tal_t *ctx) } /*~ If we can't agree on parameters, we fail to open the channel. If we're - * the funder, we need to tell lightningd, otherwise it never really notices. */ -static void negotiation_aborted(struct state *state, bool am_funder, + * the opener, we need to tell lightningd, otherwise it never really notices. */ +static void negotiation_aborted(struct state *state, bool am_opener, const char *why) { status_debug("aborted opening negotiation: %s", why); @@ -143,7 +143,7 @@ static void negotiation_aborted(struct state *state, bool am_funder, peer_billboard(true, why); /* If necessary, tell master that funding failed. */ - if (am_funder) { + if (am_opener) { u8 *msg = towire_opening_funder_failed(NULL, why); wire_sync_write(REQ_FD, take(msg)); } @@ -161,7 +161,7 @@ static void negotiation_aborted(struct state *state, bool am_funder, } /*~ For negotiation failures: we tell them the parameter we didn't like. */ -static void negotiation_failed(struct state *state, bool am_funder, +static void negotiation_failed(struct state *state, bool am_opener, const char *fmt, ...) { va_list ap; @@ -176,7 +176,7 @@ static void negotiation_failed(struct state *state, bool am_funder, "You gave bad parameters: %s", errmsg); sync_crypto_write(state->pps, take(msg)); - negotiation_aborted(state, am_funder, errmsg); + negotiation_aborted(state, am_opener, errmsg); } /*~ This is the key function that checks that their configuration is reasonable: @@ -184,7 +184,7 @@ static void negotiation_failed(struct state *state, bool am_funder, * they've accepted our open. */ static bool check_config_bounds(struct state *state, const struct channel_config *remoteconf, - bool am_funder) + bool am_opener) { struct amount_sat capacity; struct amount_sat reserve; @@ -196,7 +196,7 @@ static bool check_config_bounds(struct state *state, * - `to_self_delay` is unreasonably large. */ if (remoteconf->to_self_delay > state->max_to_self_delay) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "to_self_delay %u larger than %u", remoteconf->to_self_delay, state->max_to_self_delay); @@ -219,7 +219,7 @@ static bool check_config_bounds(struct state *state, if (!amount_sat_add(&reserve, remoteconf->channel_reserve, state->localconf.channel_reserve)) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "channel_reserve_satoshis %s" " too large", type_to_string(tmpctx, struct amount_sat, @@ -229,7 +229,7 @@ static bool check_config_bounds(struct state *state, /* If reserves are larger than total sat, we fail. */ if (!amount_sat_sub(&capacity, state->funding, reserve)) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "channel_reserve_satoshis %s" " and %s too large for funding %s", type_to_string(tmpctx, struct amount_sat, @@ -250,7 +250,7 @@ static bool check_config_bounds(struct state *state, /* If the minimum htlc is greater than the capacity, the channel is * useless. */ if (amount_msat_greater_sat(remoteconf->htlc_minimum, capacity)) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "htlc_minimum_msat %s" " too large for funding %s" " capacity_msat %s", @@ -267,7 +267,7 @@ static bool check_config_bounds(struct state *state, * set by lightningd, don't bother opening it. */ if (amount_msat_greater_sat(state->min_effective_htlc_capacity, capacity)) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "channel capacity with funding %s," " reserves %s/%s," " max_htlc_value_in_flight_msat is %s," @@ -289,7 +289,7 @@ static bool check_config_bounds(struct state *state, /* We don't worry about how many HTLCs they accept, as long as > 0! */ if (remoteconf->max_accepted_htlcs == 0) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "max_accepted_htlcs %u invalid", remoteconf->max_accepted_htlcs); return false; @@ -302,7 +302,7 @@ static bool check_config_bounds(struct state *state, * - `max_accepted_htlcs` is greater than 483. */ if (remoteconf->max_accepted_htlcs > 483) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "max_accepted_htlcs %u too large", remoteconf->max_accepted_htlcs); return false; @@ -316,7 +316,7 @@ static bool check_config_bounds(struct state *state, */ if (amount_sat_greater(remoteconf->dust_limit, remoteconf->channel_reserve)) { - negotiation_failed(state, am_funder, + negotiation_failed(state, am_opener, "dust_limit_satoshis %s" " too large for channel_reserve_satoshis %s", type_to_string(tmpctx, struct amount_sat, @@ -367,7 +367,7 @@ static void temporary_channel_id(struct channel_id *channel_id) /*~ Handle random messages we might get during opening negotiation, (eg. gossip) * returning the first non-handled one, or NULL if we aborted negotiation. */ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, - bool am_funder) + bool am_opener) { /* This is an event loop of its own. That's generally considered poor * form, but we use it in a very limited way. */ @@ -429,7 +429,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, } /* Close connection on all_channels error. */ if (all_channels) { - if (am_funder) { + if (am_opener) { msg = towire_opening_funder_failed(NULL, err); wire_sync_write(REQ_FD, take(msg)); @@ -437,7 +437,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, peer_failed_received_errmsg(state->pps, err, NULL, false); } - negotiation_aborted(state, am_funder, + negotiation_aborted(state, am_opener, tal_fmt(tmpctx, "They sent error %s", err)); /* Return NULL so caller knows to stop negotiating. */ @@ -1065,7 +1065,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) return NULL; } - /* These checks are the same whether we're funder or fundee... */ + /* These checks are the same whether we're opener or accepter... */ if (!check_config_bounds(state, &state->remoteconf, false)) return NULL; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 3a12cda3793b..990dfea21b7b 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1039,8 +1039,8 @@ static bool channelseq(struct channel *c1, struct channel *c2) CHECK(pubkey_eq(&ci1->remote_per_commit, &ci2->remote_per_commit)); CHECK(pubkey_eq(&ci1->old_remote_per_commit, &ci2->old_remote_per_commit)); CHECK(ci1->their_config.id != 0 && ci1->their_config.id == ci2->their_config.id); - CHECK(fee_states_valid(ci1->fee_states, c1->funder)); - CHECK(fee_states_valid(ci2->fee_states, c2->funder)); + CHECK(fee_states_valid(ci1->fee_states, c1->opener)); + CHECK(fee_states_valid(ci2->fee_states, c2->opener)); for (enum htlc_state i = 0; i < ARRAY_SIZE(ci1->fee_states->feerate); i++) { if (ci1->fee_states->feerate[i] == NULL) { @@ -1125,7 +1125,7 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx) pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); node_id_from_pubkey(&id, &pk); feerate = 31337; - ci->fee_states = new_fee_states(w, c1.funder, &feerate); + ci->fee_states = new_fee_states(w, c1.opener, &feerate); mempat(scriptpubkey, tal_count(scriptpubkey)); c1.first_blocknum = 1; parse_wireaddr_internal("localhost:1234", &addr, 0, false, false, false, diff --git a/wallet/wallet.c b/wallet/wallet.c index 86f1b6c0f0dd..638fb09e1efc 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1359,7 +1359,7 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) else db_bind_null(stmt, 1); db_bind_int(stmt, 2, chan->state); - db_bind_int(stmt, 3, chan->funder); + db_bind_int(stmt, 3, chan->opener); db_bind_int(stmt, 4, chan->channel_flags); db_bind_int(stmt, 5, chan->minimum_depth); From c7b9dffefc801c8bfb04f7cb1d4ec961f616b546 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 9 Sep 2019 22:45:23 -0500 Subject: [PATCH 003/131] df: add wires for dual funding messages plus tests. --- channeld/channeld.c | 8 + gossipd/gossipd.c | 8 +- wire/extracted_peer_experimental_737016aef | 92 ++++ wire/peer_wire.c | 16 +- wire/test/Makefile | 2 + wire/test/run-peer-wire.c | 508 ++++++++++++++++++++- wire/wire.h | 1 + 7 files changed, 631 insertions(+), 4 deletions(-) create mode 100644 wire/extracted_peer_experimental_737016aef diff --git a/channeld/channeld.c b/channeld/channeld.c index ce1aacbfcca8..3a4d19f91912 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1967,6 +1967,14 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_FUNDING_SIGNED: case WIRE_CHANNEL_REESTABLISH: case WIRE_CLOSING_SIGNED: +#if EXPERIMENTAL_FEATURES + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_FUNDING_COMPOSE: + case WIRE_ACCEPTER_SIGS: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#endif /* EXPERIMENTAL_FEATURES */ break; /* These are all swallowed by handle_peer_gossip_or_error */ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index c2d77373ad91..86092198d052 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -490,7 +490,13 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: -#endif + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_FUNDING_COMPOSE: + case WIRE_ACCEPTER_SIGS: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#endif /* EXPERIMENTAL_FEATURES */ status_broken("peer %s: relayed unexpected msg of type %s", type_to_string(tmpctx, struct node_id, &peer->id), wire_type_name(fromwire_peektype(msg))); diff --git a/wire/extracted_peer_experimental_737016aef b/wire/extracted_peer_experimental_737016aef new file mode 100644 index 000000000000..a1048abd4475 --- /dev/null +++ b/wire/extracted_peer_experimental_737016aef @@ -0,0 +1,92 @@ +--- wire/extracted_peer_wire_csv 2019-08-21 13:30:32.219341098 -0500 ++++ - 2019-09-11 17:38:34.177415676 -0500 +@@ -77,6 +77,89 @@ + msgtype,funding_locked,36 + msgdata,funding_locked,channel_id,channel_id, + msgdata,funding_locked,next_per_commitment_point,point, ++msgtype,open_channel2,56 ++msgdata,open_channel2,chain_hash,chain_hash, ++msgdata,open_channel2,temporary_channel_id,byte,32 ++msgdata,open_channel2,funding_satoshis,u64, ++msgdata,open_channel2,push_msat,u64, ++msgdata,open_channel2,dust_limit_satoshis,u64, ++msgdata,open_channel2,max_htlc_value_in_flight_msat,u64, ++msgdata,open_channel2,htlc_minimum_msat,u64, ++msgdata,open_channel2,feerate_per_kw,u32, ++msgdata,open_channel2,feerate_per_kw_funding,u32, ++msgdata,open_channel2,to_self_delay,u16, ++msgdata,open_channel2,max_accepted_htlcs,u16, ++msgdata,open_channel2,funding_pubkey,point, ++msgdata,open_channel2,revocation_basepoint,point, ++msgdata,open_channel2,payment_basepoint,point, ++msgdata,open_channel2,delayed_payment_basepoint,point, ++msgdata,open_channel2,htlc_basepoint,point, ++msgdata,open_channel2,first_per_commitment_point,point, ++msgdata,open_channel2,channel_flags,byte, ++msgdata,open_channel2,opening_tlv,opening_tlvs, ++tlvtype,opening_tlvs,option_upfront_shutdown_script,1 ++tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, ++tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++msgtype,accept_channel2,57 ++msgdata,accept_channel2,temporary_channel_id,byte,32 ++msgdata,accept_channel2,funding_satoshis,u64, ++msgdata,accept_channel2,dust_limit_satoshis,u64, ++msgdata,accept_channel2,max_htlc_value_in_flight_msat,u64, ++msgdata,accept_channel2,htlc_minimum_msat,u64, ++msgdata,accept_channel2,minimum_depth,u32, ++msgdata,accept_channel2,to_self_delay,u16, ++msgdata,accept_channel2,max_accepted_htlcs,u16, ++msgdata,accept_channel2,funding_pubkey,point, ++msgdata,accept_channel2,revocation_basepoint,point, ++msgdata,accept_channel2,payment_basepoint,point, ++msgdata,accept_channel2,delayed_payment_basepoint,point, ++msgdata,accept_channel2,htlc_basepoint,point, ++msgdata,accept_channel2,first_per_commitment_point,point, ++msgdata,accept_channel2,accept_tlv,accept_tlvs, ++tlvtype,accept_tlvs,option_upfront_shutdown_script,1 ++tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, ++tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++msgtype,funding_compose,58 ++msgdata,funding_compose,temporary_channel_id,byte,32 ++msgdata,funding_compose,num_inputs,u16, ++msgdata,funding_compose,input_info,input_info,num_inputs ++msgdata,funding_compose,num_outputs,u16, ++msgdata,funding_compose,output_info,output_info,num_outputs ++subtype,input_info ++subtypedata,input_info,input_satoshis,u64, ++subtypedata,input_info,prevtx_txid,sha256, ++subtypedata,input_info,prevtx_vout,u32, ++subtypedata,input_info,prevtx_scriptpubkey_len,u16, ++subtypedata,input_info,prevtx_scriptpubkey,byte,prevtx_scriptpubkey_len ++subtypedata,input_info,max_witness_len,u16, ++subtypedata,input_info,scriptlen,u16, ++subtypedata,input_info,script,byte,scriptlen ++subtype,output_info ++subtypedata,output_info,output_satoshis,u64, ++subtypedata,output_info,scriptlen,u16, ++subtypedata,output_info,script,byte,scriptlen ++msgtype,accepter_sigs,60 ++msgdata,accepter_sigs,channel_id,channel_id, ++msgdata,accepter_sigs,commitment_signature,signature, ++msgdata,accepter_sigs,num_witnesses,u16, ++msgdata,accepter_sigs,witness_stack,witness_stack,num_witnesses ++subtype,witness_stack ++subtypedata,witness_stack,num_input_witness,u16, ++subtypedata,witness_stack,witness_element,witness_element,num_input_witness ++subtype,witness_element ++subtypedata,witness_element,len,u16, ++subtypedata,witness_element,witness,byte,len ++msgtype,init_rbf,62 ++msgdata,init_rbf,channel_id,channel_id, ++msgdata,init_rbf,funding_satoshis,u64, ++msgdata,init_rbf,feerate_per_kw,u32, ++msgdata,init_rbf,feerate_per_kw_funding,u32, ++msgdata,init_rbf,num_additional_inputs,u16, ++msgdata,init_rbf,input_info,input_info,num_additional_inputs ++msgdata,init_rbf,num_outputs,u16, ++msgdata,init_rbf,output_info,output_info,num_outputs ++msgtype,ack_rbf,63 ++msgdata,ack_rbf,channel_id,channel_id, + msgtype,shutdown,38 + msgdata,shutdown,channel_id,channel_id, + msgdata,shutdown,len,u16, diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 737e2fbb6caa..607b7a3fbdba 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -33,7 +33,13 @@ static bool unknown_type(enum wire_type t) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: -#endif + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_FUNDING_COMPOSE: + case WIRE_ACCEPTER_SIGS: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#endif /* EXPERIMENTAL_FEATURES */ return false; } return true; @@ -73,7 +79,13 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: -#endif + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_FUNDING_COMPOSE: + case WIRE_ACCEPTER_SIGS: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#endif /* EXPERIMENTAL_FEATURES */ break; } return false; diff --git a/wire/test/Makefile b/wire/test/Makefile index d0a8f542d203..54bb5c6823a9 100644 --- a/wire/test/Makefile +++ b/wire/test/Makefile @@ -9,6 +9,8 @@ WIRE_TEST_PROGRAMS := $(WIRE_TEST_OBJS:.o=) WIRE_TEST_COMMON_OBJS := \ common/utils.o +wire/test/run-peer-wire: common/bigsize.o + update-mocks: $(WIRE_TEST_SRC:%=update-mocks/%) $(WIRE_TEST_PROGRAMS): $(WIRE_TEST_COMMON_OBJS) $(BITCOIN_OBJS) diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 07c08f7c4816..46befd781afc 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -1,6 +1,6 @@ -#include "../towire.c" #include "../fromwire.c" #include "../peer_wire.c" +#include "../towire.c" #include #include @@ -81,6 +81,21 @@ static void set_node_id(struct node_id *id) (tal_count((p1)->field) == tal_count((p2)->field) \ && (tal_count((p1)->field) == 0 || memcmp((p1)->field, (p2)->field, tal_bytelen((p1)->field)) == 0)) +#define eq_struct_set(p1, p2, field, type) \ + do { \ + ok &= (!(p1) && !(p2)) || ((p1) && (p2)); \ + ok &= (!(p1)->field && !(p2)->field) || ((p1)->field && (p2)->field); \ + if (ok && (p1) && (p1)->field) \ + for (size_t i = 0; i < tal_count((p1)->field); i++) { \ + struct type *_a, *_b; \ + _a = a->field[i]; \ + _b = b->field[i]; \ + ok &= (_a && _b) || (!_a && !_b); \ + if (ok && _a) \ + ok &= (type##_eq(_a, _b)); \ + } \ + } while (0) \ + /* Convenience structs for everyone! */ struct msg_error { struct channel_id channel_id; @@ -236,6 +251,67 @@ struct msg_update_fee { u32 feerate_per_kw; }; +/* Open Channel 2 */ +struct msg_open_channel2 { + struct bitcoin_blkid chain_hash; + struct channel_id temporary_channel_id; + struct amount_sat funding_satoshis; + struct amount_msat push_msat; + struct amount_sat dust_limit_satoshis; + struct amount_msat max_htlc_value_in_flight_msat; + struct amount_msat htlc_minimum_msat; + u32 feerate_per_kw; + u32 feerate_per_kw_funding; + u16 to_self_delay; + u16 max_accepted_htlcs; + struct pubkey funding_pubkey; + struct pubkey revocation_basepoint; + struct pubkey payment_basepoint; + struct pubkey delayed_payment_basepoint; + struct pubkey htlc_basepoint; + struct pubkey first_per_commitment_point; + u8 channel_flags; + struct tlv_opening_tlvs *tlv; +}; +struct msg_accept_channel2 { + struct channel_id temporary_channel_id; + struct amount_sat funding_satoshis; + struct amount_sat dust_limit_satoshis; + struct amount_msat max_htlc_value_in_flight_msat; + struct amount_msat htlc_minimum_msat; + u32 minimum_depth; + u16 to_self_delay; + u16 max_accepted_htlcs; + struct pubkey funding_pubkey; + struct pubkey revocation_basepoint; + struct pubkey payment_basepoint; + struct pubkey delayed_payment_basepoint; + struct pubkey htlc_basepoint; + struct pubkey first_per_commitment_point; + struct tlv_accept_tlvs *tlv; +}; +struct msg_funding_compose { + struct channel_id temporary_channel_id; + struct input_info **input_infos; + struct output_info **output_infos; +}; +struct msg_accepter_sigs { + struct channel_id channel_id; + secp256k1_ecdsa_signature commitment_signature; + struct witness_stack **witness_stacks; +}; +struct msg_init_rbf { + struct channel_id channel_id; + struct amount_sat funding_satoshis; + u32 feerate_per_kw; + u32 feerate_per_kw_funding; + struct input_info **input_infos; + struct output_info **output_infos; +}; +struct msg_ack_rbf { + struct channel_id channel_id; +}; + static void *towire_struct_channel_announcement(const tal_t *ctx, const struct msg_channel_announcement *s) { @@ -773,6 +849,294 @@ static struct msg_init *fromwire_struct_init(const tal_t *ctx, const void *p) return s; } +#if EXPERIMENTAL_FEATURES +static void *towire_struct_open_channel2(const tal_t *ctx, + const struct msg_open_channel2 *s) +{ + return towire_open_channel2(ctx, + &s->chain_hash, + &s->temporary_channel_id, + s->funding_satoshis, + s->push_msat, + s->dust_limit_satoshis, + s->max_htlc_value_in_flight_msat, + s->htlc_minimum_msat, + s->feerate_per_kw, + s->feerate_per_kw_funding, + s->to_self_delay, + s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->delayed_payment_basepoint, + &s->htlc_basepoint, + &s->first_per_commitment_point, + s->channel_flags, + s->tlv); +} + +static struct msg_open_channel2 *fromwire_struct_open_channel2(const tal_t *ctx, const void *p) +{ + struct msg_open_channel2 *s = tal(ctx, struct msg_open_channel2); + s->tlv = tlv_opening_tlvs_new(ctx); + + if (fromwire_open_channel2(p, &s->chain_hash, + &s->temporary_channel_id, + &s->funding_satoshis, + &s->push_msat, + &s->dust_limit_satoshis, + &s->max_htlc_value_in_flight_msat, + &s->htlc_minimum_msat, + &s->feerate_per_kw, + &s->feerate_per_kw_funding, + &s->to_self_delay, + &s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->delayed_payment_basepoint, + &s->htlc_basepoint, + &s->first_per_commitment_point, + &s->channel_flags, + s->tlv)) + return s; + return tal_free(s); +} +static void *towire_struct_accept_channel2(const tal_t *ctx, + const struct msg_accept_channel2 *s) +{ + return towire_accept_channel2(ctx, + &s->temporary_channel_id, + s->funding_satoshis, + s->dust_limit_satoshis, + s->max_htlc_value_in_flight_msat, + s->htlc_minimum_msat, + s->minimum_depth, + s->to_self_delay, + s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->htlc_basepoint, + &s->delayed_payment_basepoint, + &s->first_per_commitment_point, + s->tlv); +} + +static struct msg_accept_channel2 *fromwire_struct_accept_channel2(const tal_t *ctx, const void *p) +{ + struct msg_accept_channel2 *s = tal(ctx, struct msg_accept_channel2); + s->tlv = tlv_accept_tlvs_new(ctx); + + if (fromwire_accept_channel2(p, &s->temporary_channel_id, + &s->funding_satoshis, + &s->dust_limit_satoshis, + &s->max_htlc_value_in_flight_msat, + &s->htlc_minimum_msat, + &s->minimum_depth, + &s->to_self_delay, + &s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->htlc_basepoint, + &s->delayed_payment_basepoint, + &s->first_per_commitment_point, + s->tlv)) + return s; + return tal_free(s); +} +static void *towire_struct_funding_compose(const tal_t *ctx, + struct msg_funding_compose *s) +{ + return towire_funding_compose(ctx, + &s->temporary_channel_id, + (const struct input_info **)s->input_infos, + (const struct output_info **)s->output_infos); +} +static struct msg_funding_compose *fromwire_struct_funding_compose(const tal_t *ctx, const void *p) +{ + struct msg_funding_compose *s = tal(ctx, struct msg_funding_compose); + + if (fromwire_funding_compose(ctx, p, + &s->temporary_channel_id, + &s->input_infos, + &s->output_infos)) + return s; + return tal_free(s); +} +static void *towire_struct_accepter_sigs(const tal_t *ctx, + struct msg_accepter_sigs *s) +{ + return towire_accepter_sigs(ctx, + &s->channel_id, + &s->commitment_signature, + (const struct witness_stack **)s->witness_stacks); +} +static struct msg_accepter_sigs *fromwire_struct_accepter_sigs(const tal_t *ctx, const void *p) +{ + struct msg_accepter_sigs *s = tal(ctx, struct msg_accepter_sigs); + + if (fromwire_accepter_sigs(ctx, p, + &s->channel_id, + &s->commitment_signature, + &s->witness_stacks)) { + return s; + } + return tal_free(s); +} + +static void *towire_struct_init_rbf(const tal_t *ctx, + struct msg_init_rbf *s) +{ + return towire_init_rbf(ctx, + &s->channel_id, + s->funding_satoshis, + s->feerate_per_kw, + s->feerate_per_kw_funding, + (const struct input_info **)s->input_infos, + (const struct output_info **)s->output_infos); +} +static struct msg_init_rbf *fromwire_struct_init_rbf(const tal_t *ctx, const void *p) +{ + struct msg_init_rbf *s = tal(ctx, struct msg_init_rbf); + + if (fromwire_init_rbf(ctx, p, + &s->channel_id, + &s->funding_satoshis, + &s->feerate_per_kw, + &s->feerate_per_kw_funding, + &s->input_infos, + &s->output_infos)) + return s; + return tal_free(s); +} +static void *towire_struct_ack_rbf(const tal_t *ctx, const struct msg_ack_rbf *s) +{ + return towire_ack_rbf(ctx, &s->channel_id); +} +static struct msg_ack_rbf *fromwire_struct_ack_rbf(const tal_t *ctx, const void *p) +{ + struct msg_ack_rbf *s = tal(ctx, struct msg_ack_rbf); + + if (fromwire_ack_rbf(p, &s->channel_id)) + return s; + return tal_free(s); +} + +static bool open_option_upfront_shutdown_script_eq(const struct tlv_opening_tlvs_option_upfront_shutdown_script *a, + const struct tlv_opening_tlvs_option_upfront_shutdown_script *b) +{ + return (!a && !b) + || (a && b && eq_var(a, b, shutdown_scriptpubkey)); +} + +static bool accept_option_upfront_shutdown_script_eq(const struct tlv_accept_tlvs_option_upfront_shutdown_script *a, + const struct tlv_accept_tlvs_option_upfront_shutdown_script *b) +{ + return (!a && !b) + || (a && b && eq_var(a, b, shutdown_scriptpubkey)); +} + +static bool input_info_eq(struct input_info *a, + struct input_info *b) +{ + return eq_with(a, b, prevtx_vout) + && eq_var(a, b, prevtx_scriptpubkey) + && eq_field(a, b, max_witness_len) + && eq_var(a, b, script); +} + +static bool output_info_eq(struct output_info *a, + struct output_info *b) +{ + return eq_with(a, b, output_satoshis) + && eq_var(a, b, script); +} + +static bool witness_element_eq(struct witness_element *a, + struct witness_element *b) +{ + return ((!a && !b) || (a && b)) + && eq_var(a, b, witness); +} + +static bool witness_stack_eq(struct witness_stack *a, + struct witness_stack *b) +{ + bool ok = true; + eq_struct_set(a, b, witness_element, witness_element); + return ok; +} + + +static bool opening_tlv_eq(const struct tlv_opening_tlvs *a, + const struct tlv_opening_tlvs *b) +{ + return (!a && !b) || + (a && b && + open_option_upfront_shutdown_script_eq(a->option_upfront_shutdown_script, + b->option_upfront_shutdown_script)); +} + +static bool accept_tlv_eq(const struct tlv_accept_tlvs *a, + const struct tlv_accept_tlvs *b) +{ + return (!a && !b) || + (a && b && + accept_option_upfront_shutdown_script_eq(a->option_upfront_shutdown_script, + b->option_upfront_shutdown_script)); +} + +static bool open_channel2_eq(const struct msg_open_channel2 *a, + const struct msg_open_channel2 *b) +{ + return eq_with(a, b, max_accepted_htlcs) + && eq_between(a, b, funding_pubkey, channel_flags) + && opening_tlv_eq(a->tlv, b->tlv); +} + +static bool accept_channel2_eq(const struct msg_accept_channel2 *a, + const struct msg_accept_channel2 *b) +{ + return eq_with(a, b, max_accepted_htlcs) + && eq_between(a, b, funding_pubkey, first_per_commitment_point) + && accept_tlv_eq(a->tlv, b->tlv); +} + +static bool funding_compose_eq(const struct msg_funding_compose *a, + const struct msg_funding_compose *b) +{ + bool ok = true; + eq_struct_set(a, b, input_infos, input_info); + eq_struct_set(a, b, output_infos, output_info); + return ok && eq_upto(a, b, input_infos); +} + +static bool accepter_sigs_eq(const struct msg_accepter_sigs *a, + const struct msg_accepter_sigs *b) +{ + bool ok = true; + eq_struct_set(a, b, witness_stacks, witness_stack); + return ok && eq_upto(a, b, witness_stacks); +} + +static bool init_rbf_eq(const struct msg_init_rbf *a, + const struct msg_init_rbf *b) +{ + bool ok = true; + eq_struct_set(a, b, input_infos, input_info); + eq_struct_set(a, b, output_infos, output_info); + return ok && eq_upto(a, b, input_infos); +} + +static bool ack_rbf_eq(const struct msg_ack_rbf *a, + const struct msg_ack_rbf *b) +{ + return memcmp(a, b, sizeof(*a)) == 0; +} +#endif /* EXPERIMENTAL_FEATURES */ + static bool channel_announcement_eq(const struct msg_channel_announcement *a, const struct msg_channel_announcement *b) { @@ -955,6 +1319,19 @@ static bool node_announcement_eq(const struct msg_node_announcement *a, assert(!b || !type##_eq(a, b)); \ } +#if EXPERIMENTAL_FEATURES +/* Test failure due to duplicate TLV message */ +static void test_open_channel2_tlv_message_duplicate(const tal_t *ctx, u8 *msg) +{ + size_t len = tal_count(msg); + u8 *duplicate = tal_arr(ctx, u8, 10); + memcpy(duplicate, msg + (len - 10), 10); + towire(&msg, duplicate, 10); + msg[len - 11] = 20; /* duplicate the size variable */ + assert(fromwire_struct_open_channel2(ctx, msg) == NULL); +} +#endif /* EXPERIMENTAL_FEATURES */ + #define test_corruption(a, b, type) \ test_bitflip_and_short(a, b, type, true) @@ -986,6 +1363,17 @@ int main(void) struct msg_accept_channel ac, *ac2; struct msg_update_add_htlc uah, *uah2; struct msg_node_announcement na, *na2; + +#if EXPERIMENTAL_FEATURES + /* v2 channel establishment */ + struct msg_open_channel2 ocv2, *ocv22; + struct msg_accept_channel2 acv2, *acv22; + struct msg_funding_compose fcom, *fcom2; + struct msg_accepter_sigs acs, *acs2; + struct msg_init_rbf irbf, *irbf2; + struct msg_ack_rbf arbf, *arbf2; +#endif /* EXPERIMENTAL_FEATURES */ + void *ctx = tal(NULL, char); size_t i; u8 *msg; @@ -1177,6 +1565,124 @@ int main(void) assert(node_announcement_eq(&na, na2)); test_corruption(&na, na2, node_announcement); +#if EXPERIMENTAL_FEATURES + /* Channel Establishment v2 */ + memset(&ocv2, 2, sizeof(ocv2)); + set_pubkey(&ocv2.funding_pubkey); + set_pubkey(&ocv2.revocation_basepoint); + set_pubkey(&ocv2.payment_basepoint); + set_pubkey(&ocv2.delayed_payment_basepoint); + set_pubkey(&ocv2.htlc_basepoint); + set_pubkey(&ocv2.first_per_commitment_point); + + ocv2.tlv = tal(ctx, struct tlv_opening_tlvs); + ocv2.tlv->option_upfront_shutdown_script = tal(ctx, struct tlv_opening_tlvs_option_upfront_shutdown_script); + ocv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = tal_arr(ctx, u8, 2); + memset(ocv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey, 2, 2); + + msg = towire_struct_open_channel2(ctx, &ocv2); + ocv22 = fromwire_struct_open_channel2(ctx, msg); + assert(open_channel2_eq(&ocv2, ocv22)); + test_corruption_tlv(&ocv2, ocv22, open_channel2); + test_open_channel2_tlv_message_duplicate(ctx, msg); + + memset(&acv2, 2, sizeof(acv2)); + set_pubkey(&acv2.funding_pubkey); + set_pubkey(&acv2.revocation_basepoint); + set_pubkey(&acv2.payment_basepoint); + set_pubkey(&acv2.delayed_payment_basepoint); + set_pubkey(&acv2.htlc_basepoint); + set_pubkey(&acv2.first_per_commitment_point); + + acv2.tlv = tal(ctx, struct tlv_accept_tlvs); + acv2.tlv->option_upfront_shutdown_script = tal(ctx, struct tlv_accept_tlvs_option_upfront_shutdown_script); + acv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = tal_arr(ctx, u8, 2); + memset(acv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey, 2, 2); + + msg = towire_struct_accept_channel2(ctx, &acv2); + acv22 = fromwire_struct_accept_channel2(ctx, msg); + assert(accept_channel2_eq(&acv2, acv22)); + test_corruption_tlv(&acv2, acv22, accept_channel2); + + memset(&fcom, 2, sizeof(fcom)); + fcom.input_infos = tal_arr(ctx, struct input_info *, 2); + memset(fcom.input_infos, 2, sizeof(struct input_info *) * 2); + for (i = 0; i < 2; i++) { + fcom.input_infos[i] = tal(ctx, struct input_info); + memset(fcom.input_infos[i], 2, sizeof(struct input_info)); + fcom.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); + memset(fcom.input_infos[i]->prevtx_scriptpubkey, 2, 2); + fcom.input_infos[i]->script = tal_arr(ctx, u8, 2); + memset(fcom.input_infos[i]->script, 2, 2); + } + fcom.output_infos = tal_arr(ctx, struct output_info *, 2); + memset(fcom.output_infos, 2, sizeof(struct output_info *)*2); + for (i = 0; i < 2; i++) { + fcom.output_infos[i] = tal(ctx, struct output_info); + memset(fcom.output_infos[i], 2, sizeof(struct output_info)); + fcom.output_infos[i]->script = tal_arr(ctx, u8, 2); + memset(fcom.output_infos[i]->script, 2, 2); + } + + msg = towire_struct_funding_compose(ctx, &fcom); + fcom2 = fromwire_struct_funding_compose(ctx, msg); + assert(funding_compose_eq(&fcom, fcom2)); + test_corruption(&fcom, fcom2, funding_compose); + + memset(&acs, 2, sizeof(acs)); + acs.witness_stacks = tal_arr(ctx, struct witness_stack *, 2); + memset(acs.witness_stacks, 2, sizeof(struct witness_stack *) * 2); + for (i = 0; i < 2; i++) { + acs.witness_stacks[i] = tal(ctx, struct witness_stack); + memset(acs.witness_stacks[i], 2, sizeof(struct witness_stack)); + acs.witness_stacks[i]->witness_element = tal_arr(ctx, struct witness_element *, 2); + memset(acs.witness_stacks[i]->witness_element, 2, sizeof(struct witness_element *) * 2); + for (size_t j = 0; j < 2; j++) { + acs.witness_stacks[i]->witness_element[j] = tal(ctx, struct witness_element); + memset(acs.witness_stacks[i]->witness_element[j], 2, sizeof(struct witness_element)); + acs.witness_stacks[i]->witness_element[j]->witness = tal_arr(ctx, u8, 2); + memset(acs.witness_stacks[i]->witness_element[j]->witness, 2, 2); + } + } + + msg = towire_struct_accepter_sigs(ctx, &acs); + acs2 = fromwire_struct_accepter_sigs(ctx, msg); + assert(accepter_sigs_eq(&acs, acs2)); + test_corruption(&acs, acs2, accepter_sigs); + + memset(&irbf, 2, sizeof(irbf)); + irbf.input_infos = tal_arr(ctx, struct input_info *, 2); + memset(irbf.input_infos, 2, sizeof(struct input_info *) * 2); + for (i = 0; i < 2; i++) { + irbf.input_infos[i] = tal(ctx, struct input_info); + memset(irbf.input_infos[i], 2, sizeof(struct input_info)); + irbf.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); + memset(irbf.input_infos[i]->prevtx_scriptpubkey, 2, 2); + irbf.input_infos[i]->script = tal_arr(ctx, u8, 2); + memset(irbf.input_infos[i]->script, 2, 2); + } + irbf.output_infos = tal_arr(ctx, struct output_info *, 2); + memset(irbf.output_infos, 2, sizeof(struct output_info *)*2); + for (i = 0; i < 2; i++) { + irbf.output_infos[i] = tal(ctx, struct output_info); + memset(irbf.output_infos[i], 2, sizeof(struct output_info)); + irbf.output_infos[i]->script = tal_arr(ctx, u8, 2); + memset(irbf.output_infos[i]->script, 2, 2); + } + + msg = towire_struct_init_rbf(ctx, &irbf); + irbf2 = fromwire_struct_init_rbf(ctx, msg); + assert(init_rbf_eq(&irbf, irbf2)); + test_corruption(&irbf, irbf2, init_rbf); + + memset(&arbf, 2, sizeof(arbf)); + + msg = towire_struct_ack_rbf(ctx, &arbf); + arbf2 = fromwire_struct_ack_rbf(ctx, msg); + assert(ack_rbf_eq(&arbf, arbf2)); + test_corruption(&arbf, arbf2, ack_rbf); + +#endif /* EXPERIMENTAL_FEATURES */ /* No memory leaks please */ secp256k1_context_destroy(secp256k1_ctx); tal_free(ctx); diff --git a/wire/wire.h b/wire/wire.h index a9bc8e89d9d7..7fefb00b75ab 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include From 17b41fa3a61c92d574e5d2b5dec4df35f41ca74e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Sep 2019 14:14:14 -0500 Subject: [PATCH 004/131] df: pipe through whether or not we're using v2 we need a way to tell openingd to use v2 for channel open. --- lightningd/opening_control.c | 14 +++++++++++--- openingd/opening_wire.csv | 1 + openingd/openingd.c | 11 ++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a19b437510ff..a02d9fbfdf93 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -573,7 +573,7 @@ static void opening_funder_failed(struct subd *openingd, const u8 *msg, was_pending(command_success(uc->fc->cancels[i], response)); } - /* Tell any fundchannel_complete or fundchannel command */ + /* Tell any fundchannel_complete command */ if (uc->fc->cmd) was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s", desc)); @@ -1123,7 +1123,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, struct node_id *id; struct peer *peer; struct channel *channel; - bool *announce_channel; + bool *announce_channel, use_v2; u32 *feerate_per_kw; u8 *msg = NULL; @@ -1222,12 +1222,20 @@ static struct command_result *json_fund_channel_start(struct command *cmd, fc->our_upfront_shutdown_script = tal_steal(fc, fc->our_upfront_shutdown_script); +#if EXPERIMENTAL_FEATURES + // FIXME: use features to flag on + use_v2 = true; +#else + use_v2 = false; +#endif + msg = towire_opening_funder_start(NULL, *amount, fc->push, fc->our_upfront_shutdown_script, *feerate_per_kw, - fc->channel_flags); + fc->channel_flags, + use_v2); subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index ef1adb13f501..45fc87730ec1 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -78,6 +78,7 @@ msgdata,opening_funder_start,len_upfront,u16, msgdata,opening_funder_start,upfront_shutdown_script,u8,len_upfront msgdata,opening_funder_start,feerate_per_kw,u32, msgdata,opening_funder_start,channel_flags,u8, +msgdata,opening_funder_start,use_v2,bool, # openingd->master: send back output script for 2-of-2 funding output msgtype,opening_funder_start_reply,6102 diff --git a/openingd/openingd.c b/openingd/openingd.c index b5e69071dc56..37695e9e42d4 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -115,6 +115,11 @@ struct state { bool option_static_remotekey; struct feature_set *our_features; + + /* Things for v2 */ + bool use_v2; + struct amount_sat accepter_funding; + u32 feerate_per_kw_funding; }; static u8 *dev_upfront_shutdown_script(const tal_t *ctx) @@ -504,6 +509,9 @@ static bool setup_channel_funder(struct state *state) return false; } + if (!state->use_v2) + state->accepter_funding = AMOUNT_SAT(0); + return true; } @@ -1418,7 +1426,8 @@ static u8 *handle_master_in(struct state *state) &state->push_msat, &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw, - &channel_flags)) + &channel_flags, + &state->use_v2)) master_badmsg(WIRE_OPENING_FUNDER_START, msg); msg = funder_channel_start(state, channel_flags); From a97541cf0ad2916e2f55afefab58c7fef8601936 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Sep 2019 14:16:32 -0500 Subject: [PATCH 005/131] df: switch from funding -> opener_funding and wire in v2 calls We've now got two amounts we need to keep track of: the opener's funding and the accpeter's. We add a utlity to help keep track of the full funding. Also wires in the calls for open/accept v2 for when we're the opener. --- openingd/openingd.c | 358 +++++++++++++++++++++++++++++++------------- 1 file changed, 256 insertions(+), 102 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 37695e9e42d4..5a03ac2484e1 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -94,7 +94,7 @@ struct state { struct channel_id channel_id; /* Funding and feerate: set by opening peer. */ - struct amount_sat funding; + struct amount_sat opener_funding; struct amount_msat push_msat; u32 feerate_per_kw; struct bitcoin_txid funding_txid; @@ -133,6 +133,18 @@ static u8 *dev_upfront_shutdown_script(const tal_t *ctx) return NULL; } + +static struct amount_sat total_funding(const struct state *state) +{ + struct amount_sat total; + if (!amount_sat_add(&total, state->opener_funding, + state->accepter_funding)) + abort(); + + return total; + +} + /*~ If we can't agree on parameters, we fail to open the channel. If we're * the opener, we need to tell lightningd, otherwise it never really notices. */ static void negotiation_aborted(struct state *state, bool am_opener, @@ -191,8 +203,9 @@ static bool check_config_bounds(struct state *state, const struct channel_config *remoteconf, bool am_opener) { - struct amount_sat capacity; - struct amount_sat reserve; + struct amount_sat capacity, reserve, all_funding; + + all_funding = total_funding(state); /* BOLT #2: * @@ -233,7 +246,7 @@ static bool check_config_bounds(struct state *state, } /* If reserves are larger than total sat, we fail. */ - if (!amount_sat_sub(&capacity, state->funding, reserve)) { + if (!amount_sat_sub(&capacity, all_funding, reserve)) { negotiation_failed(state, am_opener, "channel_reserve_satoshis %s" " and %s too large for funding %s", @@ -242,7 +255,7 @@ static bool check_config_bounds(struct state *state, type_to_string(tmpctx, struct amount_sat, &state->localconf.channel_reserve), type_to_string(tmpctx, struct amount_sat, - &state->funding)); + &all_funding)); return false; } @@ -262,7 +275,7 @@ static bool check_config_bounds(struct state *state, type_to_string(tmpctx, struct amount_msat, &remoteconf->htlc_minimum), type_to_string(tmpctx, struct amount_sat, - &state->funding), + &all_funding), type_to_string(tmpctx, struct amount_sat, &capacity)); return false; @@ -278,7 +291,7 @@ static bool check_config_bounds(struct state *state, " max_htlc_value_in_flight_msat is %s," " channel capacity is %s, which is below %s", type_to_string(tmpctx, struct amount_sat, - &state->funding), + &all_funding), type_to_string(tmpctx, struct amount_sat, &remoteconf->channel_reserve), type_to_string(tmpctx, struct amount_sat, @@ -338,7 +351,7 @@ static bool check_config_bounds(struct state *state, static void set_reserve(struct state *state) { state->localconf.channel_reserve.satoshis /* Raw: rounding. */ - = state->funding.satoshis / 100; /* Raw: rounding. */ + = total_funding(state).satoshis / 100; /* Raw: rounding. */ /* BOLT #2: * @@ -351,6 +364,18 @@ static void set_reserve(struct state *state) state->localconf.channel_reserve)) state->localconf.channel_reserve = state->localconf.dust_limit; + + /* Early return if we're not setting the remote's also (v2) */ + if (!state->use_v2) + return; + + state->remoteconf.channel_reserve.satoshis /* Raw: rounding. */ + = total_funding(state).satoshis / 100; /* Raw: rounding. */ + + if (amount_sat_greater(state->remoteconf.dust_limit, + state->remoteconf.channel_reserve)) + state->remoteconf.channel_reserve + = state->remoteconf.dust_limit; } /* BOLT #2: @@ -473,11 +498,53 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, } } +static bool check_reserves(struct state *state) +{ + /* BOLT #2: + * + * The receiver: + *... + * - if `channel_reserve_satoshis` is less than `dust_limit_satoshis` + * within the `open_channel` message: + * - MUST reject the channel. + * + * - if `channel_reserve_satoshis` from the `open_channel` message is + * less than `dust_limit_satoshis`: + * - MUST reject the channel. + */ + if (amount_sat_greater(state->localconf.dust_limit, + state->remoteconf.channel_reserve)) { + negotiation_failed(state, true, + "channel reserve %s" + " would be below our dust %s", + type_to_string(tmpctx, struct amount_sat, + &state->remoteconf.channel_reserve), + type_to_string(tmpctx, struct amount_sat, + &state->localconf.dust_limit)); + return false; + } + if (amount_sat_greater(state->remoteconf.dust_limit, + state->localconf.channel_reserve)) { + negotiation_failed(state, true, + "dust limit %s" + " would be above our reserve %s", + type_to_string(tmpctx, struct amount_sat, + &state->remoteconf.dust_limit), + type_to_string(tmpctx, struct amount_sat, + &state->localconf.channel_reserve)); + return false; + } + return true; +} + static bool setup_channel_funder(struct state *state) { - /*~ For symmetry, we calculate our own reserve even though lightningd - * could do it for the we-are-funding case. */ - set_reserve(state); + if (!state->use_v2) { + /*~ For symmetry, we calculate our own reserve even though lightningd + * could do it for the we-are-funding case. */ + state->accepter_funding = AMOUNT_SAT(0); + set_reserve(state); + } /*~ Grab a random ID until the funding tx is created (we can't do that * until we know their funding_pubkey) */ @@ -499,19 +566,16 @@ static bool setup_channel_funder(struct state *state) */ if (!feature_negotiated(state->our_features, state->their_features, OPT_LARGE_CHANNELS) - && amount_sat_greater(state->funding, chainparams->max_funding)) { + && amount_sat_greater(state->opener_funding, chainparams->max_funding)) { status_failed(STATUS_FAIL_MASTER_IO, "funding_satoshis must be < %s, not %s", type_to_string(tmpctx, struct amount_sat, &chainparams->max_funding), type_to_string(tmpctx, struct amount_sat, - &state->funding)); + &state->opener_funding)); return false; } - if (!state->use_v2) - state->accepter_funding = AMOUNT_SAT(0); - return true; } @@ -539,83 +603,180 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) if (!state->upfront_shutdown_script[LOCAL]) state->upfront_shutdown_script[LOCAL] = dev_upfront_shutdown_script(state); - msg = towire_open_channel_option_upfront_shutdown_script(NULL, - &chainparams->genesis_blockhash, - &state->channel_id, - state->funding, - state->push_msat, - state->localconf.dust_limit, - state->localconf.max_htlc_value_in_flight, - state->localconf.channel_reserve, - state->localconf.htlc_minimum, - state->feerate_per_kw, - state->localconf.to_self_delay, - state->localconf.max_accepted_htlcs, - &state->our_funding_pubkey, - &state->our_points.revocation, - &state->our_points.payment, - &state->our_points.delayed_payment, - &state->our_points.htlc, - &state->first_per_commitment_point[LOCAL], - channel_flags, - state->upfront_shutdown_script[LOCAL]); + if (state->use_v2) { +#if EXPERIMENTAL_FEATURES + struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); + if (state->upfront_shutdown_script[LOCAL]) { + tlv->option_upfront_shutdown_script = + tal(tlv, struct tlv_opening_tlvs_option_upfront_shutdown_script); + tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = + state->upfront_shutdown_script[LOCAL]; + } + + /* For now, we use the same feerate for funding + commitment tx */ + /* FIXME: allow these to be done separately? */ + state->feerate_per_kw_funding = state->feerate_per_kw; + msg = towire_open_channel2(NULL, + &chainparams->genesis_blockhash, + &state->channel_id, + state->opener_funding, + state->push_msat, + state->localconf.dust_limit, + state->localconf.max_htlc_value_in_flight, + state->localconf.htlc_minimum, + state->feerate_per_kw, + state->feerate_per_kw_funding, + state->localconf.to_self_delay, + state->localconf.max_accepted_htlcs, + &state->our_funding_pubkey, + &state->our_points.revocation, + &state->our_points.payment, + &state->our_points.delayed_payment, + &state->our_points.htlc, + &state->first_per_commitment_point[LOCAL], + channel_flags, + tlv); +#else + peer_failed(state->pps, + &state->channel_id, + "Bad state: signaled v2 channel_open but missing " + "experimental features."); +#endif /* EXPERIMENTAL_FEATURES */ + } else { + /* BOLT #2: + * + * - if both nodes advertised the `option_upfront_shutdown_script` + * feature: + * - MUST include either a valid `shutdown_scriptpubkey` as required + * by `shutdown` `scriptpubkey`, or a zero-length + * `shutdown_scriptpubkey`. + * - otherwise: + * - MAY include a`shutdown_scriptpubkey`. + */ + /* We don't use shutdown_scriptpubkey (at least for now), so leave it + * NULL. */ + msg = towire_open_channel_option_upfront_shutdown_script(NULL, + &chainparams->genesis_blockhash, + &state->channel_id, + state->opener_funding, + state->push_msat, + state->localconf.dust_limit, + state->localconf.max_htlc_value_in_flight, + state->localconf.channel_reserve, + state->localconf.htlc_minimum, + state->feerate_per_kw, + state->localconf.to_self_delay, + state->localconf.max_accepted_htlcs, + &state->our_funding_pubkey, + &state->our_points.revocation, + &state->our_points.payment, + &state->our_points.delayed_payment, + &state->our_points.htlc, + &state->first_per_commitment_point[LOCAL], + channel_flags, + state->upfront_shutdown_script[LOCAL]); + } + sync_crypto_write(state->pps, take(msg)); /* This is usually a very transient state... */ peer_billboard(false, - "Funding channel start: offered, now waiting for accept_channel"); + "Funding channel start: offered, now waiting for accept_channel%s", + state->use_v2 ? "2" : ""); /* ... since their reply should be immediate. */ msg = opening_negotiate_msg(tmpctx, state, true); if (!msg) return NULL; - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - *... - * - `funding_pubkey`, `revocation_basepoint`, `htlc_basepoint`, - * `payment_basepoint`, or `delayed_payment_basepoint` are not - * valid secp256k1 pubkeys in compressed format. - */ - if (feature_negotiated(state->our_features, state->their_features, - OPT_UPFRONT_SHUTDOWN_SCRIPT)) { - if (!fromwire_accept_channel_option_upfront_shutdown_script(state, - msg, &id_in, - &state->remoteconf.dust_limit, - &state->remoteconf.max_htlc_value_in_flight, - &state->remoteconf.channel_reserve, - &state->remoteconf.htlc_minimum, - &state->minimum_depth, - &state->remoteconf.to_self_delay, - &state->remoteconf.max_accepted_htlcs, - &state->their_funding_pubkey, - &state->their_points.revocation, - &state->their_points.payment, - &state->their_points.delayed_payment, - &state->their_points.htlc, - &state->first_per_commitment_point[REMOTE], - &state->upfront_shutdown_script[REMOTE])) + /* Default is no shutdown_scriptpubkey: free any leftover one. */ + state->upfront_shutdown_script[REMOTE] + = tal_free(state->upfront_shutdown_script[REMOTE]); + + if (state->use_v2) { +#if EXPERIMENTAL_FEATURES + struct tlv_accept_tlvs *tlv = tlv_accept_tlvs_new(tmpctx); + if (!fromwire_accept_channel2(msg, &id_in, + &state->accepter_funding, + &state->remoteconf.dust_limit, + &state->remoteconf.max_htlc_value_in_flight, + &state->remoteconf.htlc_minimum, + &state->minimum_depth, + &state->remoteconf.to_self_delay, + &state->remoteconf.max_accepted_htlcs, + &state->their_funding_pubkey, + &state->their_points.revocation, + &state->their_points.payment, + &state->their_points.delayed_payment, + &state->their_points.htlc, + &state->first_per_commitment_point[REMOTE], + tlv)) peer_failed(state->pps, &state->channel_id, - "Parsing accept_channel with option_upfront_shutdown_script %s", tal_hex(msg, msg)); - } else if (!fromwire_accept_channel(msg, &id_in, - &state->remoteconf.dust_limit, - &state->remoteconf.max_htlc_value_in_flight, - &state->remoteconf.channel_reserve, - &state->remoteconf.htlc_minimum, - &state->minimum_depth, - &state->remoteconf.to_self_delay, - &state->remoteconf.max_accepted_htlcs, - &state->their_funding_pubkey, - &state->their_points.revocation, - &state->their_points.payment, - &state->their_points.delayed_payment, - &state->their_points.htlc, - &state->first_per_commitment_point[REMOTE])) + "Parsing accept_channel2 %s", tal_hex(msg, msg)); + + /* This is gross */ + if (tlv->option_upfront_shutdown_script && + tlv->option_upfront_shutdown_script->shutdown_scriptpubkey) + state->upfront_shutdown_script[REMOTE] = tal_steal(state, + tlv->option_upfront_shutdown_script->shutdown_scriptpubkey); + +#else peer_failed(state->pps, &state->channel_id, - "Parsing accept_channel %s", tal_hex(msg, msg)); + "Bad state: signaled v2 channel_accept but missing " + "experimental features. %s", + tal_hex(msg, msg)); +#endif + + } else { + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + *... + * - `funding_pubkey`, `revocation_basepoint`, `htlc_basepoint`, + * `payment_basepoint`, or `delayed_payment_basepoint` are not + * valid DER-encoded compressed secp256k1 pubkeys. + */ + if (feature_negotiated(state->our_features, state->their_features, + OPT_UPFRONT_SHUTDOWN_SCRIPT)) { + if (!fromwire_accept_channel_option_upfront_shutdown_script(state, + msg, &id_in, + &state->remoteconf.dust_limit, + &state->remoteconf.max_htlc_value_in_flight, + &state->remoteconf.channel_reserve, + &state->remoteconf.htlc_minimum, + &state->minimum_depth, + &state->remoteconf.to_self_delay, + &state->remoteconf.max_accepted_htlcs, + &state->their_funding_pubkey, + &state->their_points.revocation, + &state->their_points.payment, + &state->their_points.delayed_payment, + &state->their_points.htlc, + &state->first_per_commitment_point[REMOTE], + &state->upfront_shutdown_script[REMOTE])) + peer_failed(state->pps, + &state->channel_id, + "Parsing accept_channel with option_upfront_shutdown_script %s", tal_hex(msg, msg)); + } else if (!fromwire_accept_channel(msg, &id_in, + &state->remoteconf.dust_limit, + &state->remoteconf.max_htlc_value_in_flight, + &state->remoteconf.channel_reserve, + &state->remoteconf.htlc_minimum, + &state->minimum_depth, + &state->remoteconf.to_self_delay, + &state->remoteconf.max_accepted_htlcs, + &state->their_funding_pubkey, + &state->their_points.revocation, + &state->their_points.payment, + &state->their_points.delayed_payment, + &state->their_points.htlc, + &state->first_per_commitment_point[REMOTE])) + peer_failed(state->pps, + &state->channel_id, + "Parsing accept_channel %s", tal_hex(msg, msg)); + } /* BOLT #2: * @@ -630,17 +791,10 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) type_to_string(msg, struct channel_id, &state->channel_id)); - if (amount_sat_greater(state->remoteconf.dust_limit, - state->localconf.channel_reserve)) { - negotiation_failed(state, true, - "dust limit %s" - " would be above our reserve %s", - type_to_string(tmpctx, struct amount_sat, - &state->remoteconf.dust_limit), - type_to_string(tmpctx, struct amount_sat, - &state->localconf.channel_reserve)); + if (state->use_v2) + set_reserve(state); + else if (!check_reserves(state)) return NULL; - } if (!check_config_bounds(state, &state->remoteconf, true)) return NULL; @@ -686,7 +840,7 @@ static bool funder_finalize_channel_setup(struct state *state, &state->funding_txid, state->funding_txout, state->minimum_depth, - state->funding, + total_funding(state), local_msat, take(new_fee_states(NULL, LOCAL, &state->feerate_per_kw)), @@ -868,13 +1022,13 @@ static u8 *funder_channel_complete(struct state *state) /* We recalculate the local_msat from cached values; should * succeed because we checked it earlier */ - if (!amount_sat_sub_msat(&local_msat, state->funding, state->push_msat)) + if (!amount_sat_sub_msat(&local_msat, state->opener_funding, state->push_msat)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "push_msat %s > funding %s?", type_to_string(tmpctx, struct amount_msat, &state->push_msat), type_to_string(tmpctx, struct amount_sat, - &state->funding)); + &state->opener_funding)); if (!funder_finalize_channel_setup(state, local_msat, &sig, &tx)) return NULL; @@ -925,7 +1079,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) if (!fromwire_open_channel_option_upfront_shutdown_script(state, open_channel_msg, &chain_hash, &state->channel_id, - &state->funding, + &state->opener_funding, &state->push_msat, &state->remoteconf.dust_limit, &state->remoteconf.max_htlc_value_in_flight, @@ -947,7 +1101,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) "Parsing open_channel with option_upfront_shutdown_script %s", tal_hex(tmpctx, open_channel_msg)); } else if (!fromwire_open_channel(open_channel_msg, &chain_hash, &state->channel_id, - &state->funding, + &state->opener_funding, &state->push_msat, &state->remoteconf.dust_limit, &state->remoteconf.max_htlc_value_in_flight, @@ -991,11 +1145,11 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) /* We choose to require *negotiation*, not just support! */ if (!feature_negotiated(state->our_features, state->their_features, OPT_LARGE_CHANNELS) - && amount_sat_greater(state->funding, chainparams->max_funding)) { + && amount_sat_greater(state->opener_funding, chainparams->max_funding)) { negotiation_failed(state, false, "funding_satoshis %s too large", type_to_string(tmpctx, struct amount_sat, - &state->funding)); + &state->opener_funding)); return NULL; } @@ -1005,7 +1159,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) * ... * - `push_msat` is greater than `funding_satoshis` * 1000. */ - if (amount_msat_greater_sat(state->push_msat, state->funding)) { + if (amount_msat_greater_sat(state->push_msat, state->opener_funding)) { peer_failed(state->pps, &state->channel_id, "Their push_msat %s" @@ -1013,7 +1167,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) type_to_string(tmpctx, struct amount_msat, &state->push_msat), type_to_string(tmpctx, struct amount_sat, - &state->funding)); + &state->opener_funding)); return NULL; } @@ -1080,7 +1234,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) /* Check with lightningd that we can accept this? In particular, * if we have an existing channel, we don't support it. */ msg = towire_opening_got_offer(NULL, - state->funding, + state->opener_funding, state->push_msat, state->remoteconf.dust_limit, state->remoteconf.max_htlc_value_in_flight, @@ -1167,7 +1321,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->funding_txid, state->funding_txout, state->minimum_depth, - state->funding, + state->opener_funding, state->push_msat, take(new_fee_states(NULL, REMOTE, &state->feerate_per_kw)), @@ -1293,7 +1447,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &their_funding_pubkey, &state->funding_txid, state->funding_txout, - state->funding, + state->opener_funding, state->push_msat, channel_flags, state->feerate_per_kw, @@ -1422,7 +1576,7 @@ static u8 *handle_master_in(struct state *state) switch (t) { case WIRE_OPENING_FUNDER_START: - if (!fromwire_opening_funder_start(state, msg, &state->funding, + if (!fromwire_opening_funder_start(tmpctx, msg, &state->opener_funding, &state->push_msat, &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw, From 42f05f7bc6f97b569fe7fcefb02570ebbaef18bf Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Sep 2019 14:58:21 -0500 Subject: [PATCH 006/131] df: stash 'is_v2' into fundchannel object so we can refer to it later when doing 'complete' things --- lightningd/opening_control.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a02d9fbfdf93..1ea25d82dd9b 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -96,6 +96,9 @@ struct funding_channel { /* Any commands trying to cancel us. */ struct command **cancels; + + /* Whether or not to use channel open v2 */ + bool is_v2; }; static void uncommitted_channel_disconnect(struct uncommitted_channel *uc, @@ -1123,7 +1126,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, struct node_id *id; struct peer *peer; struct channel *channel; - bool *announce_channel, use_v2; + bool *announce_channel; u32 *feerate_per_kw; u8 *msg = NULL; @@ -1224,9 +1227,9 @@ static struct command_result *json_fund_channel_start(struct command *cmd, #if EXPERIMENTAL_FEATURES // FIXME: use features to flag on - use_v2 = true; + fc->is_v2 = true; #else - use_v2 = false; + fc->is_v2 = false; #endif msg = towire_opening_funder_start(NULL, @@ -1235,7 +1238,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, fc->our_upfront_shutdown_script, *feerate_per_kw, fc->channel_flags, - use_v2); + fc->is_v2); subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); From 2d8e26fb1779807df83eaf263716a908574c81b4 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Sep 2019 14:59:26 -0500 Subject: [PATCH 007/131] df: lookup transaction for the fundchannel_complete for v2 we need to know the inputs/outputs of the transaction so we look them up. there's more problems here that we need to unwind still: figuring out which the funding output is plus how to handle change. --- lightningd/opening_control.c | 26 ++++++++++++++++++++++++-- openingd/opening_wire.csv | 3 ++- openingd/openingd.c | 12 +++++++----- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 1ea25d82dd9b..c9ae6cef8a1b 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1033,6 +1033,7 @@ static struct command_result *json_fund_channel_complete(struct command *cmd, struct channel *channel; u32 *funding_txout_num; u16 funding_txout; + struct bitcoin_tx *tx; if (!param(cmd, buffer, params, p_req("id", param_node_id, &id), @@ -1066,11 +1067,32 @@ static struct command_result *json_fund_channel_complete(struct command *cmd, if (peer->uncommitted_channel->fc->cmd) return command_fail(cmd, LIGHTNINGD, "Channel funding in progress."); + /* We need to know the inputs/outputsfor v2 of fundchannel. + * Ideally, we'd get the PSBT for the tx passed in to fundchannel_complete, + * which would include all of the input/output information. + * Requires txprepare to return the PSBT of the tx, not just the txid + * Until this is patched, we can only do v2 self-funded tx's. + * + * FIXME: use PSBT for fundchannel_complete */ + if (peer->uncommitted_channel->fc->is_v2) { + struct unreleased_tx *utx; + utx = find_unreleased_tx(peer->ld->wallet, funding_txid); + + if (!utx) + return command_fail(cmd, LIGHTNINGD, "Unknown tx %s:%d. " + "Cannot fund a v2 channel with external tx.", + type_to_string(tmpctx, struct bitcoin_txid, funding_txid), + funding_txout); + tx = utx->tx; + } else + tx = NULL; + /* Set the cmd to this new cmd */ peer->uncommitted_channel->fc->cmd = cmd; msg = towire_opening_funder_complete(NULL, - funding_txid, - funding_txout); + funding_txid, funding_txout, + tx); + subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); } diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 45fc87730ec1..cf6f7bb9d135 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -88,10 +88,11 @@ msgdata,opening_funder_start_reply,upfront_shutdown_negotiated,bool, # master->openingd: complete channel establishment for a funding # tx that will be paid for by an external wallet -# response to this is a normal `opening_funder_reply` ?? +# response is `opening_funder_reply` msgtype,opening_funder_complete,6012 msgdata,opening_funder_complete,funding_txid,bitcoin_txid, msgdata,opening_funder_complete,funding_txout,u16, +msgdata,opening_funder_complete,tx,?bitcoin_tx, #master->openingd: cancel channel establishment for a funding msgtype,opening_funder_cancel,6013 diff --git a/openingd/openingd.c b/openingd/openingd.c index 5a03ac2484e1..8d85b4143fe8 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1009,9 +1009,9 @@ static bool funder_finalize_channel_setup(struct state *state, return false; } -static u8 *funder_channel_complete(struct state *state) +static u8 *funder_channel_complete(struct state *state, + struct bitcoin_tx *tx) { - struct bitcoin_tx *tx; struct bitcoin_signature sig; struct amount_msat local_msat; @@ -1572,6 +1572,7 @@ static u8 *handle_master_in(struct state *state) enum opening_wire_type t = fromwire_peektype(msg); u8 channel_flags; struct bitcoin_txid funding_txid; + struct bitcoin_tx *tx; u16 funding_txout; switch (t) { @@ -1590,13 +1591,14 @@ static u8 *handle_master_in(struct state *state) wire_sync_write(REQ_FD, take(msg)); return NULL; case WIRE_OPENING_FUNDER_COMPLETE: - if (!fromwire_opening_funder_complete(msg, + if (!fromwire_opening_funder_complete(tmpctx, msg, &funding_txid, - &funding_txout)) + &funding_txout, + &tx)) master_badmsg(WIRE_OPENING_FUNDER_COMPLETE, msg); state->funding_txid = funding_txid; state->funding_txout = funding_txout; - return funder_channel_complete(state); + return funder_channel_complete(state, tx); case WIRE_OPENING_FUNDER_CANCEL: /* We're aborting this, simple */ if (!fromwire_opening_funder_cancel(msg)) From a77bf7de6cf23cc142a6f6a8cc16881de0f28001 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 16 Sep 2019 19:02:27 -0500 Subject: [PATCH 008/131] hsmd: pull up utxo signing going to need to re-use this later. --- hsmd/hsmd.c | 64 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 39ad012b195e..9f9631023866 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1547,6 +1547,41 @@ static void hsm_key_for_utxo(struct privkey *privkey, struct pubkey *pubkey, } } +static void sign_input(struct bitcoin_tx *tx, struct utxo *in, + struct pubkey *inkey, + struct bitcoin_signature *sig, + int index) +{ + struct privkey inprivkey; + u8 *subscript, *wscript, *script; + + /* Figure out keys to spend this. */ + hsm_key_for_utxo(&inprivkey, inkey, in); + + /* It's either a p2wpkh or p2sh (we support that so people from + * the last bitcoin era can put funds into the wallet) */ + wscript = p2wpkh_scriptcode(tmpctx, inkey); + if (in->is_p2sh) { + /* For P2SH-wrapped Segwit, the (implied) redeemScript + * is defined in BIP141 */ + subscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, inkey); + script = bitcoin_scriptsig_p2sh_p2wpkh(tx, inkey); + bitcoin_tx_input_set_script(tx, index, script); + } else { + /* Pure segwit uses an empty inputScript; NULL has + * tal_count() == 0, so it works great here. */ + subscript = NULL; + bitcoin_tx_input_set_script(tx, index, NULL); + } + /* This is the core crypto magic. */ + sign_tx_input(tx, index, subscript, wscript, &inprivkey, inkey, + SIGHASH_ALL, sig); + + /* The witness is [sig] [key] */ + bitcoin_tx_input_set_witness( + tx, index, take(bitcoin_witness_p2wpkh(tx, sig, inkey))); +} + /* This completes the tx by filling in the input scripts with signatures. */ static void sign_all_inputs(struct bitcoin_tx *tx, struct utxo **utxos) { @@ -1564,36 +1599,9 @@ static void sign_all_inputs(struct bitcoin_tx *tx, struct utxo **utxos) assert(tx->wtx->num_inputs == tal_count(utxos)); for (size_t i = 0; i < tal_count(utxos); i++) { struct pubkey inkey; - struct privkey inprivkey; - const struct utxo *in = utxos[i]; - u8 *subscript, *wscript, *script; struct bitcoin_signature sig; - /* Figure out keys to spend this. */ - hsm_key_for_utxo(&inprivkey, &inkey, in); - - /* It's either a p2wpkh or p2sh (we support that so people from - * the last bitcoin era can put funds into the wallet) */ - wscript = p2wpkh_scriptcode(tmpctx, &inkey); - if (in->is_p2sh) { - /* For P2SH-wrapped Segwit, the (implied) redeemScript - * is defined in BIP141 */ - subscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, &inkey); - script = bitcoin_scriptsig_p2sh_p2wpkh(tx, &inkey); - bitcoin_tx_input_set_script(tx, i, script); - } else { - /* Pure segwit uses an empty inputScript; NULL has - * tal_count() == 0, so it works great here. */ - subscript = NULL; - bitcoin_tx_input_set_script(tx, i, NULL); - } - /* This is the core crypto magic. */ - sign_tx_input(tx, i, subscript, wscript, &inprivkey, &inkey, - SIGHASH_ALL, &sig); - - /* The witness is [sig] [key] */ - bitcoin_tx_input_set_witness( - tx, i, take(bitcoin_witness_p2wpkh(tx, &sig, &inkey))); + sign_input(tx, utxos[i], &inkey, &sig, i); } } From bef72096c67fca9c43999343a2f5bde7e617dbbd Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 16 Sep 2019 19:08:05 -0500 Subject: [PATCH 009/131] withdraw: refactor change output handling We're not using the change_outnum for withdraw tx's (and the way we were calculating it was broken as of the addition of 'multiple outputs'). This removes the change output knowhow from withdraw_tx entirely, and pushes the responsibility up to the caller to include the change output in the output set if desired. Consequently, we also remove the change output knowhow from hsmd. --- bitcoin/tx.c | 10 +++++++ bitcoin/tx.h | 3 +++ common/withdraw_tx.c | 64 ++++++++++++++++++++------------------------ common/withdraw_tx.h | 7 +---- hsmd/hsm_wire.csv | 3 --- hsmd/hsmd.c | 14 +++------- wallet/wallet.h | 2 -- wallet/walletrpc.c | 35 ++++++++++++------------ 8 files changed, 63 insertions(+), 75 deletions(-) diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 6ac439d84e58..a24145a4a9ca 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -14,6 +14,16 @@ #define SEGREGATED_WITNESS_FLAG 0x1 +struct bitcoin_tx_output *new_tx_output(const tal_t *ctx, + struct amount_sat amount, + const u8 *script) +{ + struct bitcoin_tx_output *output = tal(ctx, struct bitcoin_tx_output); + output->amount = amount; + output->script = tal_dup_arr(output, u8, script, tal_count(script), 0); + return output; +} + int bitcoin_tx_add_output(struct bitcoin_tx *tx, const u8 *script, struct amount_sat amount) { diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 29eeb897484f..223a2acd4754 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -50,6 +50,9 @@ struct bitcoin_tx_input { u8 **witness; }; +struct bitcoin_tx_output *new_tx_output(const tal_t *ctx, + struct amount_sat amount, + const u8 *script); /* SHA256^2 the tx: simpler than sha256_tx */ void bitcoin_txid(const struct bitcoin_tx *tx, struct bitcoin_txid *txid); diff --git a/common/withdraw_tx.c b/common/withdraw_tx.c index 1aee140bd288..0de8bb6eb2a9 100644 --- a/common/withdraw_tx.c +++ b/common/withdraw_tx.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,44 +14,37 @@ struct bitcoin_tx *withdraw_tx(const tal_t *ctx, const struct chainparams *chainparams, const struct utxo **utxos, struct bitcoin_tx_output **outputs, - const struct pubkey *changekey, - struct amount_sat change, const struct ext_key *bip32_base, - int *change_outnum, u32 nlocktime) + u32 nlocktime) { struct bitcoin_tx *tx; - int output_count; - - tx = tx_spending_utxos(ctx, chainparams, utxos, bip32_base, - !amount_sat_eq(change, AMOUNT_SAT(0)), - tal_count(outputs), nlocktime, - BITCOIN_TX_DEFAULT_SEQUENCE - 1); - - output_count = bitcoin_tx_add_multi_outputs(tx, outputs); - assert(output_count == tal_count(outputs)); - - if (!amount_sat_eq(change, AMOUNT_SAT(0))) { - /* Add one to the output_count, for the change */ - output_count++; - - const void *map[output_count]; - for (size_t i = 0; i < output_count; i++) - map[i] = int2ptr(i); - - bitcoin_tx_add_output(tx, scriptpubkey_p2wpkh(tmpctx, changekey), - change); - - assert(tx->wtx->num_outputs == output_count); - permute_outputs(tx, NULL, map); - - /* The change is the last output added, so the last position - * in the map */ - if (change_outnum) - *change_outnum = ptr2int(map[output_count - 1]); - - } else if (change_outnum) - *change_outnum = -1; - + struct pubkey key; + u8 *script; + size_t i; + + assert(tal_count(utxos) > 0 && tal_count(outputs) > 0); + + tx = bitcoin_tx(ctx, chainparams, + tal_count(utxos), + tal_count(outputs), + nlocktime); + + /* Add our utxo's */ + for (i = 0; i < tal_count(utxos); i++) { + if (utxos[i]->is_p2sh && bip32_base) { + bip32_pubkey(bip32_base, &key, utxos[i]->keyindex); + script = bitcoin_scriptsig_p2sh_p2wpkh(tmpctx, &key); + } else { + script = NULL; + } + + bitcoin_tx_add_input(tx, &utxos[i]->txid, utxos[i]->outnum, + BITCOIN_TX_DEFAULT_SEQUENCE - 1, + utxos[i]->amount, script); + } + + bitcoin_tx_add_multi_outputs(tx, outputs); + permute_outputs(tx, NULL, (const void **)outputs); permute_inputs(tx, (const void **)utxos); bitcoin_tx_finalize(tx); diff --git a/common/withdraw_tx.h b/common/withdraw_tx.h index 163f1b4757ac..cf5d67af18c6 100644 --- a/common/withdraw_tx.h +++ b/common/withdraw_tx.h @@ -21,19 +21,14 @@ struct utxo; * @chainparams: (in) the params for the created transaction. * @utxos: (in/out) tal_arr of UTXO pointers to spend (permuted to match) * @outputs: (in) tal_arr of bitcoin_tx_output, scriptPubKeys with amount to send to. - * @changekey: (in) key to send change to (only used if change_satoshis != 0). - * @change: (in) amount to send as change. * @bip32_base: (in) bip32 base for key derivation, or NULL. - * @change_outnum: (out) set to output index of change output or -1 if none, unless NULL. * @nlocktime: (in) the value to set as the transaction's nLockTime. */ struct bitcoin_tx *withdraw_tx(const tal_t *ctx, const struct chainparams *chainparams, const struct utxo **utxos, struct bitcoin_tx_output **outputs, - const struct pubkey *changekey, - struct amount_sat change, const struct ext_key *bip32_base, - int *change_outnum, u32 nlocktime); + u32 nlocktime); #endif /* LIGHTNING_COMMON_WITHDRAW_TX_H */ diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index eb1eb96e32ba..55f75f1ed9ca 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -67,9 +67,6 @@ msgdata,hsm_node_announcement_sig_reply,signature,secp256k1_ecdsa_signature, # Sign a withdrawal request msgtype,hsm_sign_withdrawal,7 -msgdata,hsm_sign_withdrawal,satoshi_out,amount_sat, -msgdata,hsm_sign_withdrawal,change_out,amount_sat, -msgdata,hsm_sign_withdrawal,change_keyindex,u32, msgdata,hsm_sign_withdrawal,num_outputs,u16, msgdata,hsm_sign_withdrawal,outputs,bitcoin_tx_output,num_outputs msgdata,hsm_sign_withdrawal,num_inputs,u16, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 9f9631023866..931cee156134 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1653,26 +1653,18 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { - struct amount_sat satoshi_out, change_out; - u32 change_keyindex; struct utxo **utxos; struct bitcoin_tx *tx; - struct pubkey changekey; struct bitcoin_tx_output **outputs; u32 nlocktime; - if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &satoshi_out, - &change_out, &change_keyindex, + if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &outputs, &utxos, &nlocktime)) return bad_req(conn, c, msg_in); - if (!bip32_pubkey(&secretstuff.bip32, &changekey, change_keyindex)) - return bad_req_fmt(conn, c, msg_in, - "Failed to get key %u", change_keyindex); - tx = withdraw_tx(tmpctx, c->chainparams, - cast_const2(const struct utxo **, utxos), outputs, - &changekey, change_out, NULL, NULL, nlocktime); + cast_const2(const struct utxo **, utxos), + outputs, NULL, nlocktime); sign_all_inputs(tx, utxos); diff --git a/wallet/wallet.h b/wallet/wallet.h index 540c26e0edaa..9e90e70073a3 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -66,8 +66,6 @@ struct unreleased_tx { /* The tx itself (unsigned initially) */ struct bitcoin_tx *tx; struct bitcoin_txid txid; - /* Index of change output, or -1 if none. */ - int change_outnum; }; /* Possible states for tracked outputs in the database. Not sure yet diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 6ec384873a58..586e460c5f3c 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -85,9 +85,6 @@ static struct command_result *broadcast_and_wait(struct command *cmd, /* FIXME: hsm will sign almost anything, but it should really * fail cleanly (not abort!) and let us report the error here. */ u8 *msg = towire_hsm_sign_withdrawal(cmd, - utx->wtx->amount, - utx->wtx->change, - utx->wtx->change_key_index, cast_const2(const struct bitcoin_tx_output **, utx->outputs), utx->wtx->utxos, @@ -311,10 +308,8 @@ static struct command_result *json_prepare_tx(struct command *cmd, * Support only one output. */ if (destination) { outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, 1); - outputs[0] = tal(outputs, struct bitcoin_tx_output); - outputs[0]->script = tal_steal(outputs[0], - cast_const(u8 *, destination)); - outputs[0]->amount = (*utx)->wtx->amount; + outputs[0] = new_tx_output(outputs, (*utx)->wtx->amount, + destination); out_len = tal_count(outputs[0]->script); goto create_tx; @@ -356,11 +351,9 @@ static struct command_result *json_prepare_tx(struct command *cmd, "'%.*s' is a invalid satoshi amount", t[2].end - t[2].start, buffer + t[2].start); + outputs[i] = new_tx_output(outputs, *amount, + cast_const(u8 *, destination)); out_len += tal_count(destination); - outputs[i] = tal(outputs, struct bitcoin_tx_output); - outputs[i]->amount = *amount; - outputs[i]->script = tal_steal(outputs[i], - cast_const(u8 *, destination)); /* In fact, the maximum amount of bitcoin satoshi is 2.1e15. * It can't be equal to/bigger than 2^64. @@ -386,8 +379,6 @@ static struct command_result *json_prepare_tx(struct command *cmd, } create_tx: - (*utx)->outputs = tal_steal(*utx, outputs); - if (chosen_utxos) result = wtx_from_utxos((*utx)->wtx, *feerate_per_kw, out_len, maxheight, @@ -404,19 +395,27 @@ static struct command_result *json_prepare_tx(struct command *cmd, if ((*utx)->wtx->all_funds) outputs[0]->amount = (*utx)->wtx->amount; + /* Add the change as the last output */ if (!amount_sat_eq((*utx)->wtx->change, AMOUNT_SAT(0))) { + struct bitcoin_tx_output *change_output; + changekey = tal(tmpctx, struct pubkey); if (!bip32_pubkey(cmd->ld->wallet->bip32_base, changekey, (*utx)->wtx->change_key_index)) return command_fail(cmd, LIGHTNINGD, "Keys generation failure"); - } else - changekey = NULL; + + change_output = new_tx_output(outputs, (*utx)->wtx->change, + scriptpubkey_p2wpkh(tmpctx, changekey)); + tal_arr_expand(outputs, *change_output); + } + + (*utx)->outputs = tal_steal(*utx, outputs); (*utx)->tx = withdraw_tx(*utx, chainparams, - (*utx)->wtx->utxos, (*utx)->outputs, - changekey, (*utx)->wtx->change, + (*utx)->wtx->utxos, + (*utx)->outputs, cmd->ld->wallet->bip32_base, - &(*utx)->change_outnum, locktime); + bitcoin_txid((*utx)->tx, &(*utx)->txid); return NULL; From db3f615524f9625c655c76f65568b74b2b998588 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 16 Sep 2019 19:34:03 -0500 Subject: [PATCH 010/131] withdraw: add ability to have additional inputs on a tx Make it such that we can include other inputs on a transaction, sort them, and sign the ones we need. We're going to need this for dual-funded transactions. --- bitcoin/tx.h | 5 ++- common/withdraw_tx.c | 14 +++++-- common/withdraw_tx.h | 6 ++- hsmd/hsm_wire.csv | 6 ++- hsmd/hsmd.c | 77 ++++++++++++++++++++++++++++++++-- tools/generate-wire.py | 1 + tools/headerversions.tmp.28501 | 0 wallet/wallet.h | 2 + wallet/walletrpc.c | 10 ++++- wire/fromwire.c | 31 +++++++++++++- wire/towire.c | 19 +++++++++ wire/wire.h | 3 ++ 12 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 tools/headerversions.tmp.28501 diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 223a2acd4754..c8f2b6da2807 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -46,8 +46,11 @@ struct bitcoin_tx_input { u8 *script; u32 sequence_number; - /* Only if BIP141 used. */ + /* If BIP141 used, or is external input */ u8 **witness; + + /* Needed for external inputs */ + struct amount_sat amount; }; struct bitcoin_tx_output *new_tx_output(const tal_t *ctx, diff --git a/common/withdraw_tx.c b/common/withdraw_tx.c index 0de8bb6eb2a9..19c61a1103d0 100644 --- a/common/withdraw_tx.c +++ b/common/withdraw_tx.c @@ -13,9 +13,11 @@ struct bitcoin_tx *withdraw_tx(const tal_t *ctx, const struct chainparams *chainparams, const struct utxo **utxos, + struct bitcoin_tx_input **inputs, struct bitcoin_tx_output **outputs, const struct ext_key *bip32_base, - u32 nlocktime) + u32 nlocktime, + const void **input_map) { struct bitcoin_tx *tx; struct pubkey key; @@ -43,12 +45,18 @@ struct bitcoin_tx *withdraw_tx(const tal_t *ctx, utxos[i]->amount, script); } + /* Add 3rd party inputs */ + for (i = 0; i < tal_count(inputs); i++) { + bitcoin_tx_add_input(tx, &inputs[i]->txid, + inputs[i]->index, inputs[i]->sequence_number, + inputs[i]->amount, inputs[i]->script); + } + bitcoin_tx_add_multi_outputs(tx, outputs); permute_outputs(tx, NULL, (const void **)outputs); - permute_inputs(tx, (const void **)utxos); + permute_inputs(tx, input_map); bitcoin_tx_finalize(tx); - assert(bitcoin_tx_check(tx)); return tx; } diff --git a/common/withdraw_tx.h b/common/withdraw_tx.h index cf5d67af18c6..3bdeff0f4bb6 100644 --- a/common/withdraw_tx.h +++ b/common/withdraw_tx.h @@ -20,15 +20,19 @@ struct utxo; * @ctx: context to tal from. * @chainparams: (in) the params for the created transaction. * @utxos: (in/out) tal_arr of UTXO pointers to spend (permuted to match) + * @inputs: (in) tal_arr of inputs for this transaction, in addition to utxos. * @outputs: (in) tal_arr of bitcoin_tx_output, scriptPubKeys with amount to send to. * @bip32_base: (in) bip32 base for key derivation, or NULL. * @nlocktime: (in) the value to set as the transaction's nLockTime. + * @input_map: (out) index of sorted inputs */ struct bitcoin_tx *withdraw_tx(const tal_t *ctx, const struct chainparams *chainparams, const struct utxo **utxos, + struct bitcoin_tx_input **inputs, struct bitcoin_tx_output **outputs, const struct ext_key *bip32_base, - u32 nlocktime); + u32 nlocktime, + const void **input_map); #endif /* LIGHTNING_COMMON_WITHDRAW_TX_H */ diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index 55f75f1ed9ca..9f1a3fc5dda0 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -67,10 +67,12 @@ msgdata,hsm_node_announcement_sig_reply,signature,secp256k1_ecdsa_signature, # Sign a withdrawal request msgtype,hsm_sign_withdrawal,7 +msgdata,hsm_sign_withdrawal,num_inputs,u16, +msgdata,hsm_sign_withdrawal,inputs,bitcoin_tx_input,num_inputs msgdata,hsm_sign_withdrawal,num_outputs,u16, msgdata,hsm_sign_withdrawal,outputs,bitcoin_tx_output,num_outputs -msgdata,hsm_sign_withdrawal,num_inputs,u16, -msgdata,hsm_sign_withdrawal,inputs,utxo,num_inputs +msgdata,hsm_sign_withdrawal,num_utxos,u16, +msgdata,hsm_sign_withdrawal,utxos,utxo,num_utxos msgdata,hsm_sign_withdrawal,nlocktime,u32, msgtype,hsm_sign_withdrawal_reply,107 diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 931cee156134..bf3f95e57897 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1605,6 +1605,42 @@ static void sign_all_inputs(struct bitcoin_tx *tx, struct utxo **utxos) } } +/* For dual-funded transactions, we don't sign every input. Instead, + * we find the inputs that correspond with the utxos we have and sign + * only those + * */ +static void sign_our_inputs(struct bitcoin_tx *tx, struct utxo **utxos, + const void **map, size_t map_len) +{ + size_t i, j; + int input_index; + + assert(tx->wtx->num_inputs >= tal_count(utxos)); + assert(tal_count(utxos) <= map_len); + + /* We add utxos to the tx first, and then any other + * inputs. Thus, we can iterate through the map from zero upward + * to find the correct utxo placement to sign */ + for (i = 0; i < tal_count(utxos); i++) { + struct pubkey inkey; + struct bitcoin_signature sig; + + input_index = -1; + for (j = 0; j < map_len; j++) { + if (ptr2int(map[j]) == i) { + input_index = j; + break; + } + } + + if (input_index < 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find index for input %zu", i); + + sign_input(tx, utxos[i], &inkey, &sig, input_index); + } +} + /*~ lightningd asks us to sign the transaction to fund a channel; it feeds us * the set of inputs and the local and remote pubkeys, and we sign it. */ static struct io_plan *handle_sign_funding_tx(struct io_conn *conn, @@ -1655,18 +1691,53 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, { struct utxo **utxos; struct bitcoin_tx *tx; + struct bitcoin_tx_input **inputs; struct bitcoin_tx_output **outputs; u32 nlocktime; + size_t input_count, i, j; + if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, - &outputs, &utxos, &nlocktime)) + &inputs, &outputs, + &utxos, &nlocktime)) return bad_req(conn, c, msg_in); + input_count = tal_count(utxos) + tal_count(inputs); + const void *map[input_count]; + for (i = 0; i < input_count; i++) + map[i] = int2ptr(i); + tx = withdraw_tx(tmpctx, c->chainparams, cast_const2(const struct utxo **, utxos), - outputs, NULL, nlocktime); + inputs, outputs, NULL, + nlocktime, + (const void **)&map); + + /* Put our signatures on the transaction */ + sign_our_inputs(tx, utxos, (const void **)&map, input_count); + + /* Add any 3rd party signatures */ + for (i = 0; i < tal_count(inputs); i++) { + if (inputs[i]->witness) { + size_t offset = tal_count(utxos) + i; + int input_index = -1; + + /* Find the index */ + for (j = 0; j < input_count; j++) { + if (ptr2int(map[j]) == offset) { + input_index = j; + break; + } + } + + if (input_index < 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find index for input %zu", i); - sign_all_inputs(tx, utxos); + bitcoin_tx_input_set_witness(tx, input_index, + inputs[i]->witness); + } + } return req_reply(conn, c, take(towire_hsm_sign_withdrawal_reply(NULL, tx))); diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 1e2552dbade4..808d8c8c281b 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -229,6 +229,7 @@ class Type(FieldSet): 'feature_set', 'onionmsg_path', 'route_hop', + 'bitcoin_tx_input', ] # Some BOLT types are re-typed based on their field name diff --git a/tools/headerversions.tmp.28501 b/tools/headerversions.tmp.28501 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/wallet/wallet.h b/wallet/wallet.h index 9e90e70073a3..6fbd57287b3c 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -63,6 +63,8 @@ struct unreleased_tx { struct wallet_tx *wtx; /* Outputs(scriptpubkey and satoshi) this pays to. */ struct bitcoin_tx_output **outputs; + /* Non-utxo inputs for this tx (i.e. not our wallet) */ + struct bitcoin_tx_input **inputs; /* The tx itself (unsigned initially) */ struct bitcoin_tx *tx; struct bitcoin_txid txid; diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 586e460c5f3c..cb5a41a17a8a 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -82,9 +82,15 @@ static struct command_result *broadcast_and_wait(struct command *cmd, struct bitcoin_tx *signed_tx; struct bitcoin_txid signed_txid; + /* Build input set */ + if (!utx->inputs) + utx->inputs = tal_arr(utx, struct bitcoin_tx_input *, 0); + /* FIXME: hsm will sign almost anything, but it should really * fail cleanly (not abort!) and let us report the error here. */ u8 *msg = towire_hsm_sign_withdrawal(cmd, + cast_const2(const struct bitcoin_tx_input **, + utx->inputs), cast_const2(const struct bitcoin_tx_output **, utx->outputs), utx->wtx->utxos, @@ -412,9 +418,11 @@ static struct command_result *json_prepare_tx(struct command *cmd, (*utx)->outputs = tal_steal(*utx, outputs); (*utx)->tx = withdraw_tx(*utx, chainparams, (*utx)->wtx->utxos, + (*utx)->inputs, (*utx)->outputs, cmd->ld->wallet->bip32_base, - locktime); + locktime, + NULL); bitcoin_txid((*utx)->tx, &(*utx)->txid); diff --git a/wire/fromwire.c b/wire/fromwire.c index e18075749a01..56f91e4b8e9c 100644 --- a/wire/fromwire.c +++ b/wire/fromwire.c @@ -403,9 +403,11 @@ void fromwire_bip32_key_version(const u8** cursor, size_t *max, struct bitcoin_tx_output *fromwire_bitcoin_tx_output(const tal_t *ctx, const u8 **cursor, size_t *max) { + u16 script_len; + struct bitcoin_tx_output *output = tal(ctx, struct bitcoin_tx_output); output->amount = fromwire_amount_sat(cursor, max); - u16 script_len = fromwire_u16(cursor, max); + script_len = fromwire_u16(cursor, max); output->script = fromwire_tal_arrn(output, cursor, max, script_len); if (!*cursor) return tal_free(output); @@ -429,3 +431,30 @@ void fromwire_chainparams(const u8 **cursor, size_t *max, fromwire_bitcoin_blkid(cursor, max, &genesis); *chainparams = chainparams_by_chainhash(&genesis); } + +struct bitcoin_tx_input *fromwire_bitcoin_tx_input(const tal_t *ctx, + const u8 **cursor, size_t *max) +{ + u16 script_len; + u16 witness_count; + u16 witness_len; + + struct bitcoin_tx_input *input = tal(ctx, struct bitcoin_tx_input); + + fromwire_bitcoin_txid(cursor, max, &input->txid); + input->index = fromwire_u32(cursor, max); + script_len = fromwire_u16(cursor, max); + input->script = script_len ? tal_arr(input, u8, script_len) : NULL; + fromwire_u8_array(cursor, max, input->script, script_len); + input->sequence_number = fromwire_u32(cursor, max); + + witness_count = fromwire_u16(cursor, max); + input->witness = witness_count ? tal_arr(input, u8 *, witness_count) : NULL; + for (size_t i = 0; i < witness_count; i++) { + witness_len = fromwire_u16(cursor, max); + input->witness[i] = witness_len ? tal_arr(input->witness, u8, witness_len) : NULL; + fromwire_u8_array(cursor, max, input->witness[i], witness_len); + } + input->amount = fromwire_amount_sat(cursor, max); + return input; +} diff --git a/wire/towire.c b/wire/towire.c index a35073c78b60..3b85bff8bed5 100644 --- a/wire/towire.c +++ b/wire/towire.c @@ -273,3 +273,22 @@ void towire_chainparams(u8 **cursor, const struct chainparams *chainparams) { towire_bitcoin_blkid(cursor, &chainparams->genesis_blockhash); } + +void towire_bitcoin_tx_input(u8 **pptr, const struct bitcoin_tx_input *input) +{ + u16 script_len = tal_count(input->script); + u16 witness_len; + + towire_bitcoin_txid(pptr, &input->txid); + towire_u32(pptr, input->index); + towire_u16(pptr, script_len); + towire_u8_array(pptr, input->script, script_len); + towire_u32(pptr, input->sequence_number); + towire_u16(pptr, tal_count(input->witness)); + for (size_t i = 0; i < tal_count(input->witness); i++) { + witness_len = tal_count(input->witness[i]); + towire_u16(pptr, witness_len); + towire_u8_array(pptr, input->witness[i], witness_len); + } + towire_amount_sat(pptr, input->amount); +} diff --git a/wire/wire.h b/wire/wire.h index 7fefb00b75ab..583ebb99baed 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -168,4 +168,7 @@ fromwire_onionmsg_path(const tal_t *ctx, const u8 **cursor, size_t *plen) return NULL; } #endif /* EXPERIMENTAL_FEATURES */ +void towire_bitcoin_tx_input(u8 **pptr, const struct bitcoin_tx_input *input); +struct bitcoin_tx_input *fromwire_bitcoin_tx_input(const tal_t *ctx, + const u8 **cursor, size_t *max); #endif /* LIGHTNING_WIRE_WIRE_H */ From fce1520e8ef848f707664e087aee7cd71becf446 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 17 Sep 2019 15:46:58 -0500 Subject: [PATCH 011/131] walletrpc: break out output extraction code pull up output parser into reusable method --- wallet/walletrpc.c | 82 ++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index cb5a41a17a8a..5e70397e6a98 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -126,6 +126,47 @@ static struct command_result *broadcast_and_wait(struct command *cmd, return command_still_pending(cmd); } +/* Extract an output. Format: {destination: amount} */ +static struct command_result *extract_output(const tal_t *ctx, + struct command *cmd, + const char *buffer, + const jsmntok_t *t, + struct bitcoin_tx_output **output) +{ + + struct amount_sat *amount; + const u8 *destination; + enum address_parse_result res; + + if (t->type != JSMN_OBJECT) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "The output format must be " + "{destination: amount}");; + + res = json_to_address_scriptpubkey(cmd, + chainparams, + buffer, &t[1], + &destination); + + if (res == ADDRESS_PARSE_UNRECOGNIZED) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Could not parse destination address"); + else if (res == ADDRESS_PARSE_WRONG_NETWORK) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Destination address is not on network %s", + chainparams->network_name); + + amount = tal(tmpctx, struct amount_sat); + if (!json_to_sat_or_all(buffer, &t[2], amount)) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "'%.*s' is a invalid satoshi amount", + t[2].end - t[2].start, buffer + t[2].start); + + *output = new_tx_output(ctx, *amount, destination); + return NULL; +} + + /* Common code for withdraw and txprepare. * * Returns NULL on success, and fills in wtx, output and @@ -329,44 +370,21 @@ static struct command_result *json_prepare_tx(struct command *cmd, (*utx)->wtx->all_funds = false; (*utx)->wtx->amount = AMOUNT_SAT(0); json_for_each_arr(i, t, outputstok) { - struct amount_sat *amount; - const u8 *destination; - enum address_parse_result res; + struct bitcoin_tx_output *output; - /* output format: {destination: amount} */ - if (t->type != JSMN_OBJECT) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "The output format must be " - "{destination: amount}"); - - res = json_to_address_scriptpubkey(cmd, - chainparams, - buffer, &t[1], - &destination); - if (res == ADDRESS_PARSE_UNRECOGNIZED) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Could not parse destination address"); - else if (res == ADDRESS_PARSE_WRONG_NETWORK) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "Destination address is not on network %s", - chainparams->network_name); - - amount = tal(tmpctx, struct amount_sat); - if (!json_to_sat_or_all(buffer, &t[2], amount)) - return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "'%.*s' is a invalid satoshi amount", - t[2].end - t[2].start, buffer + t[2].start); + result = extract_output(outputs, cmd, buffer, t, &output); + if (result) + return result; - outputs[i] = new_tx_output(outputs, *amount, - cast_const(u8 *, destination)); - out_len += tal_count(destination); + outputs[i] = output; + out_len += tal_count(output->script); /* In fact, the maximum amount of bitcoin satoshi is 2.1e15. * It can't be equal to/bigger than 2^64. * On the hand, the maximum amount of litoshi is 8.4e15, * which also can't overflow. */ /* This means this destination need "all" satoshi we have. */ - if (amount_sat_eq(*amount, AMOUNT_SAT(-1ULL))) { + if (amount_sat_eq(output->amount, AMOUNT_SAT(-1ULL))) { if (outputstok->size > 1) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "outputs[%zi]: this destination wants" @@ -374,11 +392,11 @@ static struct command_result *json_prepare_tx(struct command *cmd, " can't be more than 1. ", i); (*utx)->wtx->all_funds = true; /* `AMOUNT_SAT(-1ULL)` is the max permissible for `wallet_select_all`. */ - (*utx)->wtx->amount = *amount; + (*utx)->wtx->amount = output->amount; break; } - if (!amount_sat_add(&(*utx)->wtx->amount, (*utx)->wtx->amount, *amount)) + if (!amount_sat_add(&(*utx)->wtx->amount, (*utx)->wtx->amount, output->amount)) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "outputs: The sum of first %zi outputs" " overflow. ", i); From e550f6a57a064c13e6e3fcd94642fba05ef98d4e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:05:47 -0500 Subject: [PATCH 012/131] funding: add method for building a dual-funded tx Function and helpers for making a dual funded funding tx --- common/funding_tx.c | 271 +++++++++++ common/funding_tx.h | 35 ++ common/test/run-funding_tx_dual.c | 769 ++++++++++++++++++++++++++++++ 3 files changed, 1075 insertions(+) create mode 100644 common/test/run-funding_tx_dual.c diff --git a/common/funding_tx.c b/common/funding_tx.c index f75cbd9d25f5..6a773fe48629 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -3,8 +3,11 @@ #include #include #include +#include #include +#include #include +#include #include #ifndef SUPERVERBOSE @@ -54,3 +57,271 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, assert(bitcoin_tx_check(tx)); return tx; } + +#if EXPERIMENTAL_FEATURES +/* We leave out the change addresses if there's no change left after fees */ +static size_t calculate_input_weights(struct input_info **inputs, + struct amount_sat *total) +{ + u32 input_weight; + u64 scriptlen; + size_t weight = 0, i = 0; + + *total = AMOUNT_SAT(0); + for (i = 0; i < tal_count(inputs); i++) { + /* prev_out hash + index + sequence */ + input_weight = (32 + 4 + 4) * 4; + + if (inputs[i]->script) { + scriptlen = tal_bytelen(inputs[i]->script); + input_weight += (scriptlen + varint_size(scriptlen)) * 4; + } else { + /* 00 byte script_sig len */ + input_weight += 1 * 4; + } + + input_weight += inputs[i]->max_witness_len; + weight += input_weight; + + assert(amount_sat_add(total, *total, inputs[i]->input_satoshis)); + } + + return weight; +} + +static size_t calculate_output_weights(struct output_info **outputs) +{ + size_t i, output_weights = 0, scriptlen; + + for (i = 0; i < tal_count(outputs); i++) { + scriptlen = tal_bytelen(outputs[i]->script); + /* amount field + script + scriptlen varint */ + output_weights += (8 + scriptlen + varint_size(scriptlen)) * 4; + } + + return output_weights; +} + +static size_t calculate_weight(struct input_info **opener_inputs, + struct input_info **accepter_inputs, + struct output_info **opener_outputs, + struct output_info **accepter_outputs, + struct amount_sat *opener_total, + struct amount_sat *accepter_total) + +{ + size_t weight; + + /* version, input count, output count, locktime */ + weight = (4 + 1 + 1 + 4) * 4; + + /* add segwit fields: marker + flag */ + weight += 1 + 1; + + weight += calculate_input_weights(opener_inputs, opener_total); + weight += calculate_input_weights(accepter_inputs, accepter_total); + + /* channel funding output: amount, len, scriptpubkey */ + weight += (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WSH_LEN) * 4; + + weight += calculate_output_weights(opener_outputs); + weight += calculate_output_weights(accepter_outputs); + + return weight; +} + +static const struct output_info *find_change_output(struct output_info **outputs) +{ + size_t i = 0; + for (i = 0; i < tal_count(outputs); i++) { + if (amount_sat_eq(outputs[i]->output_satoshis, AMOUNT_SAT(0))) + return outputs[i]; + } + return NULL; +} + +static struct amount_sat calculate_output_value(struct output_info **outputs) +{ + size_t i = 0; + struct amount_sat total = AMOUNT_SAT(0); + + for (i = 0; i < tal_count(outputs); i++) { + assert(amount_sat_add(&total, total, outputs[i]->output_satoshis)); + } + return total; +} + +static void add_inputs(struct bitcoin_tx *tx, struct input_info **inputs) +{ + size_t i = 0; + for (i = 0; i < tal_count(inputs); i++) { + bitcoin_tx_add_input(tx, &inputs[i]->prevtx_txid, inputs[i]->prevtx_vout, + BITCOIN_TX_DEFAULT_SEQUENCE, + inputs[i]->input_satoshis, inputs[i]->script); + } +} + +static void add_outputs(struct bitcoin_tx *tx, struct output_info **outputs, + const struct amount_sat *change) +{ + size_t i = 0; + u8 *script; + struct amount_sat value; + + for (i = 0; i < tal_count(outputs); i++) { + /* Is this the change output?? */ + if (change && amount_sat_eq(outputs[i]->output_satoshis, AMOUNT_SAT(0))) { + /* If there's no change amount, we leave it out */ + if (amount_sat_eq(*change, AMOUNT_SAT(0))) + continue; + value = *change; + } else + value = outputs[i]->output_satoshis; + + script = tal_dup_arr(tx, u8, outputs[i]->script, + tal_count(outputs[i]->script), 0); + bitcoin_tx_add_output(tx, script, value); + } +} + +struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, + const struct chainparams *chainparams, + u16 *outnum, + u32 feerate_kw_funding, + struct amount_sat *opener_funding, + struct amount_sat accepter_funding, + struct input_info **opener_inputs, + struct input_info **accepter_inputs, + struct output_info **opener_outputs, + struct output_info **accepter_outputs, + const struct pubkey *local_fundingkey, + const struct pubkey *remote_fundingkey, + struct amount_sat *total_funding, + const void **input_map) +{ + size_t weight; + struct amount_sat funding_tx_fee, opener_total_sat, + accepter_total_sat, + opener_change, output_val; + struct bitcoin_tx *tx; + const struct output_info *change_output; + + size_t i = 0; + u64 scriptlen; + u32 input_count, output_count; + u8 *wscript; + + /* First, we calculate the weight of the transaction, with change outputs */ + weight = calculate_weight(opener_inputs, accepter_inputs, + opener_outputs, accepter_outputs, + &opener_total_sat, &accepter_total_sat); + funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); + + if (!amount_sat_sub(&opener_change, opener_total_sat, *opener_funding)) + return NULL; + + /* Check that the remaining amount at least covers the other + * indicated output values. We have to cover these other + * outputs, as they might be other funding transaction outputs. The + * only 'flexible' / change output that's removable etc is indicated + * by a zero value. */ + output_val = calculate_output_value(opener_outputs); + if (!amount_sat_sub(&opener_change, opener_change, output_val)) + return NULL; + + change_output = find_change_output(opener_outputs); + if (amount_sat_sub(&opener_change, opener_change, funding_tx_fee) && + amount_sat_greater(opener_change, chainparams->dust_limit)) { + if (!change_output) { + /* If there's no change output, we put the remainder into + * the funding output. TODO: add to spec */ + assert(amount_sat_add(opener_funding, + *opener_funding, opener_change)); + opener_change = AMOUNT_SAT(0); + } + + goto build_tx; + } + + /* Try removing opener's change output to fit fees */ + if (change_output) { + scriptlen = tal_count(change_output->script); + weight -= (8 + scriptlen + varint_size(scriptlen)) * 4; + funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); + + /* Any left over gets added to the funding output */ + if (amount_sat_sub(&opener_change, opener_change, funding_tx_fee)) { + assert(amount_sat_add(opener_funding, *opener_funding, opener_change)); + opener_change = AMOUNT_SAT(0); + goto build_tx; + } + } + + if (!amount_sat_sub(opener_funding, opener_total_sat, funding_tx_fee) || + !amount_sat_sub(opener_funding, *opener_funding, output_val)) + return NULL; + + opener_change = AMOUNT_SAT(0); + +build_tx: + input_count = tal_count(opener_inputs) + tal_count(accepter_inputs); + /* opener + accepter outputs plus the funding output */ + output_count = tal_count(opener_outputs) + + tal_count(accepter_outputs) + 1; + + /* If they had supplied a change output, but we removed it because + * remove it from the count */ + if (change_output && amount_sat_eq(AMOUNT_SAT(0), opener_change)) { + output_count -= 1; + assert(output_count > 0); + } + + tx = bitcoin_tx(ctx, chainparams, input_count, output_count, 0); + + /* Add the funding output */ + wscript = bitcoin_redeem_2of2(tx, local_fundingkey, remote_fundingkey); + SUPERVERBOSE("# funding witness script = %s\n", + tal_hex(wscript, wscript)); + + *total_funding = *opener_funding; + assert(amount_sat_add(total_funding, *total_funding, accepter_funding)); + + /* Last check, make sure our funding output is greater than + * the dust limit */ + if (!amount_sat_greater(*total_funding, chainparams->dust_limit)) + return NULL; + + + const void *o_map[output_count]; + for (i = 0; i < output_count; i++) + o_map[i] = int2ptr(i); + + bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tx, wscript), *total_funding); + + /* Add the other outputs */ + add_outputs(tx, opener_outputs, &opener_change); + add_outputs(tx, accepter_outputs, NULL); + + /* Note that hsmd depends on the opener's inputs + * being added before the accepter's inputs */ + add_inputs(tx, opener_inputs); + add_inputs(tx, accepter_inputs); + + /* Sort inputs */ + permute_inputs(tx, input_map); + + /* Sort outputs */ + permute_outputs(tx, NULL, o_map); + + for (i = 0; i < output_count; i++) { + if (o_map[i] == int2ptr(0)) { + if (outnum) + *outnum = i; + break; + } + } + + assert(bitcoin_tx_check(tx)); + return tx; +} +#endif /* EXPERIMENTAL_FEATURES */ diff --git a/common/funding_tx.h b/common/funding_tx.h index 577a4cafb2ee..899e1987abe9 100644 --- a/common/funding_tx.h +++ b/common/funding_tx.h @@ -5,6 +5,7 @@ #include #include #include +#include struct bitcoin_tx; struct ext_key; @@ -44,4 +45,38 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, struct amount_sat change, const struct pubkey *changekey, const struct ext_key *bip32_base); + +#if EXPERIMENTAL_FEATURES +/** + * funding_tx: create a P2WSH funding transaction for a channel. + * @ctx: context to tal from. + * @chainparams: (in) the params for the resulting transaction. + * @outnum: (out) txout which is the funding output. + * @feerate_kw_funding: (in) feerate for the funding transaction + * @total_funding: (out) total funding amount for this transaction + * @opener_funding: (in/out) funding amount contributed by opener + * @accepter_funding: (in) funding amount contributed by accepter + * @opener_inputs: (in) inputs from the opener + * @accepter_inputs: (in) inputs from the accepter + * @opener_outputs: (in) outputs for the opener + * @accepter_outputs: (in) outputs for the accepter + * @local_fundingkey: (in) local key for 2of2 funding output. + * @remote_fundingkey: (in) remote key for 2of2 funding output. + * @input_map: (out) ordering of inputs, after being sorted. + */ +struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, + const struct chainparams *chainparams, + u16 *outnum, + u32 feerate_kw_funding, + struct amount_sat *opener_funding, + struct amount_sat accepter_funding, + struct input_info **opener_inputs, + struct input_info **accepter_inputs, + struct output_info **opener_outputs, + struct output_info **accepter_outputs, + const struct pubkey *local_fundingkey, + const struct pubkey *remote_fundingkey, + struct amount_sat *total_funding, + const void **input_map); +#endif /* EXPERIMENTAL_FEATURES */ #endif /* LIGHTNING_COMMON_FUNDING_TX_H */ diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c new file mode 100644 index 000000000000..24cdb70f68be --- /dev/null +++ b/common/test/run-funding_tx_dual.c @@ -0,0 +1,769 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../amount.c" +#define SUPERVERBOSE printf +#include "../funding_tx.c" +#undef SUPERVERBOSE +#include "../key_derive.c" +#include "../type_to_string.c" +#include "../permute_tx.c" +#include "../utxo.c" + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for fromwire_amount_sat */ +struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } +/* Generated stub for fromwire_bitcoin_txid */ +void fromwire_bitcoin_txid(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + struct bitcoin_txid *txid UNNEEDED) +{ fprintf(stderr, "fromwire_bitcoin_txid called!\n"); abort(); } +/* Generated stub for fromwire_bool */ +bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bool called!\n"); abort(); } +/* Generated stub for fromwire_fail */ +const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_node_id */ +void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for fromwire_pubkey */ +void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_u32 */ +u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for fromwire_u64 */ +u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for towire_amount_sat */ +void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) +{ fprintf(stderr, "towire_amount_sat called!\n"); abort(); } +/* Generated stub for towire_bitcoin_txid */ +void towire_bitcoin_txid(u8 **pptr UNNEEDED, const struct bitcoin_txid *txid UNNEEDED) +{ fprintf(stderr, "towire_bitcoin_txid called!\n"); abort(); } +/* Generated stub for towire_bool */ +void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) +{ fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_node_id */ +void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "towire_node_id called!\n"); abort(); } +/* Generated stub for towire_pubkey */ +void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "towire_pubkey called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } +/* Generated stub for towire_u64 */ +void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +struct test_case { + struct input_info **opener_inputs; + struct input_info **accepter_inputs; + struct output_info **opener_outputs; + struct output_info **accepter_outputs; + struct amount_sat opener_funding; + struct amount_sat accepter_funding; + struct amount_sat expected_funding; + struct bitcoin_tx *expected_tx; + char *local_pubkey_str; + char *remote_pubkey_str; + u32 feerate; +}; + +#if EXPERIMENTAL_FEATURES +static u8 *hex_to_u8(const tal_t *ctx, char *str) +{ + return tal_hexdata(ctx, str, strlen(str)); +} + +/* Test case from the 03 Appendix F, in the RFC */ +/* FIXME: add bolt reference for this */ +static struct test_case test1(const tal_t *ctx) +{ + struct bitcoin_txid txid; + bitcoin_txid_from_hex("4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9", + strlen("4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9"), + &txid); + + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 2); + struct input_info *input_one = tal(ctx, struct input_info); + input_one->input_satoshis = AMOUNT_SAT(250000000); + input_one->prevtx_txid = txid; + input_one->prevtx_vout = 0; + input_one->prevtx_scriptpubkey = hex_to_u8(ctx, "220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946"); + input_one->max_witness_len = 75; + input_one->script = NULL; + opener_inputs[0] = input_one; + + struct input_info *input_two = tal(ctx, struct input_info); + input_two->input_satoshis = AMOUNT_SAT(250000000); + input_two->prevtx_txid = txid; + input_two->prevtx_vout = 1; + input_two->prevtx_scriptpubkey = hex_to_u8(ctx, "a9146a235d064786b49e7043e4a042d4cc429f7eb69487"); + input_two->max_witness_len = 75; + input_two->script = hex_to_u8(ctx, "220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946"); + opener_inputs[1] = input_two; + + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 2); + struct input_info *input_three = tal(ctx, struct input_info); + input_three->input_satoshis = AMOUNT_SAT(250000000); + input_three->prevtx_txid = txid; + input_three->prevtx_vout = 2; + input_three->prevtx_scriptpubkey = hex_to_u8(ctx, "160014fbb4db9d85fba5e301f4399e3038928e44e37d32"); + input_three->max_witness_len = 109; + input_three->script = NULL; + accepter_inputs[0] = input_three; + + struct input_info *input_four = tal(ctx, struct input_info); + input_four->input_satoshis = AMOUNT_SAT(250000000); + input_four->prevtx_txid = txid; + input_four->prevtx_vout = 3; + input_four->prevtx_scriptpubkey = hex_to_u8(ctx, "a9147ecd1b519326bc13b0ec716e469b58ed02b112a087"); + input_four->max_witness_len = 109; + input_four->script = hex_to_u8(ctx, "160014fbb4db9d85fba5e301f4399e3038928e44e37d32"); + accepter_inputs[1] = input_four; + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); + struct output_info *output_one = tal(ctx, struct output_info); + output_one->output_satoshis = AMOUNT_SAT(0); + output_one->script = hex_to_u8(ctx, "00141ca1cca8855bad6bc1ea5436edd8cff10b7e448b"); + opener_outputs[0] = output_one; + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + struct output_info *output_two = tal(ctx, struct output_info); + output_two->output_satoshis = AMOUNT_SAT(200000000); + output_two->script = hex_to_u8(ctx, "001444cb0c39f93ecc372b5851725bd29d865d333b10"); + accepter_outputs[0] = output_two; + + char *expected_tx_str = "0200000004b932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430000000000ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430100000023220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430200000000ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430300000017160014fbb4db9d85fba5e301f4399e3038928e44e37d32ffffffff03ea7f0100000000001600141ca1cca8855bad6bc1ea5436edd8cff10b7e448b00c2eb0b0000000016001444cb0c39f93ecc372b5851725bd29d865d333b106081ad2f00000000220020297b92c238163e820b82486084634b4846b86a3c658d87b9384192e6bea98ec500000000"; + struct test_case test1 = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(499900000), + .accepter_funding = AMOUNT_SAT(300000000), + .expected_funding = AMOUNT_SAT(799900000), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "02e16172a41e928cbd78f761bd1c657c4afc7495a1244f7f30166b654fbf7661e3", + .local_pubkey_str = "0292edb5f7bbf9e900f7e024be1c1339c6d149c11930e613af3a983d2565f4e41e", + }; + + assert(test1.expected_tx); + + return test1; +} + +/* The following inputs are build off of two prior transactions, depending + * on how many inputs there are from the 'accepter' side */ +const char* txid_str_one = "6c39988c96f100fbd1cc4ba47f73e3410922a9b41db07e80530a47fb71da053f"; +const char* txid_str_two = "07f983eea2be59f6aada611475df69c11f5f95aac5a04ff769effbf24ae9e951"; + +static struct input_info *input_one(const tal_t *ctx, int vout, const char* txid_str) +{ + struct bitcoin_txid txid; + bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); + struct input_info *input_one = tal(ctx, struct input_info); + input_one->input_satoshis = AMOUNT_SAT(500000); + input_one->prevtx_txid = txid; + input_one->prevtx_vout = vout; + input_one->prevtx_scriptpubkey = hex_to_u8(ctx, "0014ca5cc81df579bd589a428c0d29dceb81513fce8d"); + input_one->max_witness_len = 109; + input_one->script = NULL; + return input_one; +} + +static struct input_info *input_two(const tal_t *ctx, const char *txid_str) +{ + struct bitcoin_txid txid; + bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); + + struct input_info *input_two = tal(ctx, struct input_info); + input_two->input_satoshis = AMOUNT_SAT(1000000); + input_two->prevtx_txid = txid; + input_two->prevtx_vout = 0; + input_two->prevtx_scriptpubkey = hex_to_u8(ctx, "001483440596268132e6c99d44dae2d151dabd9a2b23"); + input_two->max_witness_len = 109; + input_two->script = NULL; + return input_two; +} + +static struct input_info *input_three(const tal_t *ctx, int vout, const char *txid_str) +{ + struct bitcoin_txid txid; + bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); + + struct input_info *input = tal(ctx, struct input_info); + input->input_satoshis = AMOUNT_SAT(1500000); + input->prevtx_txid = txid; + input->prevtx_vout = vout; + input->prevtx_scriptpubkey = hex_to_u8(ctx, "0014d1f40e954d7a792284b6fb19a2e0bf777441d83e"); + input->max_witness_len = 109; + input->script = NULL; + return input; +} + +/* Input four only exists on the 'second' transaction */ +static struct input_info *input_four(const tal_t *ctx) +{ + struct bitcoin_txid txid; + bitcoin_txid_from_hex(txid_str_two, strlen(txid_str_two), &txid); + + struct input_info *input = tal(ctx, struct input_info); + input->input_satoshis = AMOUNT_SAT(2000000); + input->prevtx_txid = txid; + input->prevtx_vout = 1; + input->prevtx_scriptpubkey = hex_to_u8(ctx, "0014fd9658fbd476d318f3b825b152b152aafa49bc92"); + input->max_witness_len = 109; + input->script = NULL; + return input; +} + +static struct output_info *output_one(const tal_t *ctx, u64 amount) +{ + struct output_info *output_one = tal(ctx, struct output_info); + output_one->output_satoshis = (struct amount_sat){ amount }; + output_one->script = hex_to_u8(ctx, "00140f0963bc774334ebc14d11ce940c35cfa6986415"); + return output_one; +} + +static struct output_info *output_two(const tal_t *ctx, u64 amount) +{ + struct output_info *output = tal(ctx, struct output_info); + output->output_satoshis = (struct amount_sat){ amount }; + output->script = hex_to_u8(ctx, "0014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5"); + return output; +} + +static struct output_info *output_three(const tal_t *ctx, u64 amount) +{ + struct output_info *output = tal(ctx, struct output_info); + output->output_satoshis = (struct amount_sat){ amount }; + output->script = hex_to_u8(ctx, "0014d295f76da2319791f36df5759e45b15d5e105221"); + return output; +} + +/* Check that change filled in correctly */ +static struct test_case test2(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); + opener_outputs[0] = output_one(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 253, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(490000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1480000), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* No change passed in, but output is exactly correct */ +static struct test_case test3(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); + opener_outputs[0] = output_one(ctx, 9745); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 253, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(490000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1480000), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* No change passed in, output is a little too big, funding impacted */ +static struct test_case test_no_change(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); + opener_outputs[0] = output_one(ctx, 5000); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5d8a4160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(493000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1483992.0), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* With change */ +static struct test_case test_change(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + opener_outputs[0] = output_one(ctx, 5000); + opener_outputs[1] = output_three(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff046403000000000000160014d295f76da2319791f36df5759e45b15d5e10522188130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5f8a0160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(493000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1483000), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* With change trimmed, funding decreases */ +static struct test_case test_change_trimmed(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + opener_outputs[0] = output_one(ctx, 5000); + opener_outputs[1] = output_three(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d56881160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 10000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(493000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1474920.0), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + + +/* With change trimmed, funding increases */ +static struct test_case test_change_trimmed_positive(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + opener_outputs[0] = output_one(ctx, 5000); + opener_outputs[1] = output_three(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + accepter_outputs[0] = output_two(ctx, 10000); + + + // fee = 1310 + // change = 0 + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5aaa3160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1300, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(493000), + .accepter_funding = AMOUNT_SAT(990000), + .expected_funding = AMOUNT_SAT(1483690.0), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* Funding is less than dust_limit */ +static struct test_case test_less_than_dust(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 0); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + opener_outputs[0] = output_one(ctx, 499000); + opener_outputs[1] = output_three(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + struct test_case test = { + .feerate = 1300, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(1000), + .accepter_funding = AMOUNT_SAT(0), + .expected_funding = AMOUNT_SAT(206), + .expected_tx = NULL, + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + return test; +} + +/* Funding is less than dust_limit, with accepter inputs */ +static struct test_case test_less_than_dust_with_accepter(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + accepter_inputs[0] = input_two(ctx, txid_str_one); + + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + opener_outputs[0] = output_one(ctx, 499000); + opener_outputs[1] = output_three(ctx, 0); + + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + struct test_case test = { + .feerate = 1300, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(1000), + .accepter_funding = AMOUNT_SAT(1000000), + .expected_funding = AMOUNT_SAT(1000206), + .expected_tx = NULL, + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + return test; +} + +/* Opener one input, no outputs */ +static struct test_case test_one_input(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 0); + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 0); + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + + char *expected_tx_str = "02000000013f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff01399f070000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(100000), + .accepter_funding = AMOUNT_SAT(0), + .expected_funding = AMOUNT_SAT(499513), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* Opener two inputs, no outputs */ +static struct test_case test_two_input(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 2); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 0); + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 0); + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + opener_inputs[1] = input_three(ctx, 2, txid_str_one); + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0200000000ffffffff0188811e0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(100000), + .accepter_funding = AMOUNT_SAT(0), + .expected_funding = AMOUNT_SAT(1999240), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* Full input/output set */ +static struct test_case test_full_set(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 2); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 2); + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); + + opener_inputs[0] = input_one(ctx, 2, txid_str_two); + opener_inputs[1] = input_three(ctx, 3, txid_str_two); + + accepter_inputs[0] = input_two(ctx, txid_str_two); + accepter_inputs[1] = input_four(ctx); + + opener_outputs[0] = output_one(ctx, 5000); + opener_outputs[1] = output_three(ctx, 0); + + accepter_outputs[0] = output_two(ctx, 10000); + + char *expected_tx_str = "020000000451e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070000000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070100000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070200000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070300000000ffffffff0488130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5cae31c0000000000160014d295f76da2319791f36df5759e45b15d5e10522150262f0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(100000), + .accepter_funding = AMOUNT_SAT(2990000), + .expected_funding = AMOUNT_SAT(3090000), + .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + assert(test.expected_tx); + + return test; +} + +/* More funding requested than has inputs for */ +static struct test_case test_more_than_input(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 0); + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 0); + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(600000), + .accepter_funding = AMOUNT_SAT(0), + .expected_funding = AMOUNT_SAT(499513), + .expected_tx = NULL, + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + return test; +} + +/* More funding requested (funding + outputs) than has inputs for */ +static struct test_case test_culmulative_more_than_input(const tal_t *ctx) +{ + struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); + struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 0); + struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); + struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 0); + + opener_inputs[0] = input_one(ctx, 1, txid_str_one); + + opener_outputs[0] = output_one(ctx, 100000); + + struct test_case test = { + .feerate = 1000, + .opener_inputs = opener_inputs, + .accepter_inputs = accepter_inputs, + .opener_outputs = opener_outputs, + .accepter_outputs = accepter_outputs, + .opener_funding = AMOUNT_SAT(500000), + .accepter_funding = AMOUNT_SAT(0), + .expected_funding = AMOUNT_SAT(499513), + .expected_tx = NULL, + .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", + .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + }; + + return test; +} + + +#define num_tests 14 +static struct test_case (*test_cases[num_tests])(const tal_t *ctx) = { + test1, test2, test3, test_no_change, test_change, test_change_trimmed, + test_change_trimmed_positive, test_less_than_dust, test_one_input, + test_two_input, test_full_set, test_less_than_dust_with_accepter, + test_more_than_input, test_culmulative_more_than_input, +}; + +static bool bitcoin_tx_eq(const struct bitcoin_tx *tx1, + const struct bitcoin_tx *tx2) +{ + u8 *lin1, *lin2; + bool eq; + lin1 = linearize_tx(NULL, tx1); + lin2 = linearize_tx(lin1, tx2); + eq = memeq(lin1, tal_count(lin1), lin2, tal_count(lin2)); + tal_free(lin1); + return eq; +} + +int main(void) +{ + setup_locale(); + + struct bitcoin_tx *funding; + + struct pubkey local_funding_pubkey, remote_funding_pubkey; + + secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY + | SECP256K1_CONTEXT_SIGN); + setup_tmpctx(); + + chainparams = chainparams_for_network("bitcoin"); + + u16 outnum; + struct amount_sat total_funding; + + for (size_t i = 0; i < num_tests; i++) { + struct test_case test = test_cases[i](tmpctx); + + assert(amount_sat_add(&total_funding, test.opener_funding, test.accepter_funding)); + + if (!pubkey_from_hexstr(test.local_pubkey_str, strlen(test.local_pubkey_str), + &local_funding_pubkey)) + abort(); + if (!pubkey_from_hexstr(test.remote_pubkey_str, strlen(test.remote_pubkey_str), + &remote_funding_pubkey)) + abort(); + + /* Note that dust_limit is set to 546, via chainparams */ + funding = dual_funding_funding_tx(tmpctx, chainparams, + &outnum, test.feerate, + &test.opener_funding, + test.accepter_funding, + test.opener_inputs, + test.accepter_inputs, + test.opener_outputs, + test.accepter_outputs, + &local_funding_pubkey, + &remote_funding_pubkey, + &total_funding, NULL); + + if (!test.expected_tx && !funding) + continue; + + if (!test.expected_tx ^ !funding) + abort(); + + assert(amount_sat_eq(total_funding, test.expected_funding)); + assert(bitcoin_tx_eq(funding, test.expected_tx)); + } + + /* No memory leaks please */ + secp256k1_context_destroy(secp256k1_ctx); + tal_free(tmpctx); + + return 0; +} +#else +int main(void) +{ + return 0; +} +#endif /* EXPERIMENTAL_FEATURES */ From c8d4aa1800aae3428602f09e7468a83c4d40fe75 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:20:44 -0500 Subject: [PATCH 013/131] opening: update wallet_commit_channel for df Update some assumtions of wallet_commit_channel to better take the dual-funded reality into account --- lightningd/opening_control.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index c9ae6cef8a1b..d0d718f2025f 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -167,8 +167,10 @@ wallet_commit_channel(struct lightningd *ld, struct bitcoin_signature *remote_commit_sig, const struct bitcoin_txid *funding_txid, u16 funding_outnum, - struct amount_sat funding, + struct amount_sat total_funding, + struct amount_sat local_funding, struct amount_msat push, + enum side opener, u8 channel_flags, struct channel_info *channel_info, u32 feerate, @@ -187,17 +189,28 @@ wallet_commit_channel(struct lightningd *ld, return NULL; } - if (uc->fc) { - if (!amount_sat_sub_msat(&our_msat, funding, push)) { + if (opener == LOCAL) { + if (!amount_sat_sub_msat(&our_msat, local_funding, push)) { log_broken(uc->log, "push %s exceeds funding %s", type_to_string(tmpctx, struct amount_msat, &push), type_to_string(tmpctx, struct amount_sat, - &funding)); + &local_funding)); return NULL; } - } else - our_msat = push; + } else { + if (!amount_msat_add_sat(&our_msat, push, local_funding)) { + log_broken(uc->log, "push %s exceeds funding %s", + type_to_string(tmpctx, struct amount_msat, + &push), + type_to_string(tmpctx, struct amount_sat, + &local_funding)); + return NULL; + } + } + + /* Check that we're still in bounds */ + assert(amount_msat_less_eq_sat(our_msat, total_funding)); channel_info->fee_states = new_fee_states(uc, uc->fc ? LOCAL : REMOTE, &feerate); @@ -230,7 +243,7 @@ wallet_commit_channel(struct lightningd *ld, channel = new_channel(uc->peer, uc->dbid, NULL, /* No shachain yet */ CHANNELD_AWAITING_LOCKIN, - uc->fc ? LOCAL : REMOTE, + opener, uc->log, take(uc->transient_billboard), channel_flags, @@ -239,7 +252,7 @@ wallet_commit_channel(struct lightningd *ld, 1, 1, 0, funding_txid, funding_outnum, - funding, + total_funding, push, false, /* !remote_funding_locked */ NULL, /* no scid yet */ @@ -415,7 +428,9 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, &funding_txid, funding_txout, fc->funding, + fc->funding, fc->push, + LOCAL, fc->channel_flags, &channel_info, feerate, @@ -514,7 +529,9 @@ static void opening_fundee_finished(struct subd *openingd, &funding_txid, funding_outnum, funding, + AMOUNT_SAT(0), push, + REMOTE, channel_flags, &channel_info, feerate, From e1d6dedc758983604b54e228c6f1c2b7138a907a Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:23:17 -0500 Subject: [PATCH 014/131] funding: pass utxos through to openingd we're going to need them to construct the funding tx --- lightningd/opening_control.c | 12 +++++++++--- openingd/opening_wire.csv | 3 +++ openingd/openingd.c | 7 +++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index d0d718f2025f..54420203bccb 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -99,6 +99,7 @@ struct funding_channel { /* Whether or not to use channel open v2 */ bool is_v2; + struct unreleased_tx *utx; }; static void uncommitted_channel_disconnect(struct uncommitted_channel *uc, @@ -925,7 +926,6 @@ static unsigned int openingd_msg(struct subd *openingd, } opening_funder_failed(openingd, msg, uc); return 0; - case WIRE_OPENING_FUNDEE: if (tal_count(fds) != 3) return 3; @@ -1051,6 +1051,7 @@ static struct command_result *json_fund_channel_complete(struct command *cmd, u32 *funding_txout_num; u16 funding_txout; struct bitcoin_tx *tx; + const struct utxo **utxos; if (!param(cmd, buffer, params, p_req("id", param_node_id, &id), @@ -1101,14 +1102,19 @@ static struct command_result *json_fund_channel_complete(struct command *cmd, type_to_string(tmpctx, struct bitcoin_txid, funding_txid), funding_txout); tx = utx->tx; - } else + utxos = utx->wtx->utxos; + peer->uncommitted_channel->fc->utx = utx; + } else { tx = NULL; + utxos = tal_arr(tmpctx, const struct utxo *, 0); + peer->uncommitted_channel->fc->utx = NULL; + } /* Set the cmd to this new cmd */ peer->uncommitted_channel->fc->cmd = cmd; msg = towire_opening_funder_complete(NULL, funding_txid, funding_txout, - tx); + utxos, tx); subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index cf6f7bb9d135..e6bf031c121d 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -92,6 +92,9 @@ msgdata,opening_funder_start_reply,upfront_shutdown_negotiated,bool, msgtype,opening_funder_complete,6012 msgdata,opening_funder_complete,funding_txid,bitcoin_txid, msgdata,opening_funder_complete,funding_txout,u16, +msgdata,opening_funder_complete,num_ins,u16, +#include +msgdata,opening_funder_complete,utxos,utxo,num_ins msgdata,opening_funder_complete,tx,?bitcoin_tx, #master->openingd: cancel channel establishment for a funding diff --git a/openingd/openingd.c b/openingd/openingd.c index 8d85b4143fe8..5a45a768288d 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1010,7 +1010,8 @@ static bool funder_finalize_channel_setup(struct state *state, } static u8 *funder_channel_complete(struct state *state, - struct bitcoin_tx *tx) + struct bitcoin_tx *tx, + struct utxo **utxos) { struct bitcoin_signature sig; struct amount_msat local_msat; @@ -1573,6 +1574,7 @@ static u8 *handle_master_in(struct state *state) u8 channel_flags; struct bitcoin_txid funding_txid; struct bitcoin_tx *tx; + struct utxo **utxos; u16 funding_txout; switch (t) { @@ -1594,11 +1596,12 @@ static u8 *handle_master_in(struct state *state) if (!fromwire_opening_funder_complete(tmpctx, msg, &funding_txid, &funding_txout, + &utxos, &tx)) master_badmsg(WIRE_OPENING_FUNDER_COMPLETE, msg); state->funding_txid = funding_txid; state->funding_txout = funding_txout; - return funder_channel_complete(state, tx); + return funder_channel_complete(state, tx, utxos); case WIRE_OPENING_FUNDER_CANCEL: /* We're aborting this, simple */ if (!fromwire_opening_funder_cancel(msg)) From f6ed18f3189d71339f835a933c054eadb49f447b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:24:31 -0500 Subject: [PATCH 015/131] dual-funding: wire up opener side of dual funding Dual funding means that both the opener (us) and the accepter (the remote peer) have the opportunity to add funds to the funding transaction. This patch implements the protocol set required for the second half of dual-funding; from fundchannel_complete onward. --- lightningd/opening_control.c | 217 +++++++++++++++ openingd/channel_establishment.h | 16 ++ openingd/opening_wire.csv | 26 ++ openingd/openingd.c | 457 +++++++++++++++++++++++++++++++ 4 files changed, 716 insertions(+) create mode 100644 openingd/channel_establishment.h diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 54420203bccb..0051cd3c0098 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -372,6 +372,212 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp, tal_free(fc->uc); } +#if EXPERIMENTAL_FEATURES +static bool update_unreleased_tx(struct unreleased_tx *utx, + struct bitcoin_tx *tx, + u32 *input_map, + struct witness_stack **witnesses) +{ + size_t i, j, num_other_ins, num_utxo; + + num_utxo = tal_count(utx->wtx->utxos); + num_other_ins = tx->wtx->num_inputs - num_utxo; + assert(num_other_ins == tal_count(witnesses)); + + utx->inputs = tal_free(utx->inputs); + utx->inputs = tal_arr(utx, struct bitcoin_tx_input *, num_other_ins); + for (i = 0; i < num_other_ins; i++) { + struct wally_tx_input wi; + struct bitcoin_tx_input *in; + size_t index = -1; + + in = tal(utx->inputs, struct bitcoin_tx_input); + /* The input map is 'inverted', in that the + * original index is the value, the index is its + * current index. We know the original + * and need to find the current, so we iterate + * until we find the original -- its index is + * the current `index` */ + for (j = 0; j < tx->wtx->num_inputs; j++) { + if (input_map[j] == i + num_utxo) { + index = j; + break; + } + } + + if (index == -1) + return false; + + wi = tx->wtx->inputs[index]; + + bitcoin_tx_input_get_txid(tx, index, &in->txid); + in->index = wi.index; + in->sequence_number = wi.sequence; + + /* Amount is unknown here */ + in->amount = AMOUNT_SAT(0); + + /* Copy over input's scriptpubkey */ + if (wi.script_len) { + in->script = tal_arr(in, u8, wi.script_len); + memcpy(in->script, wi.script, wi.script_len); + } else + in->script = NULL; + + in->witness = tal_arr(in, u8 *, + tal_count(witnesses[i]->witness_element)); + for (j = 0; j < tal_count(witnesses[i]->witness_element); j++) { + in->witness[j] = + tal_dup_arr(in->witness, + u8, + witnesses[i]->witness_element[j]->witness, + tal_count(witnesses[i]->witness_element[j]->witness), + 0); + } + + utx->inputs[i] = in; + } + + utx->outputs = tal_free(utx->outputs); + utx->outputs = tal_arr(utx, struct bitcoin_tx_output *, tx->wtx->num_outputs); + for (i = 0; i < tx->wtx->num_outputs; i++) { + struct wally_tx_output out; + struct amount_sat amount; + u8 *script; + + out = tx->wtx->outputs[i]; + + amount.satoshis = out.satoshi; /* Raw: type conversion */ + + /* Copy over output's script */ + script = tal_arr(utx->outputs, u8, out.script_len); + memcpy(script, out.script, out.script_len); + + utx->outputs[i] = new_tx_output(utx->outputs, + amount, script); + } + + /* Update transaction fields on utx */ + utx->tx = tal_free(utx->tx); + utx->tx = tal_steal(utx, tx); + bitcoin_txid(tx, &utx->txid); + + return true; +} +#endif /* EXPERIMENTAL_FEATURES */ + +static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, + const int *fds, + struct uncommitted_channel *uc) +{ +#if EXPERIMENTAL_FEATURES + struct channel_info channel_info; + struct bitcoin_txid funding_txid; + u16 funding_txout; + struct bitcoin_signature remote_commit_sig; + struct bitcoin_tx *remote_commit, *funding_tx; + u32 feerate, feerate_funding; + struct amount_sat local_funding, total_funding; + struct channel *channel; + struct lightningd *ld = openingd->ld; + u8 *remote_upfront_shutdown_script; + struct per_peer_state *pps; + struct bitcoin_tx_input **remote_ins; + struct funding_channel *fc = uc->fc; + struct unreleased_tx *utx = fc->utx; + u32 *input_map; + struct witness_stack **witnesses = NULL; + + /* This is a new channel_info.their_config so set its ID to 0 */ + channel_info.their_config.id = 0; + + if (!fromwire_opening_dual_funding_signed(resp, resp, + &pps, + &remote_commit, + &remote_commit_sig, + &funding_tx, + &funding_txout, + &remote_ins, + &input_map, + &local_funding, + &channel_info.their_config, + &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, + &feerate, + &feerate_funding, + &uc->our_config.channel_reserve, + &remote_upfront_shutdown_script)) { + log_broken(fc->uc->log, + "bad OPENING_DUAL_FUNDING_SIGNED %s", + tal_hex(resp, resp)); + was_pending(command_fail(fc->cmd, LIGHTNINGD, + "bad OPENING_DUAL_FUNDING_SIGNED %s", + tal_hex(fc->cmd, resp))); + goto cleanup; + } + + // FIXME: remove chainparams? + remote_commit->chainparams = chainparams; + per_peer_state_set_fds_arr(pps, fds); + + /* openingd should never accept their funding channel in this case. */ + if (peer_active_channel(uc->peer)) { + log_broken(uc->log, "openingd accepted peer funding channel"); + uncommitted_channel_disconnect(uc, LOG_BROKEN, "already have active channel"); + goto cleanup; + } + + /* Update the funding tx that we have for this */ + if (!update_unreleased_tx(utx, funding_tx, input_map, witnesses)) { + log_broken(uc->log, "Unable to update unreleased tx"); + uncommitted_channel_disconnect(uc, LOG_BROKEN, "internal error in creating updated tx"); + goto cleanup; + } + + + /* Pull out the funding amount */ + total_funding.satoshis /* Raw: type conversion */ + = utx->tx->wtx->outputs[funding_txout].satoshi; /* Raw: type conversion */ + bitcoin_txid(funding_tx, &funding_txid); + + /* Consumes uc */ + channel = wallet_commit_channel(ld, uc, + remote_commit, + &remote_commit_sig, + &funding_txid, + funding_txout, + total_funding, + local_funding, + fc->push, + LOCAL, + fc->channel_flags, + &channel_info, + feerate, + fc->our_upfront_shutdown_script, + remote_upfront_shutdown_script); + + /* Watch for funding confirms */ + channel_watch_funding(ld, channel); + + /* Needed for the success statement */ + derive_channel_id(&fc->cid, &channel->funding_txid, funding_txout); + + funding_success(channel); + peer_start_channeld(channel, pps, NULL, false); + +cleanup: + subd_release_channel(openingd, uc); + uc->openingd = NULL; + tal_free(uc); +#else + fatal("Requires EXPERIMENTAL_FEATURES"); +#endif /* EXPERIMENTAL_FEATURES */ +} + static void opening_funder_finished(struct subd *openingd, const u8 *resp, const int *fds, struct funding_channel *fc) @@ -908,6 +1114,17 @@ static unsigned int openingd_msg(struct subd *openingd, return 3; opening_funder_finished(openingd, msg, fds, uc->fc); return 0; + case WIRE_OPENING_DUAL_FUNDING_SIGNED: + if (!uc->fc) { + log_broken(openingd->log, "Unexpected DUAL_FUNDING_SIGNED %s", + tal_hex(tmpctx, msg)); + tal_free(openingd); + return 0; + } + if (tal_count(fds) != 3) + return 3; + opening_opener_sigs_received(openingd, msg, fds, uc); + return 0; case WIRE_OPENING_FUNDER_START_REPLY: if (!uc->fc) { log_broken(openingd->log, "Unexpected FUNDER_START_REPLY %s", diff --git a/openingd/channel_establishment.h b/openingd/channel_establishment.h new file mode 100644 index 000000000000..71bc0cb42ee3 --- /dev/null +++ b/openingd/channel_establishment.h @@ -0,0 +1,16 @@ +#ifndef LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H +#define LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H +#include + +#define REMOTE_CONTRIB_LIMIT 4 + +/* Designator for flagging what role a peer + * is playing in channel establishment (v2) + */ +enum role { + OPENER, + ACCEPTER, + NUM_ROLES +}; + +#endif /* LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H */ diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index e6bf031c121d..4bae99e4ae01 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -132,6 +132,32 @@ msgdata,opening_fundee,local_shutdown_scriptpubkey,u8,local_shutdown_len msgdata,opening_fundee,remote_shutdown_len,u16, msgdata,opening_fundee,remote_shutdown_scriptpubkey,u8,remote_shutdown_len +# openingd->master: accepter's signatures etc +# for a dual-funded channel open +msgtype,opening_dual_funding_signed,6204 +msgdata,opening_dual_funding_signed,pps,per_peer_state, +msgdata,opening_dual_funding_signed,first_commit,bitcoin_tx, +msgdata,opening_dual_funding_signed,first_commit_sig,bitcoin_signature, +msgdata,opening_dual_funding_signed,funding_tx,bitcoin_tx, +msgdata,opening_dual_funding_signed,funding_tx_out,u16, +msgdata,opening_dual_funding_signed,num_witnesses,u16, +msgdata,opening_dual_funding_signed,remote_witnesses,bitcoin_tx_input,num_witnesses +msgdata,opening_dual_funding_signed,num_inputs,u32, +msgdata,opening_dual_funding_signed,input_map,u32,num_inputs +msgdata,opening_dual_funding_signed,local_funding,amount_sat, +msgdata,opening_dual_funding_signed,their_config,channel_config, +msgdata,opening_dual_funding_signed,revocation_basepoint,pubkey, +msgdata,opening_dual_funding_signed,payment_basepoint,pubkey, +msgdata,opening_dual_funding_signed,htlc_basepoint,pubkey, +msgdata,opening_dual_funding_signed,delayed_payment_basepoint,pubkey, +msgdata,opening_dual_funding_signed,their_per_commit_point,pubkey, +msgdata,opening_dual_funding_signed,remote_fundingkey,pubkey, +msgdata,opening_dual_funding_signed,feerate_per_kw,u32, +msgdata,opening_dual_funding_signed,feerate_per_kw_funding,u32, +msgdata,opening_dual_funding_signed,local_reserve,amount_sat, +msgdata,opening_dual_funding_signed,shutdown_len,u16, +msgdata,opening_dual_funding_signed,shutdown_scriptpubkey,u8,shutdown_len + # master -> openingd: do you have a memleak? msgtype,opening_dev_memleak,6033 diff --git a/openingd/openingd.c b/openingd/openingd.c index 5a45a768288d..675c9d2807dc 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -818,6 +820,457 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) OPT_UPFRONT_SHUTDOWN_SCRIPT)); } +#if EXPERIMENTAL_FEATURES +static void check_channel_id(struct state *state, + struct channel_id *id_in, + struct channel_id *original_channel_id) +{ + /* BOLT #2: + * + * The `temporary_channel_id` MUST be the same as the + * `temporary_channel_id` in the `open_channel` message. + */ + if (!channel_id_eq(id_in, original_channel_id)) + peer_failed(state->pps, id_in, + "channel establishment: ids don't match: expected %s got %s", + type_to_string(tmpctx, struct channel_id, original_channel_id), + type_to_string(tmpctx, struct channel_id, id_in)); +} + +/* Derives the needed inputs / outputs from a bitcoin tx */ +static void derive_input_output_info(const tal_t *ctx, + struct bitcoin_tx *tx, + struct utxo **utxos, + bool exclude_funding_output, + struct input_info ***inputs, + struct output_info ***outputs) +{ + size_t i; + + *inputs = tal_arr(ctx, struct input_info *, tal_count(utxos)); + for (i = 0; i < tal_count(utxos); i++) { + struct input_info *in; + in = tal(*inputs, struct input_info); + + in->input_satoshis = utxos[i]->amount; + in->prevtx_txid = utxos[i]->txid; + in->prevtx_vout = utxos[i]->outnum; + in->prevtx_scriptpubkey = tal_dup_arr(in, u8, utxos[i]->scriptPubkey, + tal_bytelen(utxos[i]->scriptPubkey), 0); + + /* All our inputs are sig + key (P2WPKH or P2SH-P2WPKH) */ + in->max_witness_len = 1 + 1 + 73 + 1 + 33; + + /* + * FIXME: add BOLT reference when merged. + * `input_info`.`script` is the scriptPubkey data for the input. + * NB: for native SegWit inputs (P2WPKH and P2WSH) inputs, the `script` field + * will be empty. + */ + if (utxos[i]->is_p2sh) { + in->script = tal_arr(in, u8, tx->wtx->inputs[i].script_len); + memcpy(in->script, tx->wtx->inputs[i].script, + tx->wtx->inputs[i].script_len); + } else + in->script = NULL; + + (*inputs)[i] = in; + } + + *outputs = tal_arr(ctx, struct output_info *, 0); + for (i = 0; i < tx->wtx->num_outputs; i++) { + struct output_info *out; + struct wally_tx_output wo; + + wo = tx->wtx->outputs[i]; + + /* This is a hack that excludes P2WSH outputs + * which for us, now are exclusively funding outputs */ + if (exclude_funding_output && wo.script_len == 34) + continue; + + out = tal(*outputs, struct output_info); + out->output_satoshis.satoshis = wo.satoshi; /* Raw: type conversion */ + out->script = tal_arr(out, u8, wo.script_len); + memcpy(out->script, wo.script, wo.script_len); + + tal_arr_expand(outputs, out); + } +} + +static bool check_remote_inputs(struct input_info **remote_inputs, + struct amount_sat *input_funding) +{ + size_t i = 0; + + // FIXME: we should check that they don't also + // turn in the funding output + // and maybe check that none of their outputs + // are duplicates?? + *input_funding = AMOUNT_SAT(0); + for (i = 0; i < tal_count(remote_inputs); i++) { + + if (!amount_sat_add(input_funding, *input_funding, remote_inputs[i]->input_satoshis)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Overflow in remote input amount %s + %s", + type_to_string(tmpctx, struct amount_sat, + &remote_inputs[i]->input_satoshis), + type_to_string(tmpctx, struct amount_sat, + input_funding)); + /** TODO: add BOLT reference when merged + * - MUST ensure each `input_info` refers to a non-malleable (segwit) UTXO. */ + /* P2SH wrapped inputs send the redeemscript, which we can check */ + if (remote_inputs[i]->script) { + if (!is_p2wpkh(remote_inputs[i]->script, NULL) + && !is_p2wsh(remote_inputs[i]->script, NULL)) + return false; + } else if (!is_p2wpkh(remote_inputs[i]->prevtx_scriptpubkey, NULL) + && !is_p2wsh(remote_inputs[i]->prevtx_scriptpubkey, NULL)) + return false; + + } + return true; +} + + +/* Check that the tx info your peer sent you is kosher */ +static bool check_remote_input_outputs(struct state *state, + enum role remote_role, + struct input_info **remote_inputs, + struct output_info **remote_outputs, + struct amount_sat stated_funding_sats) +{ + size_t i = 0; + struct amount_sat funding, other_outputs, funding_tx_sats; + bool has_change_address; + + /** + * BOLT-737016aef544011f385a9e081f85eca34eb61ab6 + * - if is the `opener`: + * - MUST NOT send zero inputs (`num_inputs` cannot be zero). + */ + if (remote_role == OPENER) { + if (!tal_count(remote_inputs)) + peer_failed(state->pps, + &state->channel_id, + "Opener sent no funding inputs"); + } else { + /** + * BOLT-737016aef544011f385a9e081f85eca34eb61ab6 + * - if is the `accepter`: + * - consider the `contribution count` the total of their `num_inputs` plus + * `num_outputs' + * - MUST NOT send a `funding_compose` message where the `contribution count` + * exceeds the limit of 4. + */ + if (tal_count(remote_inputs) + tal_count(remote_outputs) > REMOTE_CONTRIB_LIMIT) + peer_failed(state->pps, + &state->channel_id, + "Too many remote contributions. " + "Received %ld inputs, %ld outputs; " + "max allowed is %d", + tal_count(remote_inputs), + tal_count(remote_outputs), + REMOTE_CONTRIB_LIMIT); + } + + if (!check_remote_inputs(remote_inputs, &funding)) + peer_failed(state->pps, + &state->channel_id, + "Peer sent malleable (non-Segwit) input."); + + other_outputs = AMOUNT_SAT(0); + has_change_address = false; + for (i = 0; i < tal_count(remote_outputs); i++) { + if (amount_sat_eq(AMOUNT_SAT(0), remote_outputs[i]->output_satoshis)) { + if (has_change_address) + peer_failed(state->pps, + &state->channel_id, + "Peer sent more than one change outputs."); + + has_change_address = true; + } + if (!amount_sat_add(&other_outputs, other_outputs, remote_outputs[i]->output_satoshis)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Overflow in remote outher_outputs satoshis %s + %s", + type_to_string(tmpctx, struct amount_sat, + &other_outputs), + type_to_string(tmpctx, struct amount_sat, + &remote_outputs[i]->output_satoshis)); + + /* TODO: add BOLT reference when merged + * - MUST ensure the `output_info`.`script` is a standard script + */ + if (!is_known_scripttype(remote_outputs[i]->script)) + peer_failed(state->pps, + &state->channel_id, + "Peer sent non-standard output script."); + + } + + /** TODO: add BOLT reference when merged + * The receiving node: + * - if the total `input_info`.`satoshis` is less than the total `output_info`.`satoshis` + * - MUST fail the channel. + */ + if (!amount_sat_sub(&funding_tx_sats, funding, other_outputs)) + peer_failed(state->pps, + &state->channel_id, + "Total remote input satoshi less than output satoshis. change:%s inputs:%s", + type_to_string(tmpctx, struct amount_sat, + &other_outputs), + type_to_string(tmpctx, struct amount_sat, + &funding)); + + if (!amount_sat_greater_eq(funding_tx_sats, stated_funding_sats)) + peer_failed(state->pps, + &state->channel_id, + "Input amounts won't afford " + "funding amount (desired: %s, provided: %s).", + type_to_string(tmpctx, struct amount_sat, + &stated_funding_sats), + type_to_string(tmpctx, struct amount_sat, + &funding_tx_sats)); + + return true; +} +#endif + +static u8 *funder_finalize_channel_setup2(struct state *state, + struct utxo **utxos, + struct bitcoin_signature *sig, + struct bitcoin_tx **tx) +{ +#if EXPERIMENTAL_FEATURES + u8 *msg; + struct channel_id id_in; + const u8 *wscript; + char *err_reason; + struct input_info **local_ins, **remote_ins; + struct output_info **local_outs, **remote_outs; + struct bitcoin_tx_input **remotetx_ins; + struct amount_sat total_funding; + struct bitcoin_signature their_sig, our_sig; + struct amount_msat local_funding_msat; + + size_t i, input_count; + struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; + struct witness_stack **remote_witnesses; + + /* Derive components, omitting the funding output */ + local_ins = tal_arr(tmpctx, struct input_info *, 0); + local_outs = tal_arr(tmpctx, struct output_info *, 0); + derive_input_output_info(tmpctx, *tx, utxos, true, + &local_ins, &local_outs); + + /* Send them to the peer */ + msg = towire_funding_compose(tmpctx, &state->channel_id, + cast_const2(const struct input_info **, local_ins), + cast_const2(const struct output_info **, local_outs)); + + sync_crypto_write(state->pps, take(msg)); + + peer_billboard(false, + "Opening channel: funding_compose sent, " + "waiting for funding_compose reply"); + + msg = opening_negotiate_msg(tmpctx, state, false); + if (!msg) + return NULL; + + /* The next message is "funding_compose", which tells us the funding + * inputs and outputs they've selected. */ + if (!fromwire_funding_compose(state, msg, &id_in, + &remote_ins, + &remote_outs)) + peer_failed(state->pps, + &state->channel_id, + "Parsing received funding_compose %s", tal_hex(msg, msg)); + + if (!check_remote_input_outputs(state, ACCEPTER, + remote_ins, remote_outs, + state->accepter_funding)) + return NULL; + + /* FIXME: send their inputs master to verify via bitcoind */ + + input_count = tal_count(local_ins) + tal_count(remote_ins); + const void *map[input_count]; + for (i = 0; i < input_count; i++) + map[i] = int2ptr(i); + + /* Build the funding transaction */ + funding_tx = dual_funding_funding_tx(state, chainparams, + &state->funding_txout, + state->feerate_per_kw_funding, + &state->opener_funding, + state->accepter_funding, + local_ins, remote_ins, + local_outs, remote_outs, + &state->our_funding_pubkey, + &state->their_funding_pubkey, + &total_funding, + (const void **)&map); + + if (!funding_tx) + peer_failed(state->pps, + &state->channel_id, + "Unable to afford funding transaction"); + + bitcoin_txid(funding_tx, &state->funding_txid); + + /* Move our push_msat over to the other peer */ + if (!amount_sat_sub_msat(&local_funding_msat, state->opener_funding, state->push_msat)) + peer_failed(state->pps, + &state->channel_id, + "Unable to afford funding transaction, pushed to much"); + + state->channel = new_initial_channel(state, + &state->funding_txid, + state->funding_txout, + state->minimum_depth, + total_funding, + local_funding_msat, + 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, + state->option_static_remotekey, + LOCAL); + + /* We don't expect this to fail, but it does do some additional + * internal sanity checks. */ + if (!state->channel) + peer_failed(state->pps, + &state->channel_id, + "We could not create channel with given config"); + + /* We switch over to using the funding_tx derived channel_id */ + derive_channel_id(&state->channel_id, + &state->funding_txid, state->funding_txout); + + /* We need to send them the signatures for their commitment tx */ + remote_commit = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[REMOTE], + REMOTE, &err_reason); + + if (!remote_commit) + negotiation_failed(state, true, + "Could not meet fees and reserve: %s", err_reason); + + msg = towire_hsm_sign_remote_commitment_tx(NULL, + remote_commit, + &state->channel->funding_pubkey[REMOTE], + state->channel->funding, + (const struct witscript **) remote_commit->output_witscripts, + &state->first_per_commitment_point[REMOTE], + state->channel->option_static_remotekey); + + wire_sync_write(HSM_FD, take(msg)); + msg = wire_sync_read(tmpctx, HSM_FD); + if (!fromwire_hsm_sign_tx_reply(msg, &our_sig)) + status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s", + tal_hex(tmpctx, msg)); + + peer_billboard(false, "Opening channel: sending commitment_signed"); + + /* Now we send it */ + msg = towire_commitment_signed(tmpctx, &state->channel_id, + &our_sig.s, NULL); + + sync_crypto_write(state->pps, take(msg)); + msg = opening_negotiate_msg(tmpctx, state, true); + if (!msg) + return NULL; + + their_sig.sighash_type = SIGHASH_ALL; + if (!fromwire_accepter_sigs(state, msg, &id_in, + &their_sig.s, + (struct witness_stack ***)&remote_witnesses)) + peer_failed(state->pps, + &state->channel_id, + "Bad accepter_sigs in %s", tal_hex(msg, msg)); + + peer_billboard(false, + "Opening channel: accepter_sigs received"); + + /* Check that they're using the right channel_id */ + check_channel_id(state, &id_in, &state->channel_id); + + /* Check that they sent the right count of witnesses */ + if (tal_count(remote_witnesses) != tal_count(remote_ins)) + peer_failed(state->pps, + &state->channel_id, + "Received %zu witnesses for %zu inputs", + tal_count(remote_witnesses), + tal_count(remote_ins)); + + /* We create *our* initial commitment transaction, and check the + * signature they sent against that. */ + local_commit = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[LOCAL], + LOCAL, &err_reason); + if (!local_commit) + negotiation_failed(state, false, + "Did not meet fees and reserve: %s", err_reason); + + if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey, &their_sig)) + peer_failed(state->pps, + &state->channel_id, + "Bad signature %s on tx %s using key %s", + type_to_string(tmpctx, struct bitcoin_signature, + &their_sig), + type_to_string(tmpctx, struct bitcoin_tx, local_commit), + type_to_string(tmpctx, struct pubkey, + &state->their_funding_pubkey)); + + peer_billboard(false, + "Opening channel: accepter sigs are acceptable, moving to sign tx"); + + u32 i_map[input_count]; + for (size_t i = 0; i < input_count; i++) { + i_map[i] = ptr2int(map[i]); + } + + /* Convert witnesses to something more palatable for + * how our generated wires work */ + /* FIXME: remove post EXPERIMENTAL_FEATURE, since witness_stack will be wireable */ + remotetx_ins = tal_arr(tmpctx, struct bitcoin_tx_input *, tal_count(remote_witnesses)); + for (i = 0; i < tal_count(remote_witnesses); i++) { + remotetx_ins[i] = tal(remotetx_ins, struct bitcoin_tx_input); + } + + return towire_opening_dual_funding_signed(state, + state->pps, + local_commit, + &their_sig, + funding_tx, + state->funding_txout, + cast_const2( + const struct bitcoin_tx_input **, + remotetx_ins), + i_map, + state->opener_funding, + &state->remoteconf, + &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->feerate_per_kw, + state->feerate_per_kw_funding, + state->localconf.channel_reserve, + state->upfront_shutdown_script[REMOTE]); +#else + return NULL; +#endif /* EXPERIMENTAL_FEATURES */ +} + static bool funder_finalize_channel_setup(struct state *state, struct amount_msat local_msat, struct bitcoin_signature *sig, @@ -1031,6 +1484,9 @@ static u8 *funder_channel_complete(struct state *state, type_to_string(tmpctx, struct amount_sat, &state->opener_funding)); + if (state->use_v2) + return funder_finalize_channel_setup2(state, utxos, &sig, &tx); + if (!funder_finalize_channel_setup(state, local_msat, &sig, &tx)) return NULL; @@ -1619,6 +2075,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_OPENING_DEV_MEMLEAK_REPLY: case WIRE_OPENING_INIT: case WIRE_OPENING_FUNDER_REPLY: + case WIRE_OPENING_DUAL_FUNDING_SIGNED: case WIRE_OPENING_FUNDER_START_REPLY: case WIRE_OPENING_FUNDEE: case WIRE_OPENING_FUNDER_FAILED: From e4173bfe19a5efdc1f0d4d3fe0c1a00d9459d569 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Sep 2019 19:26:27 -0500 Subject: [PATCH 016/131] fundchannel_complete: return 'txid' and 'remote signed' tx Only applies for dual funded transactions. Ideally will be obsoleted with a PSBT implementation soon.TM Changelog-Added: JSON-API, `fundchannel_complete` now includes the `txid` and `tx_with_remotesigs` for channels opened using v2 protocol pathway --- lightningd/opening_control.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 0051cd3c0098..8840286469cc 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -308,6 +308,11 @@ static void funding_success(struct channel *channel) json_add_string(response, "channel_id", type_to_string(tmpctx, struct channel_id, &fc->cid)); json_add_bool(response, "commitments_secured", true); + if (fc->utx) { + json_add_txid(response, "txid", &fc->utx->txid); + /* FIXME: use PSBT for this */ + json_add_tx(response, "tx_with_remotesigs", fc->utx->tx); + } was_pending(command_success(cmd, response)); } From 7762faeb03b635df3a4a76be3d3bf57d2856e633 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 19 Sep 2019 18:13:25 -0500 Subject: [PATCH 017/131] df: wire in feature flag this number is tentative, will need to be updated when set definitively --- common/features.c | 7 +++++++ common/features.h | 9 +++++++++ lightningd/opening_control.c | 3 +-- tests/test_misc.py | 36 +++++++++++++++++++++++++----------- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/common/features.c b/common/features.c index 490cb18a94f8..421d7fa3015f 100644 --- a/common/features.c +++ b/common/features.c @@ -71,6 +71,10 @@ static const struct feature_style feature_styles[] = { [BOLT11_FEATURE] = FEATURE_REPRESENT, [CHANNEL_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL} }, #endif + { OPT_FUNDCHANNEL_V2, + .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL, + [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, + [CHANNEL_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL} }, }; static enum feature_copy_style feature_copy_style(u32 f, enum feature_place p) @@ -274,6 +278,9 @@ static const char *feature_name(const tal_t *ctx, size_t f) "option_static_remotekey", "option_payment_secret", "option_basic_mpp", +#if EXPERIMENTAL_FEATURES + "option_dual_fund", +#endif }; if (f / 2 >= ARRAY_SIZE(fnames)) diff --git a/common/features.h b/common/features.h index dd844bb4b25f..8fc10372564e 100644 --- a/common/features.h +++ b/common/features.h @@ -108,4 +108,13 @@ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES); #if EXPERIMENTAL_FEATURES #define OPT_ONION_MESSAGES 102 #endif + +/*BOLT-1a9a018f5e2fa7239ae25f333c0be1f294f6c5e9 #2 + * + * | Bits | Name |... + * | 28/29 | `option_dual_fund` |... + */ +/* FIXME: update the RFC to match */ +#define OPT_FUNDCHANNEL_V2 18 + #endif /* LIGHTNING_COMMON_FEATURES_H */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 8840286469cc..9810925bed42 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1493,8 +1493,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, = tal_steal(fc, fc->our_upfront_shutdown_script); #if EXPERIMENTAL_FEATURES - // FIXME: use features to flag on - fc->is_v2 = true; + fc->is_v2 = feature_offered(peer->their_features, OPT_FUNDCHANNEL_V2); #else fc->is_v2 = false; #endif diff --git a/tests/test_misc.py b/tests/test_misc.py index 37f3aaa1a214..a07ae5c21b3b 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -6,8 +6,10 @@ from pyln.client import RpcError from threading import Event from pyln.testing.utils import ( - DEVELOPER, TIMEOUT, VALGRIND, DEPRECATED_APIS, sync_blockheight, only_one, - wait_for, TailableProc, env + DEVELOPER, TIMEOUT, VALGRIND, DEPRECATED_APIS, + EXPERIMENTAL_FEATURES, + sync_blockheight, only_one, wait_for, + TailableProc, env ) from ephemeral_port_reserve import reserve from utils import EXPERIMENTAL_FEATURES @@ -1787,15 +1789,27 @@ def test_dev_demux(node_factory): def test_list_features_only(node_factory): features = subprocess.check_output(['lightningd/lightningd', '--list-features-only']).decode('utf-8').splitlines() - expected = ['option_data_loss_protect/odd', - 'option_upfront_shutdown_script/odd', - 'option_gossip_queries/odd', - 'option_var_onion_optin/odd', - 'option_gossip_queries_ex/odd', - 'option_static_remotekey/odd', - 'option_payment_secret/odd', - 'option_basic_mpp/odd', - ] + if EXPERIMENTAL_FEATURES: + expected = ['option_data_loss_protect/odd', + 'option_upfront_shutdown_script/odd', + 'option_gossip_queries/odd', + 'option_var_onion_optin/odd', + 'option_gossip_queries_ex/odd', + 'option_static_remotekey/odd', + 'option_payment_secret/odd', + 'option_basic_mpp/odd', + 'option_dual_fund/odd', + ] + else: + expected = ['option_data_loss_protect/odd', + 'option_upfront_shutdown_script/odd', + 'option_gossip_queries/odd', + 'option_var_onion_optin/odd', + 'option_gossip_queries_ex/odd', + 'option_static_remotekey/odd', + 'option_payment_secret/odd', + 'option_basic_mpp/odd', + ] assert features == expected From 5c0bd16335af39edffff20744a7fc13e98d44a7f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 23 Sep 2019 18:26:20 -0500 Subject: [PATCH 018/131] utxos: pass through the scriptpubkey We're now passing utxos to openingd, who needs to know what the scriptPubkey is, to relay to our peer. --- common/test/run-funding_tx.c | 12 ++++++++++++ common/test/run-funding_tx_dual.c | 12 ++++++++++++ common/utxo.c | 11 +++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 24e04e3974a0..8035bbcea9d0 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -37,12 +37,18 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n /* Generated stub for fromwire_pubkey */ void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_u16 */ +u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } /* Generated stub for fromwire_u32 */ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u32 called!\n"); abort(); } /* Generated stub for fromwire_u64 */ u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } /* Generated stub for towire_amount_sat */ void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) { fprintf(stderr, "towire_amount_sat called!\n"); abort(); } @@ -58,12 +64,18 @@ void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) /* Generated stub for towire_pubkey */ void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "towire_pubkey called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } /* Generated stub for towire_u32 */ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) { fprintf(stderr, "towire_u32 called!\n"); abort(); } /* Generated stub for towire_u64 */ void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) { fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ #if 0 diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index 24cdb70f68be..eec513dce564 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -37,12 +37,18 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n /* Generated stub for fromwire_pubkey */ void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_u16 */ +u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } /* Generated stub for fromwire_u32 */ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u32 called!\n"); abort(); } /* Generated stub for fromwire_u64 */ u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } /* Generated stub for towire_amount_sat */ void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) { fprintf(stderr, "towire_amount_sat called!\n"); abort(); } @@ -58,12 +64,18 @@ void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) /* Generated stub for towire_pubkey */ void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "towire_pubkey called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } /* Generated stub for towire_u32 */ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) { fprintf(stderr, "towire_u32 called!\n"); abort(); } /* Generated stub for towire_u64 */ void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) { fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ struct test_case { diff --git a/common/utxo.c b/common/utxo.c index b39adde67df2..90568e6445b4 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -24,11 +24,15 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) if (utxo->close_info->commitment_point) towire_pubkey(pptr, utxo->close_info->commitment_point); } + + towire_u16(pptr, tal_count(utxo->scriptPubkey)); + towire_u8_array(pptr, utxo->scriptPubkey, tal_count(utxo->scriptPubkey)); } struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) { struct utxo *utxo = tal(ctx, struct utxo); + u16 script_len; fromwire_bitcoin_txid(ptr, max, &utxo->txid); utxo->outnum = fromwire_u32(ptr, max); @@ -36,10 +40,6 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) utxo->keyindex = fromwire_u32(ptr, max); utxo->is_p2sh = fromwire_bool(ptr, max); - /* No need to tell hsmd about the scriptPubkey, it has all the info to - * derive it from the rest. */ - utxo->scriptPubkey = NULL; - if (fromwire_bool(ptr, max)) { utxo->close_info = tal(utxo, struct unilateral_close_info); utxo->close_info->channel_id = fromwire_u64(ptr, max); @@ -54,6 +54,9 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) } else { utxo->close_info = NULL; } + + script_len = fromwire_u16(ptr, max); + fromwire_u8_array(ptr, max, utxo->scriptPubkey, script_len); return utxo; } From 7dfe35e79830338db5f8686b4f998acd54e17b43 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 14:18:28 -0500 Subject: [PATCH 019/131] txprepare: zero out change if asked dual funding needs an output who's value is set to zero in order to correctly specify change for the opener. this modifies txprepare to allow for generating such an output Changelog-Added: JSON-API: `txprepare` now takes a parameter, `zero_out_change`, that will set the value of the change output to zero in any composed transaction. --- plugins/fundchannel.c | 7 +++++++ wallet/walletrpc.c | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 7caf703880a6..1fbc26e70d87 100644 --- a/plugins/fundchannel.c +++ b/plugins/fundchannel.c @@ -42,6 +42,9 @@ struct funding_req { /* Failing result (NULL on success) */ /* Raw JSON from RPC output */ const char *error; + + /* Are we using v2 protocol ? */ + bool is_v2; }; static struct command_result *send_prior(struct command *cmd, @@ -210,6 +213,8 @@ static void txprepare(struct json_stream *js, json_add_u32(js, "minconf", *fr->minconf); if (fr->utxo_str) json_add_jsonstr(js, "utxos", fr->utxo_str); + if (fr->is_v2) + json_add_bool(js, "zero_out_change", true); } static struct command_result *prepare_actual(struct command *cmd, @@ -408,6 +413,8 @@ static struct command_result *json_fundchannel(struct command *cmd, NULL)) return command_param_failed(); + /* Set to false at start, will update when we know more */ + fr->is_v2 = false; fr->funding_all = streq(fr->funding_str, "all"); return connect_to_peer(cmd, fr); diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 5e70397e6a98..62b137b8db23 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -181,6 +181,7 @@ static struct command_result *json_prepare_tx(struct command *cmd, u32 *feerate_per_kw = NULL; struct command_result *result; u32 *minconf, maxheight; + bool *zero_out_change; struct pubkey *changekey; struct bitcoin_tx_output **outputs; const jsmntok_t *outputstok = NULL, *t; @@ -203,6 +204,7 @@ static struct command_result *json_prepare_tx(struct command *cmd, p_opt("feerate", param_feerate, &feerate_per_kw), p_opt_def("minconf", param_number, &minconf, 1), p_opt("utxos", param_utxos, &chosen_utxos), + p_opt_def("zero_out_change", param_bool, &zero_out_change, false), NULL)) return command_param_failed(); } else if (params->type == JSMN_ARRAY) { @@ -214,6 +216,7 @@ static struct command_result *json_prepare_tx(struct command *cmd, p_opt("feerate_or_sat", param_tok, &secondtok), p_opt("minconf_or_feerate", param_tok, &thirdtok), p_opt("utxos_or_minconf", param_tok, &fourthtok), + p_opt_def("zero_out_change", param_bool, &zero_out_change, false), NULL)) return command_param_failed(); @@ -298,6 +301,7 @@ static struct command_result *json_prepare_tx(struct command *cmd, p_opt("feerate", param_feerate, &feerate_per_kw), p_opt_def("minconf", param_number, &minconf, 1), p_opt("utxos", param_utxos, &chosen_utxos), + p_opt_def("zero_out_change", param_bool, &zero_out_change, false), NULL)) /* If the parameters mixed the new style and the old style, * fail it. */ @@ -315,6 +319,9 @@ static struct command_result *json_prepare_tx(struct command *cmd, } } } else { + /* not an option for withdraws, set to false */ + zero_out_change = tal(cmd, bool); + *zero_out_change = false; /* *withdraw* command still use 'destination' and 'satoshi' as parameters. */ if (!param(cmd, buffer, params, p_req("destination", param_bitcoin_address, @@ -422,17 +429,24 @@ static struct command_result *json_prepare_tx(struct command *cmd, /* Add the change as the last output */ if (!amount_sat_eq((*utx)->wtx->change, AMOUNT_SAT(0))) { struct bitcoin_tx_output *change_output; + struct amount_sat change; changekey = tal(tmpctx, struct pubkey); if (!bip32_pubkey(cmd->ld->wallet->bip32_base, changekey, (*utx)->wtx->change_key_index)) return command_fail(cmd, LIGHTNINGD, "Keys generation failure"); - change_output = new_tx_output(outputs, (*utx)->wtx->change, + + if (*zero_out_change) + change = AMOUNT_SAT(0); + else + change = (*utx)->wtx->change; + change_output = new_tx_output(outputs, change, scriptpubkey_p2wpkh(tmpctx, changekey)); - tal_arr_expand(outputs, *change_output); + tal_arr_expand(&outputs, change_output); } + (*utx)->inputs = NULL; (*utx)->outputs = tal_steal(*utx, outputs); (*utx)->tx = withdraw_tx(*utx, chainparams, (*utx)->wtx->utxos, From 576444e855a6eab4e63c7a0acb420fb740ed27c6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 8 Oct 2019 10:54:18 -0500 Subject: [PATCH 020/131] zero_out_change: add to pylightning Changelog-Added: Pyln, fundchannel_start now includes handling for the `zero_out_change` parameter --- contrib/pyln-client/pyln/client/lightning.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 70ab6ef74730..370d573e1d2f 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1077,12 +1077,13 @@ def txprepare(self, *args, **kwargs): if len(args) and not isinstance(args[0], list): return self._deprecated_txprepare(*args, **kwargs) - def _txprepare(outputs, feerate=None, minconf=None, utxos=None): + def _txprepare(outputs, feerate=None, minconf=None, utxos=None, zero_out_change=None): payload = { "outputs": outputs, "feerate": feerate, "minconf": minconf, "utxos": utxos, + "zero_out_change": zero_out_change, } return self.call("txprepare", payload) From 2cb4da1d2ee55be20ff35d2df73169c1b47d4d9b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 14:27:07 -0500 Subject: [PATCH 021/131] wire: add dual-funding subtypes to list allows us to use them in wire definitions other than where they are defined. --- tools/generate-wire.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 808d8c8c281b..032be83e82cc 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -230,6 +230,9 @@ class Type(FieldSet): 'onionmsg_path', 'route_hop', 'bitcoin_tx_input', + 'output_info', + 'input_info', + 'witness_stack', ] # Some BOLT types are re-typed based on their field name From f66a35df70f76cb088ac3c8e6f14dc8d17259544 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 16:47:16 -0500 Subject: [PATCH 022/131] wallet-df: save our_funds amount to channel record We'll need it to represent to user in `listpeers` --- lightningd/channel.c | 2 + lightningd/channel.h | 5 ++ lightningd/opening_control.c | 1 + wallet/db.c | 48 +++++++++++++++ wallet/wallet.c | 114 ++++++++++++++++++----------------- 5 files changed, 116 insertions(+), 54 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 33dcb13d0065..4e00bbc178ec 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -159,6 +159,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u16 funding_outnum, struct amount_sat funding, struct amount_msat push, + struct amount_sat our_funds, bool remote_funding_locked, /* NULL or stolen */ struct short_channel_id *scid, @@ -227,6 +228,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->funding_outnum = funding_outnum; channel->funding = funding; channel->push = push; + channel->our_funds = our_funds; channel->remote_funding_locked = remote_funding_locked; channel->scid = tal_steal(channel, scid); channel->our_msat = our_msat; diff --git a/lightningd/channel.h b/lightningd/channel.h index 9fc5c432fdf1..fbd30e01079f 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -60,6 +60,10 @@ struct channel { struct bitcoin_txid funding_txid; u16 funding_outnum; struct amount_sat funding; + + /* Our original funds, in funding amount */ + struct amount_sat our_funds; + struct amount_msat push; bool remote_funding_locked; /* Channel if locked locally. */ @@ -149,6 +153,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u16 funding_outnum, struct amount_sat funding, struct amount_msat push, + struct amount_sat our_funds, bool remote_funding_locked, /* NULL or stolen */ struct short_channel_id *scid STEALS, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 9810925bed42..94ad85df459d 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -255,6 +255,7 @@ wallet_commit_channel(struct lightningd *ld, funding_outnum, total_funding, push, + local_funding, false, /* !remote_funding_locked */ NULL, /* no scid yet */ /* The three arguments below are msatoshi_to_us, diff --git a/wallet/db.c b/wallet/db.c index 3e06ce436a98..3f881d899431 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -20,6 +20,8 @@ struct migration { static void migrate_pr2342_feerate_per_channel(struct lightningd *ld, struct db *db); +static void migrate_our_funding(struct lightningd *ld, struct db *db); + /* Do not reorder or remove elements from this array, it is used to * migrate existing databases from a previous state, based on the * string indices */ @@ -596,6 +598,7 @@ static struct migration dbmigrations[] = { * Turn anything in transition into a WIRE_TEMPORARY_NODE_FAILURE. */ {SQL("ALTER TABLE channel_htlcs ADD localfailmsg BLOB;"), NULL}, {SQL("UPDATE channel_htlcs SET localfailmsg=decode('2002', 'hex') WHERE malformed_onion != 0 AND direction = 1;"), NULL}, + {SQL("ALTER TABLE channels ADD our_funding_satoshi INTEGER DEFAULT 0;"), migrate_our_funding}, }; /* Leak tracking. */ @@ -1072,6 +1075,51 @@ static void migrate_pr2342_feerate_per_channel(struct lightningd *ld, struct db tal_free(stmt); } +/* We've added a column `our_funding_satoshis`, since channels can now + * have funding for either channel participant. We need to 'backfill' this + * data, however. We can do this using the fact that our_funding_satoshi + * is the same as the funding_satoshi for every channel where we are + * the `funder` + */ +static void migrate_our_funding(struct lightningd *ld, struct db *db) +{ + struct db_stmt *query_stmt, *update_stmt; + struct amount_sat funding_sat; + u64 channel_dbid; + + /* Fetch out the id and funding_satoshis */ + query_stmt = db_prepare_v2(db, SQL("SELECT id, funding_satoshi" + " FROM channels" + " WHERE funder = ?")); + db_bind_int(query_stmt, 0, LOCAL); + db_query_prepared(query_stmt); + if (query_stmt->error) + db_fatal("Error migrating funding %s", query_stmt->error); + + while (db_step(query_stmt)) { + /* Statement to update record */ + update_stmt = db_prepare_v2(db, SQL("UPDATE channels" + " SET our_funding_satoshi = ?" + " WHERE id = ?;")); + + channel_dbid = db_column_u64(query_stmt, 0); + db_column_amount_sat(query_stmt, 1, &funding_sat); + + db_bind_amount_sat(update_stmt, 0, &funding_sat); + db_bind_u64(update_stmt, 1, channel_dbid); + + db_exec_prepared_v2(update_stmt); + + if (update_stmt->error) + db_fatal("Error migrating funding for channel %"PRIu64" %s", + channel_dbid, update_stmt->error); + + tal_free(update_stmt); + } + + tal_free(query_stmt); +} + void db_bind_null(struct db_stmt *stmt, int pos) { assert(pos < tal_count(stmt->bindings)); diff --git a/wallet/wallet.c b/wallet/wallet.c index 638fb09e1efc..c51aed10385a 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -873,7 +873,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm struct basepoints local_basepoints; struct pubkey local_funding_pubkey; struct pubkey *future_per_commitment_point; - struct amount_sat funding_sat; + struct amount_sat funding_sat, our_funding_sat; struct amount_msat push_msat, our_msat, msat_to_us_min, msat_to_us_max; peer_dbid = db_column_u64(stmt, 1); @@ -893,15 +893,15 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm scid = NULL; } - ok &= wallet_shachain_load(w, db_column_u64(stmt, 27), &wshachain); + ok &= wallet_shachain_load(w, db_column_u64(stmt, 28), &wshachain); - remote_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 28, u8); + remote_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 29, u8); local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 46, u8); /* Do we have a last_sent_commit, if yes, populate */ - if (!db_column_is_null(stmt, 41)) { - const u8 *cursor = db_column_blob(stmt, 41); - size_t len = db_column_bytes(stmt, 41); + if (!db_column_is_null(stmt, 42)) { + const u8 *cursor = db_column_blob(stmt, 42); + size_t len = db_column_bytes(stmt, 42); size_t n = 0; last_sent_commit = tal_arr(tmpctx, struct changed_htlc, n); while (len) { @@ -913,33 +913,33 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm last_sent_commit = NULL; #ifdef COMPAT_V060 - if (!last_sent_commit && !db_column_is_null(stmt, 30)) { + if (!last_sent_commit && !db_column_is_null(stmt, 31)) { last_sent_commit = tal(tmpctx, struct changed_htlc); - last_sent_commit->newstate = db_column_u64(stmt, 30); - last_sent_commit->id = db_column_u64(stmt, 31); + last_sent_commit->newstate = db_column_u64(stmt, 31); + last_sent_commit->id = db_column_u64(stmt, 32); } #endif - if (!db_column_is_null(stmt, 40)) { + if (!db_column_is_null(stmt, 41)) { future_per_commitment_point = tal(tmpctx, struct pubkey); - db_column_pubkey(stmt, 40, future_per_commitment_point); + db_column_pubkey(stmt, 41, future_per_commitment_point); } else future_per_commitment_point = NULL; channel_config_id = db_column_u64(stmt, 3); ok &= wallet_channel_config_load(w, channel_config_id, &our_config); db_column_sha256d(stmt, 12, &funding_txid.shad); - ok &= db_column_signature(stmt, 33, &last_sig.s); + ok &= db_column_signature(stmt, 34, &last_sig.s); last_sig.sighash_type = SIGHASH_ALL; /* Populate channel_info */ - db_column_pubkey(stmt, 18, &channel_info.remote_fundingkey); - db_column_pubkey(stmt, 19, &channel_info.theirbase.revocation); - db_column_pubkey(stmt, 20, &channel_info.theirbase.payment); - db_column_pubkey(stmt, 21, &channel_info.theirbase.htlc); - db_column_pubkey(stmt, 22, &channel_info.theirbase.delayed_payment); - db_column_pubkey(stmt, 23, &channel_info.remote_per_commit); - db_column_pubkey(stmt, 24, &channel_info.old_remote_per_commit); + db_column_pubkey(stmt, 19, &channel_info.remote_fundingkey); + db_column_pubkey(stmt, 20, &channel_info.theirbase.revocation); + db_column_pubkey(stmt, 21, &channel_info.theirbase.payment); + db_column_pubkey(stmt, 22, &channel_info.theirbase.htlc); + db_column_pubkey(stmt, 23, &channel_info.theirbase.delayed_payment); + db_column_pubkey(stmt, 24, &channel_info.remote_per_commit); + db_column_pubkey(stmt, 25, &channel_info.old_remote_per_commit); wallet_channel_config_load(w, db_column_u64(stmt, 4), &channel_info.their_config); @@ -956,7 +956,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm return NULL; } - final_key_idx = db_column_u64(stmt, 29); + final_key_idx = db_column_u64(stmt, 30); if (final_key_idx < 0) { log_broken(w->log, "%s: Final key < 0", __func__); return NULL; @@ -966,10 +966,11 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm &local_basepoints, &local_funding_pubkey); db_column_amount_sat(stmt, 14, &funding_sat); - db_column_amount_msat(stmt, 16, &push_msat); - db_column_amount_msat(stmt, 17, &our_msat); - db_column_amount_msat(stmt, 38, &msat_to_us_min); - db_column_amount_msat(stmt, 39, &msat_to_us_max); + db_column_amount_sat(stmt, 15, &our_funding_sat); + db_column_amount_msat(stmt, 17, &push_msat); + db_column_amount_msat(stmt, 18, &our_msat); + db_column_amount_msat(stmt, 39, &msat_to_us_min); + db_column_amount_msat(stmt, 40, &msat_to_us_max); /* We want it to take this, rather than copy. */ take(channel_info.fee_states); @@ -989,12 +990,13 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_column_int(stmt, 13), funding_sat, push_msat, - db_column_int(stmt, 15) != 0, + our_funding_sat, + db_column_int(stmt, 16) != 0, scid, our_msat, msat_to_us_min, /* msatoshi_to_us_min */ msat_to_us_max, /* msatoshi_to_us_max */ - db_column_tx(tmpctx, stmt, 32), + db_column_tx(tmpctx, stmt, 33), &last_sig, wallet_htlc_sigs_load(tmpctx, w, db_column_u64(stmt, 0)), @@ -1002,19 +1004,19 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm remote_shutdown_scriptpubkey, local_shutdown_scriptpubkey, final_key_idx, - db_column_int(stmt, 34) != 0, + db_column_int(stmt, 35) != 0, last_sent_commit, - db_column_u64(stmt, 35), - db_column_int(stmt, 36), + db_column_u64(stmt, 36), db_column_int(stmt, 37), + db_column_int(stmt, 38), /* Not connected */ false, &local_basepoints, &local_funding_pubkey, future_per_commitment_point, - db_column_int(stmt, 42), db_column_int(stmt, 43), - db_column_arr(tmpctx, stmt, 44, u8), - db_column_int(stmt, 45)); + db_column_int(stmt, 44), + db_column_arr(tmpctx, stmt, 45, u8), + db_column_int(stmt, 46)); return chan; } @@ -1055,6 +1057,7 @@ static bool wallet_channels_load_active(struct wallet *w) ", funding_tx_id" ", funding_tx_outnum" ", funding_satoshi" + ", our_funding_satoshi" ", funding_locked_remote" ", push_msatoshi" ", msatoshi_local" @@ -1335,6 +1338,7 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) " funding_tx_id=?," " funding_tx_outnum=?," " funding_satoshi=?," + " our_funding_satoshi=?," " funding_locked_remote=?," " push_msatoshi=?," " msatoshi_local=?," @@ -1371,37 +1375,39 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_int(stmt, 10, chan->funding_outnum); db_bind_amount_sat(stmt, 11, &chan->funding); - db_bind_int(stmt, 12, chan->remote_funding_locked); - db_bind_amount_msat(stmt, 13, &chan->push); - db_bind_amount_msat(stmt, 14, &chan->our_msat); + db_bind_amount_sat(stmt, 12, &chan->our_funds); + db_bind_int(stmt, 13, chan->remote_funding_locked); + db_bind_amount_msat(stmt, 14, &chan->push); + db_bind_amount_msat(stmt, 15, &chan->our_msat); if (chan->shutdown_scriptpubkey[REMOTE]) - db_bind_blob(stmt, 15, chan->shutdown_scriptpubkey[REMOTE], + db_bind_blob(stmt, 16, chan->shutdown_scriptpubkey[REMOTE], tal_count(chan->shutdown_scriptpubkey[REMOTE])); else - db_bind_null(stmt, 15); - - db_bind_u64(stmt, 16, chan->final_key_idx); - db_bind_u64(stmt, 17, chan->our_config.id); - db_bind_tx(stmt, 18, chan->last_tx); - db_bind_signature(stmt, 19, &chan->last_sig.s); - db_bind_int(stmt, 20, chan->last_was_revoke); - db_bind_int(stmt, 21, chan->min_possible_feerate); - db_bind_int(stmt, 22, chan->max_possible_feerate); - db_bind_amount_msat(stmt, 23, &chan->msat_to_us_min); - db_bind_amount_msat(stmt, 24, &chan->msat_to_us_max); - db_bind_int(stmt, 25, chan->feerate_base); - db_bind_int(stmt, 26, chan->feerate_ppm); + db_bind_null(stmt, 16); + + db_bind_u64(stmt, 17, chan->final_key_idx); + db_bind_u64(stmt, 18, chan->our_config.id); + db_bind_tx(stmt, 19, chan->last_tx); + db_bind_signature(stmt, 20, &chan->last_sig.s); + db_bind_int(stmt, 21, chan->last_was_revoke); + db_bind_int(stmt, 22, chan->min_possible_feerate); + db_bind_int(stmt, 23, chan->max_possible_feerate); + db_bind_amount_msat(stmt, 24, &chan->msat_to_us_min); + db_bind_amount_msat(stmt, 25, &chan->msat_to_us_max); + db_bind_int(stmt, 26, chan->feerate_base); + db_bind_int(stmt, 27, chan->feerate_ppm); if (chan->remote_upfront_shutdown_script) db_bind_blob( - stmt, 27, chan->remote_upfront_shutdown_script, + stmt, 28, chan->remote_upfront_shutdown_script, tal_count(chan->remote_upfront_shutdown_script)); else - db_bind_null(stmt, 27); - db_bind_int(stmt, 28, chan->option_static_remotekey); - db_bind_blob(stmt, 29, chan->shutdown_scriptpubkey[LOCAL], + db_bind_null(stmt, 28); + + db_bind_int(stmt, 29, chan->option_static_remotekey); + db_bind_blob(stmt, 30, chan->shutdown_scriptpubkey[LOCAL], tal_count(chan->shutdown_scriptpubkey[LOCAL])); - db_bind_u64(stmt, 30, chan->dbid); + db_bind_u64(stmt, 31, chan->dbid); db_exec_prepared_v2(take(stmt)); wallet_channel_config_save(w, &chan->channel_info.their_config); From 9cc6bec7a924908b46dc141c96dd9d11a0beb8da Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:05:28 -0500 Subject: [PATCH 023/131] utxo: add scriptSig field Allow the utxo object to bear the scriptSig as well; also fixes broken scriptPubkey parsing on utxo --- common/utxo.c | 19 ++++++++++++++----- common/utxo.h | 3 +++ wallet/wallet.c | 17 +++++++++++++++++ wallet/wallet.h | 8 ++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/common/utxo.c b/common/utxo.c index 90568e6445b4..dd3b4b4a539a 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -16,6 +16,11 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) towire_u32(pptr, utxo->keyindex); towire_bool(pptr, utxo->is_p2sh); + towire_u16(pptr, tal_count(utxo->scriptPubkey)); + towire_u8_array(pptr, utxo->scriptPubkey, tal_count(utxo->scriptPubkey)); + towire_u16(pptr, tal_count(utxo->scriptSig)); + towire_u8_array(pptr, utxo->scriptSig, tal_count(utxo->scriptSig)); + towire_bool(pptr, is_unilateral_close); if (is_unilateral_close) { towire_u64(pptr, utxo->close_info->channel_id); @@ -24,15 +29,13 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) if (utxo->close_info->commitment_point) towire_pubkey(pptr, utxo->close_info->commitment_point); } - - towire_u16(pptr, tal_count(utxo->scriptPubkey)); - towire_u8_array(pptr, utxo->scriptPubkey, tal_count(utxo->scriptPubkey)); } struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) { struct utxo *utxo = tal(ctx, struct utxo); u16 script_len; + u16 scriptsig_len; fromwire_bitcoin_txid(ptr, max, &utxo->txid); utxo->outnum = fromwire_u32(ptr, max); @@ -40,6 +43,14 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) utxo->keyindex = fromwire_u32(ptr, max); utxo->is_p2sh = fromwire_bool(ptr, max); + script_len = fromwire_u16(ptr, max); + utxo->scriptPubkey = tal_arr(utxo, u8, script_len); + fromwire_u8_array(ptr, max, utxo->scriptPubkey, script_len); + + scriptsig_len = fromwire_u16(ptr, max); + utxo->scriptSig = tal_arr(utxo, u8, scriptsig_len); + fromwire_u8_array(ptr, max, utxo->scriptSig, scriptsig_len); + if (fromwire_bool(ptr, max)) { utxo->close_info = tal(utxo, struct unilateral_close_info); utxo->close_info->channel_id = fromwire_u64(ptr, max); @@ -55,8 +66,6 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) utxo->close_info = NULL; } - script_len = fromwire_u16(ptr, max); - fromwire_u8_array(ptr, max, utxo->scriptPubkey, script_len); return utxo; } diff --git a/common/utxo.h b/common/utxo.h index 459d5c5ccea1..1652cc2c6e9e 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -41,6 +41,9 @@ struct utxo { /* The scriptPubkey if it is known */ u8 *scriptPubkey; + + /* scriptSig. Only for P2SH outputs */ + u8 *scriptSig; }; void towire_utxo(u8 **pptr, const struct utxo *utxo); diff --git a/wallet/wallet.c b/wallet/wallet.c index c51aed10385a..753e6b0976a0 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -175,6 +175,7 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->blockheight = NULL; utxo->spendheight = NULL; utxo->scriptPubkey = NULL; + utxo->scriptSig = NULL; if (!db_column_is_null(stmt, 9)) { blockheight = tal(utxo, u32); @@ -537,6 +538,22 @@ const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, return utxo; } +u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex) +{ + struct ext_key ext; + struct pubkey key; + + if (bip32_key_from_parent(w->bip32_base, keyindex, + BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK) { + fatal("Unable to derive pubkey"); + } + + if (!pubkey_from_der(ext.pub_key, PUBKEY_CMPR_LEN, &key)) + fatal("Unble to derive pubkey from DER"); + + return bitcoin_scriptsig_p2sh_p2wpkh(ctx, &key); +} + bool wallet_can_spend(struct wallet *w, const u8 *script, u32 *index, bool *output_is_p2sh) { diff --git a/wallet/wallet.h b/wallet/wallet.h index 6fbd57287b3c..a8e6231eb87f 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -399,6 +399,14 @@ const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, struct amount_sat *sat, struct amount_sat *fee_estimate); +/* derive_redeem_scriptsig - Compute the scriptSig for a P2SH-P2WPKH + * + * @ctx - allocation context + * @w - wallet + * @keyindex - index of the internal BIP32 key + */ +u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex); + /** * wallet_select_specific - Select utxos given an array of txids and an array of outputs index * From 95a1fd4f1d1783db83e77f4292841539a35de74e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:13:48 -0500 Subject: [PATCH 024/131] channeld: add flag for whether channel has our funds --- channeld/channel_wire.csv | 1 + channeld/channeld.c | 4 +++- channeld/full_channel.c | 2 ++ channeld/full_channel.h | 2 ++ channeld/test/run-full_channel.c | 4 ++-- common/initial_channel.c | 2 ++ common/initial_channel.h | 6 ++++++ devtools/mkcommit.c | 1 + lightningd/channel_control.c | 1 + openingd/openingd.c | 4 +++- 10 files changed, 23 insertions(+), 4 deletions(-) diff --git a/channeld/channel_wire.csv b/channeld/channel_wire.csv index cf87f8a1aa26..22ec4c35d387 100644 --- a/channeld/channel_wire.csv +++ b/channeld/channel_wire.csv @@ -25,6 +25,7 @@ msgdata,channel_init,remote_basepoints,basepoints, msgdata,channel_init,remote_per_commit,pubkey, msgdata,channel_init,old_remote_per_commit,pubkey, msgdata,channel_init,opener,enum side, +msgdata,channel_init,local_funded,bool, msgdata,channel_init,fee_base,u32, msgdata,channel_init,fee_proportional,u32, msgdata,channel_init,local_msatoshi,amount_msat, diff --git a/channeld/channeld.c b/channeld/channeld.c index 3a4d19f91912..9920b7620a18 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -3085,7 +3085,7 @@ static void init_channel(struct peer *peer) struct secret last_remote_per_commit_secret; secp256k1_ecdsa_signature *remote_ann_node_sig; secp256k1_ecdsa_signature *remote_ann_bitcoin_sig; - bool option_static_remotekey; + bool option_static_remotekey, local_funded; #if !DEVELOPER bool dev_fail_process_onionpacket; /* Ignored */ #endif @@ -3111,6 +3111,7 @@ static void init_channel(struct peer *peer) &peer->remote_per_commit, &peer->old_remote_per_commit, &opener, + &local_funded, &peer->fee_base, &peer->fee_per_satoshi, &local_msat, @@ -3205,6 +3206,7 @@ static void init_channel(struct peer *peer) &funding_pubkey[LOCAL], &funding_pubkey[REMOTE], option_static_remotekey, + local_funded, opener); if (!channel_force_htlcs(peer->channel, diff --git a/channeld/full_channel.c b/channeld/full_channel.c index ecb1180ea17a..56596968d02e 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -101,6 +101,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, + bool local_funded, enum side opener) { struct channel *channel = new_initial_channel(ctx, @@ -116,6 +117,7 @@ struct channel *new_full_channel(const tal_t *ctx, local_funding_pubkey, remote_funding_pubkey, option_static_remotekey, + local_funded, opener); if (channel) { diff --git a/channeld/full_channel.h b/channeld/full_channel.h index 7d618ec9ca23..aaaeb4e52f6e 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -25,6 +25,7 @@ struct existing_htlc; * @local_fundingkey: local funding key * @remote_fundingkey: remote funding key * @option_static_remotekey: use `option_static_remotekey`. + * @local_funded: true if local has inputs in funding tx * @opener: which side initiated it. * * Returns state, or NULL if malformed. @@ -43,6 +44,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, + bool local_funded, enum side opener); /** diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 2fac4d079711..017479f22c3f 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -477,7 +477,7 @@ int main(void) &localbase, &remotebase, &local_funding_pubkey, &remote_funding_pubkey, - false, LOCAL); + false, true, LOCAL); rchannel = new_full_channel(tmpctx, &funding_txid, funding_output_index, 0, funding_amount, to_remote, @@ -488,7 +488,7 @@ int main(void) &remotebase, &localbase, &remote_funding_pubkey, &local_funding_pubkey, - false, REMOTE); + false, false, REMOTE); /* BOLT #3: * diff --git a/common/initial_channel.c b/common/initial_channel.c index 718b9a9cf511..238afa3c2560 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -24,6 +24,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, + bool local_funded, enum side opener) { struct channel *channel = tal(ctx, struct channel); @@ -32,6 +33,7 @@ struct channel *new_initial_channel(const tal_t *ctx, channel->funding_txid = *funding_txid; channel->funding_txout = funding_txout; channel->funding = funding; + channel->local_funded = local_funded; channel->minimum_depth = minimum_depth; if (!amount_sat_sub_msat(&remote_msatoshi, channel->funding, local_msatoshi)) diff --git a/common/initial_channel.h b/common/initial_channel.h index b68f7fe58575..3829cf0e73aa 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -41,6 +41,9 @@ struct channel { /* Who is paying fees. */ enum side opener; + /* True if we have inputs in the funding tx */ + bool local_funded; + /* Limits and settings on this channel. */ struct channel_config config[NUM_SIDES]; @@ -78,6 +81,8 @@ struct channel { * @remote_basepoints: remote basepoints. * @local_fundingkey: local funding key * @remote_fundingkey: remote funding key + * @option_static_remotekey: whether to use static remotekeys or not + * @local_funded: true if we put funds into the funding tx * @opener: which side initiated it. * * Returns channel, or NULL if malformed. @@ -96,6 +101,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct pubkey *local_funding_pubkey, const struct pubkey *remote_funding_pubkey, bool option_static_remotekey, + bool local_funded, enum side opener); diff --git a/devtools/mkcommit.c b/devtools/mkcommit.c index 076e55d3c2f0..c121d70648d9 100644 --- a/devtools/mkcommit.c +++ b/devtools/mkcommit.c @@ -387,6 +387,7 @@ int main(int argc, char *argv[]) &localbase, &remotebase, &funding_localkey, &funding_remotekey, option_static_remotekey, + fee_payer == LOCAL, fee_payer); if (!channel_force_htlcs(channel, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 6d0f7dbaaa9b..72830fb7f4ca 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -482,6 +482,7 @@ void peer_start_channeld(struct channel *channel, &channel->channel_info.remote_per_commit, &channel->channel_info.old_remote_per_commit, channel->opener, + !amount_sat_eq(channel->our_funds, AMOUNT_SAT(0)), channel->feerate_base, channel->feerate_ppm, channel->our_msat, diff --git a/openingd/openingd.c b/openingd/openingd.c index 675c9d2807dc..781e00fda2e3 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1140,6 +1140,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->our_funding_pubkey, &state->their_funding_pubkey, state->option_static_remotekey, + true, LOCAL); /* We don't expect this to fail, but it does do some additional @@ -1304,7 +1305,7 @@ static bool funder_finalize_channel_setup(struct state *state, &state->our_funding_pubkey, &state->their_funding_pubkey, state->option_static_remotekey, - /* Opener is local */ + true, LOCAL); /* We were supposed to do enough checks above, but just in case, * new_initial_channel will fail to create absurd channels */ @@ -1788,6 +1789,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->our_funding_pubkey, &their_funding_pubkey, state->option_static_remotekey, + false, REMOTE); /* We don't expect this to fail, but it does do some additional * internal sanity checks. */ From 04986a66e53b2fef8ad11f0d642ac889acf64596 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:29:05 -0500 Subject: [PATCH 025/131] df: pass opener's change through so we can update utx We need the change amount to be correct when we send the tx, so we save the change amount and pipe it through. --- common/funding_tx.c | 28 ++++++------- common/funding_tx.h | 4 +- common/test/run-funding_tx_dual.c | 5 ++- lightningd/opening_control.c | 12 ++++-- openingd/opening_wire.csv | 14 +++++-- openingd/openingd.c | 65 +++++++++++++------------------ 6 files changed, 66 insertions(+), 62 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 6a773fe48629..bfae733215c3 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -197,12 +197,12 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, struct amount_sat *total_funding, + struct amount_sat *opener_change, const void **input_map) { size_t weight; struct amount_sat funding_tx_fee, opener_total_sat, - accepter_total_sat, - opener_change, output_val; + accepter_total_sat, output_val; struct bitcoin_tx *tx; const struct output_info *change_output; @@ -217,7 +217,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, &opener_total_sat, &accepter_total_sat); funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); - if (!amount_sat_sub(&opener_change, opener_total_sat, *opener_funding)) + if (!amount_sat_sub(opener_change, opener_total_sat, *opener_funding)) return NULL; /* Check that the remaining amount at least covers the other @@ -226,18 +226,18 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, * only 'flexible' / change output that's removable etc is indicated * by a zero value. */ output_val = calculate_output_value(opener_outputs); - if (!amount_sat_sub(&opener_change, opener_change, output_val)) + if (!amount_sat_sub(opener_change, *opener_change, output_val)) return NULL; change_output = find_change_output(opener_outputs); - if (amount_sat_sub(&opener_change, opener_change, funding_tx_fee) && - amount_sat_greater(opener_change, chainparams->dust_limit)) { + if (amount_sat_sub(opener_change, *opener_change, funding_tx_fee) && + amount_sat_greater(*opener_change, chainparams->dust_limit)) { if (!change_output) { /* If there's no change output, we put the remainder into * the funding output. TODO: add to spec */ assert(amount_sat_add(opener_funding, - *opener_funding, opener_change)); - opener_change = AMOUNT_SAT(0); + *opener_funding, *opener_change)); + *opener_change = AMOUNT_SAT(0); } goto build_tx; @@ -250,9 +250,9 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); /* Any left over gets added to the funding output */ - if (amount_sat_sub(&opener_change, opener_change, funding_tx_fee)) { - assert(amount_sat_add(opener_funding, *opener_funding, opener_change)); - opener_change = AMOUNT_SAT(0); + if (amount_sat_sub(opener_change, *opener_change, funding_tx_fee)) { + assert(amount_sat_add(opener_funding, *opener_funding, *opener_change)); + *opener_change = AMOUNT_SAT(0); goto build_tx; } } @@ -261,7 +261,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, !amount_sat_sub(opener_funding, *opener_funding, output_val)) return NULL; - opener_change = AMOUNT_SAT(0); + *opener_change = AMOUNT_SAT(0); build_tx: input_count = tal_count(opener_inputs) + tal_count(accepter_inputs); @@ -271,7 +271,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, /* If they had supplied a change output, but we removed it because * remove it from the count */ - if (change_output && amount_sat_eq(AMOUNT_SAT(0), opener_change)) { + if (change_output && amount_sat_eq(AMOUNT_SAT(0), *opener_change)) { output_count -= 1; assert(output_count > 0); } @@ -299,7 +299,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tx, wscript), *total_funding); /* Add the other outputs */ - add_outputs(tx, opener_outputs, &opener_change); + add_outputs(tx, opener_outputs, opener_change); add_outputs(tx, accepter_outputs, NULL); /* Note that hsmd depends on the opener's inputs diff --git a/common/funding_tx.h b/common/funding_tx.h index 899e1987abe9..28ef4d4a954f 100644 --- a/common/funding_tx.h +++ b/common/funding_tx.h @@ -53,7 +53,6 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, * @chainparams: (in) the params for the resulting transaction. * @outnum: (out) txout which is the funding output. * @feerate_kw_funding: (in) feerate for the funding transaction - * @total_funding: (out) total funding amount for this transaction * @opener_funding: (in/out) funding amount contributed by opener * @accepter_funding: (in) funding amount contributed by accepter * @opener_inputs: (in) inputs from the opener @@ -62,6 +61,8 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, * @accepter_outputs: (in) outputs for the accepter * @local_fundingkey: (in) local key for 2of2 funding output. * @remote_fundingkey: (in) remote key for 2of2 funding output. + * @total_funding: (out) total funding amount for this transaction + * @opener_change: (out) change amount for opener * @input_map: (out) ordering of inputs, after being sorted. */ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, @@ -77,6 +78,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, struct amount_sat *total_funding, + struct amount_sat *opener_change, const void **input_map); #endif /* EXPERIMENTAL_FEATURES */ #endif /* LIGHTNING_COMMON_FUNDING_TX_H */ diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index eec513dce564..4d32b2464607 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -730,7 +730,7 @@ int main(void) chainparams = chainparams_for_network("bitcoin"); u16 outnum; - struct amount_sat total_funding; + struct amount_sat total_funding, opener_change; for (size_t i = 0; i < num_tests; i++) { struct test_case test = test_cases[i](tmpctx); @@ -755,7 +755,8 @@ int main(void) test.accepter_outputs, &local_funding_pubkey, &remote_funding_pubkey, - &total_funding, NULL); + &total_funding, + &opener_change, NULL); if (!test.expected_tx && !funding) continue; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 94ad85df459d..8ddb6cea6183 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -382,6 +382,7 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp, static bool update_unreleased_tx(struct unreleased_tx *utx, struct bitcoin_tx *tx, u32 *input_map, + struct amount_sat opener_change, struct witness_stack **witnesses) { size_t i, j, num_other_ins, num_utxo; @@ -467,6 +468,7 @@ static bool update_unreleased_tx(struct unreleased_tx *utx, utx->tx = tal_free(utx->tx); utx->tx = tal_steal(utx, tx); bitcoin_txid(tx, &utx->txid); + utx->wtx->change = opener_change; return true; } @@ -483,12 +485,12 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, struct bitcoin_signature remote_commit_sig; struct bitcoin_tx *remote_commit, *funding_tx; u32 feerate, feerate_funding; - struct amount_sat local_funding, total_funding; + struct amount_sat local_funding, total_funding, opener_change; struct channel *channel; struct lightningd *ld = openingd->ld; u8 *remote_upfront_shutdown_script; struct per_peer_state *pps; - struct bitcoin_tx_input **remote_ins; + struct witness_stack **remote_witnesses; struct funding_channel *fc = uc->fc; struct unreleased_tx *utx = fc->utx; u32 *input_map; @@ -503,7 +505,8 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, &remote_commit_sig, &funding_tx, &funding_txout, - &remote_ins, + &opener_change, + &remote_witnesses, &input_map, &local_funding, &channel_info.their_config, @@ -538,7 +541,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, } /* Update the funding tx that we have for this */ - if (!update_unreleased_tx(utx, funding_tx, input_map, witnesses)) { + if (!update_unreleased_tx(utx, funding_tx, input_map, opener_change, witnesses)) { log_broken(uc->log, "Unable to update unreleased tx"); uncommitted_channel_disconnect(uc, LOG_BROKEN, "internal error in creating updated tx"); goto cleanup; @@ -710,6 +713,7 @@ static void opening_fundee_finished(struct subd *openingd, &funding_txid, &funding_outnum, &funding, + &AMOUNT_SAT(0), &push, &channel_flags, &feerate, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 4bae99e4ae01..ef2bca1f7cc6 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -119,13 +119,16 @@ msgdata,opening_fundee,their_per_commit_point,pubkey, msgdata,opening_fundee,remote_fundingkey,pubkey, msgdata,opening_fundee,funding_txid,bitcoin_txid, msgdata,opening_fundee,funding_txout,u16, -msgdata,opening_fundee,funding_satoshis,amount_sat, +msgdata,opening_fundee,opener_funding,amount_sat, +msgdata,opening_fundee,accepter_funding,amount_sat, msgdata,opening_fundee,push_msat,amount_msat, msgdata,opening_fundee,channel_flags,u8, msgdata,opening_fundee,feerate_per_kw,u32, -# The funding signed message: send this and we're committed. +# The 'signed' message: send this and we're committed. +# msgtype v1: funding_signed +# msgtype v2: accepter_sigs msgdata,opening_fundee,msglen,u16, -msgdata,opening_fundee,funding_signed_msg,u8,msglen +msgdata,opening_fundee,signed_msg,u8,msglen msgdata,opening_fundee,our_channel_reserve_satoshis,amount_sat, msgdata,opening_fundee,local_shutdown_len,u16, msgdata,opening_fundee,local_shutdown_scriptpubkey,u8,local_shutdown_len @@ -134,14 +137,17 @@ msgdata,opening_fundee,remote_shutdown_scriptpubkey,u8,remote_shutdown_len # openingd->master: accepter's signatures etc # for a dual-funded channel open +#include msgtype,opening_dual_funding_signed,6204 +#if EXPERIMENTAL_FEATURES msgdata,opening_dual_funding_signed,pps,per_peer_state, msgdata,opening_dual_funding_signed,first_commit,bitcoin_tx, msgdata,opening_dual_funding_signed,first_commit_sig,bitcoin_signature, msgdata,opening_dual_funding_signed,funding_tx,bitcoin_tx, msgdata,opening_dual_funding_signed,funding_tx_out,u16, +msgdata,opening_dual_funding_signed,opener_change,amount_sat, msgdata,opening_dual_funding_signed,num_witnesses,u16, -msgdata,opening_dual_funding_signed,remote_witnesses,bitcoin_tx_input,num_witnesses +msgdata,opening_dual_funding_signed,remote_witnesses,witness_stack,num_witnesses msgdata,opening_dual_funding_signed,num_inputs,u32, msgdata,opening_dual_funding_signed,input_map,u32,num_inputs msgdata,opening_dual_funding_signed,local_funding,amount_sat, diff --git a/openingd/openingd.c b/openingd/openingd.c index 781e00fda2e3..d856097b6e11 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1048,19 +1048,16 @@ static u8 *funder_finalize_channel_setup2(struct state *state, char *err_reason; struct input_info **local_ins, **remote_ins; struct output_info **local_outs, **remote_outs; - struct bitcoin_tx_input **remotetx_ins; - struct amount_sat total_funding; + struct amount_sat total_funding, opener_change; struct bitcoin_signature their_sig, our_sig; struct amount_msat local_funding_msat; size_t i, input_count; struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; - struct witness_stack **remote_witnesses; + const struct witness_stack **remote_witnesses; /* Derive components, omitting the funding output */ - local_ins = tal_arr(tmpctx, struct input_info *, 0); - local_outs = tal_arr(tmpctx, struct output_info *, 0); - derive_input_output_info(tmpctx, *tx, utxos, true, + derive_input_output_info(state, *tx, utxos, true, &local_ins, &local_outs); /* Send them to the peer */ @@ -1110,6 +1107,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->our_funding_pubkey, &state->their_funding_pubkey, &total_funding, + &opener_change, (const void **)&map); if (!funding_tx) @@ -1230,43 +1228,35 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->their_funding_pubkey)); peer_billboard(false, - "Opening channel: accepter sigs are acceptable, moving to sign tx"); + "Opening channel: accepter sigs are acceptable, moving to sign tx %s", + type_to_string(state, struct bitcoin_tx, funding_tx)); - u32 i_map[input_count]; + u32 *i_map = tal_arr(state, u32, input_count); for (size_t i = 0; i < input_count; i++) { i_map[i] = ptr2int(map[i]); } - /* Convert witnesses to something more palatable for - * how our generated wires work */ - /* FIXME: remove post EXPERIMENTAL_FEATURE, since witness_stack will be wireable */ - remotetx_ins = tal_arr(tmpctx, struct bitcoin_tx_input *, tal_count(remote_witnesses)); - for (i = 0; i < tal_count(remote_witnesses); i++) { - remotetx_ins[i] = tal(remotetx_ins, struct bitcoin_tx_input); - } - return towire_opening_dual_funding_signed(state, - state->pps, - local_commit, - &their_sig, - funding_tx, - state->funding_txout, - cast_const2( - const struct bitcoin_tx_input **, - remotetx_ins), - i_map, - state->opener_funding, - &state->remoteconf, - &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->feerate_per_kw, - state->feerate_per_kw_funding, - state->localconf.channel_reserve, - state->upfront_shutdown_script[REMOTE]); + state->pps, + local_commit, + &their_sig, + funding_tx, + state->funding_txout, + opener_change, + remote_witnesses, + i_map, + state->opener_funding, + &state->remoteconf, + &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->feerate_per_kw, + state->feerate_per_kw_funding, + state->localconf.channel_reserve, + state->upfront_shutdown_script[REMOTE]); #else return NULL; #endif /* EXPERIMENTAL_FEATURES */ @@ -1907,6 +1897,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->funding_txid, state->funding_txout, state->opener_funding, + AMOUNT_SAT(0), state->push_msat, channel_flags, state->feerate_per_kw, From 7913287161889d9d8879b8ef81e86c732a85a361 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:36:32 -0500 Subject: [PATCH 026/131] hsmd: add method for signing dual funded txs method plus wire calls --- connectd/Makefile | 1 + gossipd/Makefile | 1 + hsmd/Makefile | 2 + hsmd/capabilities.h | 1 + hsmd/hsm_wire.csv | 31 ++++++++++++ hsmd/hsmd.c | 121 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 157 insertions(+) diff --git a/connectd/Makefile b/connectd/Makefile index 28d41d7e4dd9..1d7fdeaa675a 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -54,6 +54,7 @@ CONNECTD_COMMON_OBJS := \ common/features.o \ common/gen_status_wire.o \ common/gossip_rcvd_filter.o \ + common/htlc_wire.o \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ diff --git a/gossipd/Makefile b/gossipd/Makefile index 7de9fae19ec6..0bd9b98aab90 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -56,6 +56,7 @@ GOSSIPD_COMMON_OBJS := \ common/features.o \ common/gen_status_wire.o \ common/gossip_rcvd_filter.o \ + common/htlc_wire.o \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ diff --git a/hsmd/Makefile b/hsmd/Makefile index 9b4c49c25bf4..7663ba9b1c94 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -22,10 +22,12 @@ HSMD_COMMON_OBJS := \ common/funding_tx.o \ common/gen_status_wire.o \ common/hash_u5.o \ + common/htlc_wire.o \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ + common/onionreply.o \ common/permute_tx.o \ common/status.o \ common/status_wire.o \ diff --git a/hsmd/capabilities.h b/hsmd/capabilities.h index 3a306e778a2a..98b8f7a2442e 100644 --- a/hsmd/capabilities.h +++ b/hsmd/capabilities.h @@ -7,6 +7,7 @@ #define HSM_CAP_COMMITMENT_POINT 8 #define HSM_CAP_SIGN_REMOTE_TX 16 #define HSM_CAP_SIGN_CLOSING_TX 32 +#define HSM_CAP_SIGN_ACCEPTER_FUNDING_TX 64 #define HSM_CAP_MASTER 1024 #endif /* LIGHTNING_HSMD_CAPABILITIES_H */ diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index 9f1a3fc5dda0..5946f35eec3b 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -57,6 +57,37 @@ msgdata,hsm_sign_funding,inputs,utxo,num_inputs msgtype,hsm_sign_funding_reply,104 msgdata,hsm_sign_funding_reply,tx,bitcoin_tx, +# Return witness stack for a funding tx. +msgtype,hsm_dual_funding_sigs,40 +#if EXPERIMENTAL_FEATURES +#include +#include +#include +#include +msgdata,hsm_dual_funding_sigs,num_utxos,u16, +msgdata,hsm_dual_funding_sigs,our_utxos,utxo,num_utxos +msgdata,hsm_dual_funding_sigs,feerate_kw_funding,u32, +msgdata,hsm_dual_funding_sigs,opener_funding,amount_sat, +msgdata,hsm_dual_funding_sigs,accepter_funding,amount_sat, +msgdata,hsm_dual_funding_sigs,num_opener_inputs,u16, +msgdata,hsm_dual_funding_sigs,opener_inputs,input_info,num_opener_inputs +msgdata,hsm_dual_funding_sigs,num_accepter_inputs,u16, +msgdata,hsm_dual_funding_sigs,accepter_inputs,input_info,num_accepter_inputs +msgdata,hsm_dual_funding_sigs,num_opener_outputs,u16, +msgdata,hsm_dual_funding_sigs,opener_outputs,output_info,num_opener_outputs +msgdata,hsm_dual_funding_sigs,num_accepter_outputs,u16, +msgdata,hsm_dual_funding_sigs,accepter_outputs,output_info,num_accepter_outputs +msgdata,hsm_dual_funding_sigs,our_pubkey,pubkey, +msgdata,hsm_dual_funding_sigs,their_pubkey,pubkey, +msgdata,hsm_dual_funding_sigs,opener,enum side, + +msgtype,hsm_dual_funding_sigs_reply,42 +#if EXPERIMENTAL_FEATURES +msgdata,hsm_dual_funding_sigs_reply,stack_height,u16, +msgdata,hsm_dual_funding_sigs_reply,witnesses,witness_stack,stack_height +msgdata,hsm_dual_funding_sigs_reply,tx,bitcoin_tx, + + # Master asks the HSM to sign a node_announcement msgtype,hsm_node_announcement_sig_req,6 msgdata,hsm_node_announcement_sig_req,annlen,u16, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index bf3f95e57897..d1aac2867c6d 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1641,6 +1641,112 @@ static void sign_our_inputs(struct bitcoin_tx *tx, struct utxo **utxos, } } +#if EXPERIMENTAL_FEATURES +static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, + struct client *c, + const u8 *msg_in) +{ + size_t i = 0, j; + struct bitcoin_tx *tx; + u32 feerate_kw_funding, offset; + struct pubkey local_pubkey, remote_pubkey; + struct amount_sat opener_funding, accepter_funding; + struct input_info **opener_inputs, **accepter_inputs; + struct output_info **opener_outputs, **accepter_outputs; + struct utxo **our_utxos; + struct amount_sat total_funding, opener_change; + enum side opener; + struct witness_stack **stacks; + + if (!fromwire_hsm_dual_funding_sigs(tmpctx, + msg_in, + &our_utxos, + &feerate_kw_funding, + &opener_funding, + &accepter_funding, + &opener_inputs, + &accepter_inputs, + &opener_outputs, + &accepter_outputs, + &local_pubkey, + &remote_pubkey, + &opener)) + + return bad_req(conn, c, msg_in); + + size_t input_count = tal_count(opener_inputs) + + tal_count(accepter_inputs); + + const void *map[input_count]; + for (i = 0; i < input_count; i++) + map[i] = int2ptr(i); + + tx = dual_funding_funding_tx(tmpctx, + c->chainparams, + NULL, + feerate_kw_funding, + &opener_funding, + accepter_funding, + opener_inputs, accepter_inputs, + opener_outputs, accepter_outputs, + &local_pubkey, + &remote_pubkey, + &total_funding, + &opener_change, + (const void **)&map); + + if (!tx) + return bad_req_fmt(conn, c, msg_in, + "Unable to create valid funding tx."); + + /* For the input_map, the opener_inputs are added before the accepter's */ + offset = opener == LOCAL ? 0 : tal_count(opener_inputs); + + stacks = tal_arr(tmpctx, struct witness_stack *, tal_count(our_utxos)); + for (i = 0; i < tal_count(our_utxos); i++) { + struct bitcoin_signature sig; + struct pubkey inkey; + size_t input_index = -1; + struct witness_stack *stack; + u8 **witnesses; + + stack = tal(stacks, struct witness_stack); + for (j = 0; j < input_count; j++) { + if (ptr2int(map[j]) == i + offset) { + input_index = j; + break; + } + } + + if (input_index == -1) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find index for input"); + + sign_input(tx, our_utxos[i], &inkey, &sig, input_index); + witnesses = + bitcoin_witness_p2wpkh(tmpctx, &sig, &inkey); + + stack->witness_element = + tal_arr(stack, struct witness_element *, tal_count(witnesses)); + + for (j = 0; j < tal_count(witnesses); j++) { + stack->witness_element[j] = + tal(stack->witness_element, struct witness_element); + stack->witness_element[j]->witness = + tal_steal(stack->witness_element[j], witnesses[j]); + } + + stacks[i] = stack; + tal_free(witnesses); + } + + return req_reply(conn, c, take( + towire_hsm_dual_funding_sigs_reply(tmpctx, + cast_const2(const struct witness_stack **, stacks), + cast_const(const struct bitcoin_tx *, tx)))); +} +#endif /* EXPERIMENTAL_FEATURES */ + /*~ lightningd asks us to sign the transaction to fund a channel; it feeds us * the set of inputs and the local and remote pubkeys, and we sign it. */ static struct io_plan *handle_sign_funding_tx(struct io_conn *conn, @@ -1963,6 +2069,13 @@ static bool check_client_capabilities(struct client *client, case WIRE_HSM_SIGN_MUTUAL_CLOSE_TX: return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0; + case WIRE_HSM_DUAL_FUNDING_SIGS: +#if EXPERIMENTAL_FEATURES + return (client->capabilities & HSM_CAP_SIGN_ACCEPTER_FUNDING_TX) != 0; +#else + return false; +#endif /* EXPERIMENTAL_FEATURES */ + case WIRE_HSM_INIT: case WIRE_HSM_CLIENT_HSMFD: case WIRE_HSM_SIGN_FUNDING: @@ -1982,6 +2095,7 @@ static bool check_client_capabilities(struct client *client, case WIRE_HSM_CUPDATE_SIG_REPLY: case WIRE_HSM_CLIENT_HSMFD_REPLY: case WIRE_HSM_SIGN_FUNDING_REPLY: + case WIRE_HSM_DUAL_FUNDING_SIGS_REPLY: case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_SIGN_WITHDRAWAL_REPLY: case WIRE_HSM_SIGN_INVOICE_REPLY: @@ -2035,6 +2149,12 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSM_SIGN_FUNDING: return handle_sign_funding_tx(conn, c, c->msg_in); + case WIRE_HSM_DUAL_FUNDING_SIGS: +#if EXPERIMENTAL_FEATURES + return handle_sign_dual_funding_tx(conn, c, c->msg_in); +#else + return NULL; +#endif /* EXPERIMENTAL_FEATURES */ case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REQ: return handle_sign_node_announcement(conn, c, c->msg_in); @@ -2087,6 +2207,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSM_CUPDATE_SIG_REPLY: case WIRE_HSM_CLIENT_HSMFD_REPLY: case WIRE_HSM_SIGN_FUNDING_REPLY: + case WIRE_HSM_DUAL_FUNDING_SIGS_REPLY: case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_SIGN_WITHDRAWAL_REPLY: case WIRE_HSM_SIGN_INVOICE_REPLY: From 2ac857746cb7986ebb081e6b5b53e32bb5e9b323 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:40:09 -0500 Subject: [PATCH 027/131] hsmd: allow openingd to call hsm to sign dual-funded tx Allow openingd to call hmsd for dual_funding tx's (accepter flow) --- lightningd/opening_control.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 8ddb6cea6183..879dd288d1ef 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1210,7 +1210,8 @@ void peer_start_openingd(struct peer *peer, hsmfd = hsm_get_client_fd(peer->ld, &uc->peer->id, uc->dbid, HSM_CAP_COMMITMENT_POINT - | HSM_CAP_SIGN_REMOTE_TX); + | HSM_CAP_SIGN_REMOTE_TX + | HSM_CAP_SIGN_ACCEPTER_FUNDING_TX); uc->openingd = new_channel_subd(peer->ld, "lightning_openingd", From 3ba492d2e2451f5f4963d0e21703f15edfc3e427 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:47:42 -0500 Subject: [PATCH 028/131] wallet: method to compute available funds for df When we're the accepter, we need to be able to tell a plugin hook what the total available sats we have for an open channel offer. This new wallet method will calculate the total amount of sats we have available, based on our top X highest valued utxos. --- wallet/wallet.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ wallet/wallet.h | 11 +++++++ 2 files changed, 88 insertions(+) diff --git a/wallet/wallet.c b/wallet/wallet.c index 753e6b0976a0..0845095c446c 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -538,6 +538,63 @@ const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, return utxo; } +/* Select highest value, confirmed, UTXOs. Optionally limit number to return */ +static struct utxo **sorted_confirmed_utxos(const tal_t *ctx, struct wallet *w, + const enum output_status state) +{ + struct utxo **results; + int i; + struct db_stmt *stmt; + + if (state == output_state_any) + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", confirmation_height" + ", spend_height" + ", scriptpubkey " + " FROM outputs" + " WHERE confirmation_height IS NOT NULL" + " ORDER BY value DESC")); + else { + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", confirmation_height" + ", spend_height" + ", scriptpubkey " + " FROM outputs" + " WHERE status = ?" + " AND confirmation_height IS NOT NULL" + " ORDER BY value DESC")); + db_bind_int(stmt, 0, output_status_in_db(state)); + } + db_query_prepared(stmt); + + results = tal_arr(ctx, struct utxo *, 0); + for (i = 0; db_step(stmt); i++) { + struct utxo *u = wallet_stmt2output(results, stmt); + tal_arr_expand(&results, u); + } + tal_free(stmt); + + return results; +} + u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex) { struct ext_key ext; @@ -554,6 +611,26 @@ u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex) return bitcoin_scriptsig_p2sh_p2wpkh(ctx, &key); } +void wallet_compute_max(struct wallet *w, u32 max_utxos, struct amount_sat *sat) +{ + size_t i = 0; + struct utxo **available; + + available = sorted_confirmed_utxos(NULL, w, output_state_available); + + *sat = AMOUNT_SAT(0); + for (i = 0; i < tal_count(available) && i < max_utxos; i++) { + if (!amount_sat_add(sat, *sat, available[i]->amount)) + fatal("Overflow in sum of available satoshis %zu/%zu %s + %s", + i, tal_count(available), + type_to_string(tmpctx, struct amount_sat, + sat), + type_to_string(tmpctx, struct amount_sat, + &available[i]->amount)); + } + tal_free(available); +} + bool wallet_can_spend(struct wallet *w, const u8 *script, u32 *index, bool *output_is_p2sh) { diff --git a/wallet/wallet.h b/wallet/wallet.h index a8e6231eb87f..829431e87775 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -407,6 +407,17 @@ const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, */ u8 *derive_redeem_scriptsig(const tal_t *ctx, struct wallet *w, u32 keyindex); +/* wallet_compute_max - Compute the maxiumum amount of available sats in our largest + * {max_utxos} utxos + * + * Note that only calculates using the set of utxos that are currently available. + * + * @w - wallet, available utxos + * @max_utxos - limit to number of utxos to sum, ranked by largest + * @sat - (out) sum of {max_utxos} amounts + * */ +void wallet_compute_max(struct wallet *w, u32 max_utxos, struct amount_sat *sat); + /** * wallet_select_specific - Select utxos given an array of txids and an array of outputs index * From eef704b06f84bd9ddfa95b06720b4e41d2800b15 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:50:51 -0500 Subject: [PATCH 029/131] fundchannel: update to work with dual funding Update fundchannel to correctly update the txid for txsend and to know whether or not we're using v2 (needed for knowing whether or not to use the zero_output flag) --- plugins/fundchannel.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 1fbc26e70d87..2acc418634e7 100644 --- a/plugins/fundchannel.c +++ b/plugins/fundchannel.c @@ -104,6 +104,7 @@ static struct command_result *send_tx(struct command *cmd, struct out_req *req; const jsmntok_t *tok; bool commitments_secured; + char *txid; /* For sanity's sake, let's check that it's secured */ tok = json_get_member(buf, result, "commitments_secured"); @@ -111,9 +112,17 @@ static struct command_result *send_tx(struct command *cmd, /* TODO: better failure path? this should never fail though. */ plugin_err(cmd->plugin, "Commitment not secured."); + /* The txid might be updated, since the peer might have added + * inputs, also */ + tok = json_get_member(buf, result, "txid"); + if (tok) { + txid = json_strdup(cmd, buf, tok); + if (!bitcoin_txid_from_hex(txid, strlen(txid), &fr->tx_id)) + plugin_err(cmd->plugin, "Unable to parse reserved txid %s", txid); + } + /* Stash the channel_id so we can return it when finalized */ - tok = json_get_member(buf, result, "channel_id"); - fr->chanstr = json_strdup(fr, buf, tok); + fr->chanstr = json_strdup(fr, buf, json_get_member(buf, result, "channel_id")); req = jsonrpc_request_start(cmd->plugin, cmd, "txsend", finish, tx_abort, fr); @@ -247,6 +256,10 @@ static struct command_result *fundchannel_start_done(struct command *cmd, fr->funding_addr = json_strdup(cmd, buf, json_get_member(buf, result, "funding_address")); + /* Is this a v2 request? */ + fr->is_v2 = json_tok_streq(buf, + json_get_member(buf, result, "open_channel_version"), "2"); + /* Now that we're ready to go, cancel the reserved tx */ req = jsonrpc_request_start(cmd->plugin, cmd, "txdiscard", prepare_actual, cancel_start, From 5e44b47bdc65394abf2f6bda0d909a906a1324ac Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 17:53:03 -0500 Subject: [PATCH 030/131] listpeers: show funding_allocation for df'd channels Calculate the correct funding amounts to display for dual funded channels. --- lightningd/peer_control.c | 40 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index a737f9652f6f..81dfab9c0444 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -613,6 +613,7 @@ static void json_add_channel(struct lightningd *ld, struct channel_id cid; struct channel_stats channel_stats; struct amount_msat spendable, receivable, funding_msat, their_msat; + struct amount_sat remote_funds; struct peer *p = channel->peer; json_object_start(response, key); @@ -653,36 +654,23 @@ static void json_add_channel(struct lightningd *ld, response, "private", !(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)); - // FIXME @conscott : Modify this when dual-funded channels - // are implemented + /* Calculate remote peer's funding contribution */ + assert(amount_sat_sub(&remote_funds, + channel->funding, channel->our_funds)); + /* Add funding amounts, raw msat */ json_object_start(response, "funding_allocation_msat"); - if (channel->opener == LOCAL) { - json_add_u64(response, node_id_to_hexstr(tmpctx, &p->id), 0); - json_add_u64(response, node_id_to_hexstr(tmpctx, &ld->id), - channel->funding.satoshis * 1000); /* Raw: raw JSON field */ - } else { - json_add_u64(response, node_id_to_hexstr(tmpctx, &ld->id), 0); - json_add_u64(response, node_id_to_hexstr(tmpctx, &p->id), - channel->funding.satoshis * 1000); /* Raw: raw JSON field */ - } + json_add_u64(response, node_id_to_hexstr(tmpctx, &p->id), + remote_funds.satoshis * 1000); /* Raw: raw JSON field */ + json_add_u64(response, node_id_to_hexstr(tmpctx, &ld->id), + channel->our_funds.satoshis * 1000); /* Raw: raw JSON field */ json_object_end(response); + /* Add funding amounts, 'msat' style */ json_object_start(response, "funding_msat"); - if (channel->opener == LOCAL) { - json_add_sat_only(response, - node_id_to_hexstr(tmpctx, &p->id), - AMOUNT_SAT(0)); - json_add_sat_only(response, - node_id_to_hexstr(tmpctx, &ld->id), - channel->funding); - } else { - json_add_sat_only(response, - node_id_to_hexstr(tmpctx, &ld->id), - AMOUNT_SAT(0)); - json_add_sat_only(response, - node_id_to_hexstr(tmpctx, &p->id), - channel->funding); - } + json_add_sat_only(response, node_id_to_hexstr(tmpctx, &p->id), + remote_funds); + json_add_sat_only(response, node_id_to_hexstr(tmpctx, &ld->id), + channel->our_funds); json_object_end(response); if (!amount_sat_to_msat(&funding_msat, channel->funding)) { From 8af5018646e5a85032bca7df941705648cfe5d24 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 18:13:32 -0500 Subject: [PATCH 031/131] df-accepter: pass v2 info back to opening_control Send info that we need for doing the right thing in the openchannel plugin back to opening_control --- lightningd/opening_control.c | 5 +++++ openingd/opening_wire.csv | 2 ++ openingd/openingd.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 879dd288d1ef..85331b0a084a 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -943,12 +943,15 @@ static void channel_config(struct lightningd *ld, struct openchannel_hook_payload { struct subd *openingd; struct amount_sat funding_satoshis; + /* Is this a v2 openchannel call? */ + bool is_v2; struct amount_msat push_msat; struct amount_sat dust_limit_satoshis; struct amount_msat max_htlc_value_in_flight_msat; struct amount_sat channel_reserve_satoshis; struct amount_msat htlc_minimum_msat; u32 feerate_per_kw; + u32 feerate_per_kw_funding; u16 to_self_delay; u16 max_accepted_htlcs; u8 channel_flags; @@ -1085,6 +1088,7 @@ static void opening_got_offer(struct subd *openingd, payload = tal(openingd, struct openchannel_hook_payload); payload->openingd = openingd; if (!fromwire_opening_got_offer(payload, msg, + &payload->is_v2, &payload->funding_satoshis, &payload->push_msat, &payload->dust_limit_satoshis, @@ -1092,6 +1096,7 @@ static void opening_got_offer(struct subd *openingd, &payload->channel_reserve_satoshis, &payload->htlc_minimum_msat, &payload->feerate_per_kw, + &payload->feerate_per_kw_funding, &payload->to_self_delay, &payload->max_accepted_htlcs, &payload->channel_flags, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index ef2bca1f7cc6..ac2da0ef69cb 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -31,6 +31,7 @@ msgdata,opening_init,dev_fast_gossip,bool, # Openingd->master: they offered channel, should we continue? msgtype,opening_got_offer,6005 +msgdata,opening_got_offer,is_v2,bool, msgdata,opening_got_offer,funding_satoshis,amount_sat, msgdata,opening_got_offer,push_msat,amount_msat, msgdata,opening_got_offer,dust_limit_satoshis,amount_sat, @@ -38,6 +39,7 @@ msgdata,opening_got_offer,max_htlc_value_in_flight_msat,amount_msat, msgdata,opening_got_offer,channel_reserve_satoshis,amount_sat, msgdata,opening_got_offer,htlc_minimum_msat,amount_msat, msgdata,opening_got_offer,feerate_per_kw,u32, +msgdata,opening_got_offer,feerate_per_kw_funding,u32, msgdata,opening_got_offer,to_self_delay,u16, msgdata,opening_got_offer,max_accepted_htlcs,u16, msgdata,opening_got_offer,channel_flags,u8, diff --git a/openingd/openingd.c b/openingd/openingd.c index d856097b6e11..8947d3982988 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1682,6 +1682,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) /* Check with lightningd that we can accept this? In particular, * if we have an existing channel, we don't support it. */ msg = towire_opening_got_offer(NULL, + state->use_v2, state->opener_funding, state->push_msat, state->remoteconf.dust_limit, @@ -1689,6 +1690,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) state->remoteconf.channel_reserve, state->remoteconf.htlc_minimum, state->feerate_per_kw, + state->feerate_per_kw, state->remoteconf.to_self_delay, state->remoteconf.max_accepted_htlcs, channel_flags, From 06906410c16a5b959adea1ba226cd6fb458435c6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 18:17:06 -0500 Subject: [PATCH 032/131] df-accepter: if payload is v2, calculate available funds --- lightningd/opening_control.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 85331b0a084a..10ea46f5bad2 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,10 @@ struct uncommitted_channel { /* If we offered channel, this contains information, otherwise NULL */ struct funding_channel *fc; + /* If this is dual funded and we're the accepter, + * this contains information, otherwise NULL */ + struct peer_funding *pf; + /* Our basepoints for the channel. */ struct basepoints local_basepoints; @@ -99,9 +104,19 @@ struct funding_channel { /* Whether or not to use channel open v2 */ bool is_v2; + + /* Transaction we're building for a v2 channel open */ struct unreleased_tx *utx; }; +struct peer_funding { + struct utxo **utxos; + struct amount_sat accepter_funding; + + /* Channel, subsequent owner of us */ + struct uncommitted_channel *uc; +}; + static void uncommitted_channel_disconnect(struct uncommitted_channel *uc, enum log_level level, const char *desc) @@ -950,6 +965,7 @@ struct openchannel_hook_payload { struct amount_msat max_htlc_value_in_flight_msat; struct amount_sat channel_reserve_satoshis; struct amount_msat htlc_minimum_msat; + struct amount_sat available_funds; u32 feerate_per_kw; u32 feerate_per_kw_funding; u16 to_self_delay; @@ -1107,6 +1123,18 @@ static void opening_got_offer(struct subd *openingd, return; } + if (payload->is_v2) { + uc->pf = tal(uc, struct peer_funding); + /* Calculate the max we can contribute to this channel */ + /* We use one less than the contribution count limit + * to leave room for a change output */ + wallet_compute_max(openingd->ld->wallet, + /* Leave space for change */ + REMOTE_CONTRIB_LIMIT - 1, + &payload->available_funds); + } else + uc->pf = NULL; + tal_add_destructor2(openingd, openchannel_payload_remove_openingd, payload); plugin_hook_call_openchannel(openingd->ld, payload); } From ce4e3e804429d3ad3b6e8285b6a90afdab3b5691 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 18:18:23 -0500 Subject: [PATCH 033/131] fundchannel_start: include version of open protocol Changelog-Added: JSON-API, `fundchannel_start` response includes a `open_channel_version` member, indicating the protocol that the channel establishment is using --- lightningd/opening_control.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 10ea46f5bad2..db41ed4747b9 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -351,6 +351,8 @@ static void funding_started_success(struct funding_channel *fc, json_add_hex_talarr(response, "close_to", fc->our_upfront_shutdown_script); } + json_add_string(response, "open_channel_version", fc->is_v2 ? "2" : "1"); + /* Clear this so cancel doesn't think it's still in progress */ fc->cmd = NULL; was_pending(command_success(cmd, response)); From 0df73e15ce536073671835deac0b6174d6a3a7ca Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 18:28:02 -0500 Subject: [PATCH 034/131] df-accepter: accepter logic Implements accepter side of df Changelog-Added: Plugins, `openchannel` hook can now return back a `funding_sats` member, that will contribute that amount to the pending channel open, if the channel is using the v2 protocol --- channeld/channeld.c | 10 +- lightningd/channel_control.c | 4 +- lightningd/opening_control.c | 165 +++++++++- openingd/opening_wire.csv | 10 + openingd/openingd.c | 592 ++++++++++++++++++++++++++++++----- 5 files changed, 687 insertions(+), 94 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 9920b7620a18..45fde77d6ce2 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -3078,7 +3078,7 @@ static void init_channel(struct peer *peer) enum side opener; struct existing_htlc **htlcs; bool reconnected; - u8 *funding_signed; + u8 *sigs_msg; const u8 *msg; struct fee_states *fee_states; u32 minimum_depth; @@ -3136,7 +3136,7 @@ static void init_channel(struct peer *peer) &peer->shutdown_sent[REMOTE], &peer->final_scriptpubkey, &peer->channel_flags, - &funding_signed, + &sigs_msg, &peer->announce_depth_reached, &last_remote_per_commit_secret, &peer->their_features, @@ -3231,9 +3231,9 @@ static void init_channel(struct peer *peer) if (reconnected) peer_reconnect(peer, &last_remote_per_commit_secret); - /* If we have a funding_signed message, send that immediately */ - if (funding_signed) - sync_crypto_write(peer->pps, take(funding_signed)); + /* If we have a final sigs message, send that immediately */ + if (sigs_msg) + sync_crypto_write(peer->pps, take(sigs_msg)); /* Reenable channel */ channel_announcement_negotiate(peer); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 72830fb7f4ca..b567be3696a4 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -372,7 +372,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) void peer_start_channeld(struct channel *channel, struct per_peer_state *pps, - const u8 *funding_signed, + const u8 *sigs_msg, bool reconnected) { u8 *initmsg; @@ -507,7 +507,7 @@ void peer_start_channeld(struct channel *channel, channel->shutdown_scriptpubkey[REMOTE] != NULL, channel->shutdown_scriptpubkey[LOCAL], channel->channel_flags, - funding_signed, + sigs_msg, reached_announce_depth, &last_remote_per_commit_secret, channel->peer->their_features, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index db41ed4747b9..578a400b730f 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1,6 +1,7 @@ #include "bitcoin/feerate.h" #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -696,20 +698,23 @@ static void opening_fundee_finished(struct subd *openingd, const int *fds, struct uncommitted_channel *uc) { - u8 *funding_signed; + u8 *final_peer_msg; struct channel_info channel_info; struct bitcoin_signature remote_commit_sig; struct bitcoin_tx *remote_commit; struct lightningd *ld = openingd->ld; struct bitcoin_txid funding_txid; u16 funding_outnum; - struct amount_sat funding; + struct amount_sat opener_funding; + struct amount_sat accepter_funding; + struct amount_sat total_funding; struct amount_msat push; u32 feerate; u8 channel_flags; struct channel *channel; u8 *remote_upfront_shutdown_script, *local_upfront_shutdown_script; struct per_peer_state *pps; + struct utxo **utxos; log_debug(uc->log, "Got opening_fundee_finish_response"); @@ -729,12 +734,12 @@ static void opening_fundee_finished(struct subd *openingd, &channel_info.remote_fundingkey, &funding_txid, &funding_outnum, - &funding, - &AMOUNT_SAT(0), + &opener_funding, + &accepter_funding, &push, &channel_flags, &feerate, - &funding_signed, + &final_peer_msg, &uc->our_config.channel_reserve, &local_upfront_shutdown_script, &remote_upfront_shutdown_script)) { @@ -756,14 +761,23 @@ static void opening_fundee_finished(struct subd *openingd, goto failed; } + if (!amount_sat_add(&total_funding, opener_funding, accepter_funding)) + abort(); + + if (uc->pf) + /* We steal here, because otherwise gets eaten below */ + utxos = tal_steal(tmpctx, uc->pf->utxos); + else + utxos = NULL; + /* Consumes uc */ channel = wallet_commit_channel(ld, uc, remote_commit, &remote_commit_sig, &funding_txid, funding_outnum, - funding, - AMOUNT_SAT(0), + total_funding, + accepter_funding, push, REMOTE, channel_flags, @@ -774,13 +788,18 @@ static void opening_fundee_finished(struct subd *openingd, if (!channel) { uncommitted_channel_disconnect(uc, LOG_BROKEN, "Commit channel failed"); - goto failed; + goto failed_later; } log_debug(channel->log, "Watching funding tx %s", type_to_string(reply, struct bitcoin_txid, &channel->funding_txid)); + if (utxos) { + // TODO: mark utxos as shared + tal_free(utxos); + } + channel_watch_funding(ld, channel); /* Tell plugins about the success */ @@ -788,13 +807,16 @@ static void opening_fundee_finished(struct subd *openingd, &channel->funding_txid, &channel->remote_funding_locked); /* On to normal operation! */ - peer_start_channeld(channel, pps, funding_signed, false); + peer_start_channeld(channel, pps, final_peer_msg, false); subd_release_channel(openingd, uc); uc->openingd = NULL; tal_free(uc); return; +failed_later: + if (utxos) + tal_free(utxos); failed: close(fds[0]); close(fds[1]); @@ -959,9 +981,9 @@ static void channel_config(struct lightningd *ld, struct openchannel_hook_payload { struct subd *openingd; - struct amount_sat funding_satoshis; /* Is this a v2 openchannel call? */ bool is_v2; + struct amount_sat opener_satoshis; struct amount_msat push_msat; struct amount_sat dust_limit_satoshis; struct amount_msat max_htlc_value_in_flight_msat; @@ -984,7 +1006,7 @@ openchannel_hook_serialize(struct openchannel_hook_payload *payload, json_object_start(stream, "openchannel"); json_add_node_id(stream, "id", &uc->peer->id); json_add_amount_sat_only(stream, "funding_satoshis", - payload->funding_satoshis); + payload->opener_satoshis); json_add_amount_msat_only(stream, "push_msat", payload->push_msat); json_add_amount_sat_only(stream, "dust_limit_satoshis", payload->dust_limit_satoshis); @@ -1013,12 +1035,17 @@ static void openchannel_payload_remove_openingd(struct subd *openingd, } static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS, - const char *buffer, - const jsmntok_t *toks) + const char *buffer, + const jsmntok_t *toks) { struct subd *openingd = payload->openingd; const u8 *our_upfront_shutdown_script; + struct uncommitted_channel *uc = openingd->channel; + struct peer_funding *pf = uc->pf; const char *errmsg = NULL; + struct amount_sat change; + struct bitcoin_tx_output **outputs; + bool has_change; /* We want to free this, whatever happens. */ tal_steal(tmpctx, payload); @@ -1076,12 +1103,115 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS, } else our_upfront_shutdown_script = NULL; } - } else + + if (payload->is_v2 && !errmsg) { + const jsmntok_t *funding_sats = json_get_member(buffer, + toks, + "funding_sats"); + if (funding_sats) + json_to_sat(buffer, funding_sats, &pf->accepter_funding); + else + pf->accepter_funding = AMOUNT_SAT(0); + } + } else { our_upfront_shutdown_script = NULL; + if (pf) + pf->accepter_funding = AMOUNT_SAT(0); + } + + if (!payload->is_v2 || errmsg) { + subd_send_msg(openingd, + take(towire_opening_got_offer_reply(NULL, errmsg, + our_upfront_shutdown_script))); + return; + } + + /* Find utxos for funding this */ + if (amount_sat_greater(pf->accepter_funding, AMOUNT_SAT(0))) { + /* Print a warning if we're trying to fund a channel with more + * than we said that we'd be allowed to */ + if (amount_sat_greater(pf->accepter_funding, payload->available_funds)) + log_info(openingd->log, + "Attempting to fund channel for %s when max was set to %s", + type_to_string( + tmpctx, struct amount_sat, &pf->accepter_funding), + type_to_string( + tmpctx, struct amount_sat, &payload->available_funds)); + + struct amount_sat fee_estimate UNUSED; + pf->utxos = (struct utxo **)wallet_select_coins(pf, openingd->ld->wallet, + true, pf->accepter_funding, + 0, 0, + UINT32_MAX, /* minconf 1 */ + &fee_estimate, &change); + + /* Verify that we're still under the max remote that is allowed */ + if (tal_count(pf->utxos) > REMOTE_CONTRIB_LIMIT) { + log_info(openingd->log, + "Too many utxos selected (%zu), only %"PRIu16" allowed", + tal_count(pf->utxos), REMOTE_CONTRIB_LIMIT - 1); + pf->utxos = tal_free(pf->utxos); + change = AMOUNT_SAT(0); + } + } else { + change = AMOUNT_SAT(0); + pf->utxos = NULL; + } + + /* Either no utxos were found, or we weren't funding it anyway */ + if (!pf->utxos) { + if (amount_sat_greater(pf->accepter_funding, AMOUNT_SAT(0))) + /* FIXME: send notification to the plugin that + * we weren't able to fund this channel as they + * requested; utxo set has changed since hook was called */ + log_unusual(openingd->log, + "Unable to fund channel with %s; utxos unavailable", + type_to_string(tmpctx, struct amount_sat, + &pf->accepter_funding)); + + pf->accepter_funding = AMOUNT_SAT(0); + change = AMOUNT_SAT(0); + } + + has_change = amount_sat_greater(change, AMOUNT_SAT(0)); + outputs = tal_arr(tmpctx, struct bitcoin_tx_output *, has_change ? 1 : 0); + if (has_change) { + struct bitcoin_tx_output *output; + struct pubkey *changekey; + s64 change_keyindex; + + output = tal(outputs, struct bitcoin_tx_output); + output->amount = change; + + change_keyindex = wallet_get_newindex(openingd->ld); + changekey = tal(tmpctx, struct pubkey); + if (!bip32_pubkey(openingd->ld->wallet->bip32_base, + changekey, change_keyindex)) { + fatal("Error deriving change key %lu", change_keyindex); + } + output->script = scriptpubkey_p2wpkh(output, changekey); + outputs[0] = output; + } + + /* We need to supply the scriptSig to our peer, for P2SH wrapped inputs */ + for (size_t i = 0; i < tal_count(pf->utxos); i++) { + if (pf->utxos[i]->is_p2sh) + pf->utxos[i]->scriptSig = + derive_redeem_scriptsig(pf->utxos[i], + openingd->ld->wallet, + pf->utxos[i]->keyindex); + else + pf->utxos[i]->scriptSig = NULL; + + } subd_send_msg(openingd, - take(towire_opening_got_offer_reply(NULL, errmsg, - our_upfront_shutdown_script))); + take(towire_opening_got_offer_reply_fund( + NULL, pf->accepter_funding, + cast_const2(const struct utxo **, pf->utxos), + cast_const2(const struct bitcoin_tx_output **, + outputs), + our_upfront_shutdown_script))); } REGISTER_SINGLE_PLUGIN_HOOK(openchannel, @@ -1107,7 +1237,7 @@ static void opening_got_offer(struct subd *openingd, payload->openingd = openingd; if (!fromwire_opening_got_offer(payload, msg, &payload->is_v2, - &payload->funding_satoshis, + &payload->opener_satoshis, &payload->push_msat, &payload->dust_limit_satoshis, &payload->max_htlc_value_in_flight_msat, @@ -1204,6 +1334,7 @@ static unsigned int openingd_msg(struct subd *openingd, case WIRE_OPENING_FUNDER_COMPLETE: case WIRE_OPENING_FUNDER_CANCEL: case WIRE_OPENING_GOT_OFFER_REPLY: + case WIRE_OPENING_GOT_OFFER_REPLY_FUND: case WIRE_OPENING_DEV_MEMLEAK: /* Replies never get here */ case WIRE_OPENING_DEV_MEMLEAK_REPLY: diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index ac2da0ef69cb..ae15a1713908 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -51,6 +51,16 @@ msgdata,opening_got_offer_reply,rejection,?wirestring, msgdata,opening_got_offer_reply,shutdown_len,u16, msgdata,opening_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len +# master->openingd: we'd like to fund this too, maybe +msgtype,opening_got_offer_reply_fund,6107 +msgdata,opening_got_offer_reply_fund,our_funding,amount_sat, +msgdata,opening_got_offer_reply_fund,num_inputs,u16, +msgdata,opening_got_offer_reply_fund,utxos,utxo,num_inputs +msgdata,opening_got_offer_reply_fund,num_outputs,u16, +msgdata,opening_got_offer_reply_fund,outputs,bitcoin_tx_output,num_outputs +msgdata,opening_got_offer_reply_fund,shutdown_len,u16, +msgdata,opening_got_offer_reply_fund,our_shutdown_scriptpubkey,?u8,shutdown_len + # Openingd->master: we've successfully offered channel. # This gives their sig, means we can broadcast tx: we're done. msgtype,opening_funder_reply,6101 diff --git a/openingd/openingd.c b/openingd/openingd.c index 8947d3982988..3c77b38f2a5b 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1500,6 +1500,515 @@ static u8 *funder_channel_complete(struct state *state, state->upfront_shutdown_script[REMOTE]); } +static bool fundee_check_primitives(struct state *state, + struct bitcoin_blkid chain_hash) +{ + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + * - the `chain_hash` value is set to a hash of a chain + * that is unknown to the receiver. + */ + if (!bitcoin_blkid_eq(&chain_hash, + &chainparams->genesis_blockhash)) { + negotiation_failed(state, false, + "Unknown chain-hash %s", + type_to_string(tmpctx, + struct bitcoin_blkid, + &chain_hash)); + return false; + } + + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + *... + * - `funding_satoshis` is greater than or equal to 2^24 and the receiver does not support + * `option_support_large_channel`. */ + /* We choose to require *negotiation*, not just support! */ + if (!feature_negotiated(state->our_features, state->their_features, + OPT_LARGE_CHANNELS) + && amount_sat_greater(state->opener_funding, chainparams->max_funding)) { + negotiation_failed(state, false, + "funding_satoshis %s too large", + type_to_string(tmpctx, struct amount_sat, + &state->opener_funding)); + return false; + } + + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + * ... + * - `push_msat` is greater than `funding_satoshis` * 1000. + */ + if (amount_msat_greater_sat(state->push_msat, state->opener_funding)) { + peer_failed(state->pps, + &state->channel_id, + "Their push_msat %s" + " would be too large for funding_satoshis %s", + type_to_string(tmpctx, struct amount_msat, + &state->push_msat), + type_to_string(tmpctx, struct amount_sat, + &state->opener_funding)); + return false; + } + + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + *... + * - it considers `feerate_per_kw` too small for timely processing or + * unreasonably large. + */ + if (state->feerate_per_kw < state->min_feerate) { + negotiation_failed(state, false, + "feerate_per_kw %u below minimum %u", + state->feerate_per_kw, state->min_feerate); + return false; + } + + if (state->feerate_per_kw > state->max_feerate) { + negotiation_failed(state, false, + "feerate_per_kw %u above maximum %u", + state->feerate_per_kw, state->max_feerate); + return false; + } + return true; +} + +#if EXPERIMENTAL_FEATURES +static void inputs_to_infos(const tal_t *ctx, struct utxo **utxos, + struct input_info ***input_infos) +{ + size_t i; + + *input_infos = tal_arr(ctx, struct input_info *, tal_count(utxos)); + for (i = 0; i < tal_count(utxos); i++) { + struct input_info *info; + info = tal(*input_infos, struct input_info); + info->input_satoshis = utxos[i]->amount; + info->prevtx_txid = utxos[i]->txid; + info->prevtx_vout = utxos[i]->outnum; + + info->prevtx_scriptpubkey = tal_dup_arr(info, u8, utxos[i]->scriptPubkey, + tal_bytelen(utxos[i]->scriptPubkey), 0); + + /* All our outputs are sig + key (P2WPKH or P2SH-P2WPKH) */ + info->max_witness_len = 1 + 1 + 73 + 1 + 33; + + /* + * BOLT-1a9a018f5e2fa7239ae25f333c0be1f294f6c5e9 + * `input_info`.`script` is the scriptPubkey data for the input. + * NB: for native SegWit inputs (P2WPKH and P2WSH) inputs, the `script` field + * will be empty. + */ + if (tal_count(utxos[i]->scriptSig)) + info->script = tal_dup_arr(info, u8, utxos[i]->scriptSig, + tal_count(utxos[i]->scriptSig), 0); + else + info->script = NULL; + + (*input_infos)[i] = info; + } +} + +static struct output_info **outputs_to_infos(const tal_t *ctx, struct bitcoin_tx_output **outputs) +{ + struct output_info **infos; + size_t i; + + infos = tal_arr(ctx, struct output_info *, tal_count(outputs)); + for (i = 0; i < tal_count(outputs); i++) { + struct output_info *info; + info = tal(infos, struct output_info); + + info->script = tal_dup_arr(info, u8, outputs[i]->script, + tal_count(outputs[i]->script), 0); + info->output_satoshis = outputs[i]->amount; + infos[i] = info; + } + + return infos; +} + +static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) +{ + struct bitcoin_blkid chain_hash; + struct utxo **utxos; + struct bitcoin_tx_output **outputs; + struct input_info **their_inputs, **our_inputs; + struct output_info **their_outputs, **our_outputs; + + char *err_reason; + struct witness_stack **our_stack; + struct bitcoin_txid hsm_funding_txid; + struct bitcoin_tx *funding_tx; + struct bitcoin_signature their_sig, our_sig; + secp256k1_ecdsa_signature *htlc_sigs; + struct bitcoin_tx *local_commit, *remote_commit; + struct amount_sat total_funding, opener_change; + struct amount_msat local_msat; + struct channel_id id_in; + const u8 *wscript; + u8 channel_flags; + u8 *msg; + + struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); + if (!fromwire_open_channel2(open_channel2_msg, + &chain_hash, + &state->channel_id, + &state->opener_funding, + &state->push_msat, + &state->remoteconf.dust_limit, + &state->remoteconf.max_htlc_value_in_flight, + &state->remoteconf.htlc_minimum, + &state->feerate_per_kw, + &state->feerate_per_kw_funding, + &state->remoteconf.to_self_delay, + &state->remoteconf.max_accepted_htlcs, + &state->their_funding_pubkey, + &state->their_points.revocation, + &state->their_points.payment, + &state->their_points.delayed_payment, + &state->their_points.htlc, + &state->first_per_commitment_point[REMOTE], + &channel_flags, + tlv)) + peer_failed(state->pps, NULL, + "Bad open_channel2 %s", + tal_hex(open_channel2_msg, open_channel2_msg)); + + /* Default is no shutdown_scriptpubkey: free any leftover one. */ + state->upfront_shutdown_script[REMOTE] + = tal_free(state->upfront_shutdown_script[REMOTE]); + + if (tlv->option_upfront_shutdown_script && + tlv->option_upfront_shutdown_script->shutdown_scriptpubkey) + state->upfront_shutdown_script[REMOTE] = tal_steal(state, + tlv->option_upfront_shutdown_script->shutdown_scriptpubkey); + + if (!fundee_check_primitives(state, chain_hash)) + return NULL; + + // we do all the reserve checks after we've gotten their amounts + + /* Check with lightningd that we can accept this? In particular, + * if we have an existing channel, we don't support it. */ + msg = towire_opening_got_offer(NULL, + state->use_v2, + state->opener_funding, + state->push_msat, + state->remoteconf.dust_limit, + state->remoteconf.max_htlc_value_in_flight, + AMOUNT_SAT(0), + state->remoteconf.htlc_minimum, + state->feerate_per_kw, + state->feerate_per_kw_funding, + state->remoteconf.to_self_delay, + state->remoteconf.max_accepted_htlcs, + channel_flags, + state->upfront_shutdown_script[REMOTE]); + wire_sync_write(REQ_FD, take(msg)); + msg = wire_sync_read(tmpctx, REQ_FD); + + enum opening_wire_type t = fromwire_peektype(msg); + if (t == WIRE_OPENING_GOT_OFFER_REPLY) { + if (!fromwire_opening_got_offer_reply(tmpctx, msg, &err_reason, + &state->upfront_shutdown_script[LOCAL])) + master_badmsg(WIRE_OPENING_GOT_OFFER_REPLY, msg); + + /* We only call this if there's an error to return */ + if (!err_reason) + err_reason = "Unknown error occurred attempting" + " to open channel."; + + u8 *errmsg = towire_errorfmt(NULL, &state->channel_id, + "%s", err_reason); + sync_crypto_write(state->pps, take(errmsg)); + + /* We exit here. Errored in lightningd */ + return NULL; + + } else if (!fromwire_opening_got_offer_reply_fund(state, msg, + &state->accepter_funding, + &utxos, &outputs, + &state->upfront_shutdown_script[LOCAL])) + master_badmsg(WIRE_OPENING_GOT_OFFER_REPLY_FUND, msg); + + /* This reserves 1% of the channel (rounded up) */ + set_reserve(state); + + /* These checks are the same whether we're opener or accepter... */ + if (!check_config_bounds(state, &state->remoteconf, true)) + return NULL; + + struct tlv_accept_tlvs *accept_tlv = tlv_accept_tlvs_new(tmpctx); + if (state->upfront_shutdown_script[LOCAL]) { + accept_tlv->option_upfront_shutdown_script = tal(tlv, + struct tlv_accept_tlvs_option_upfront_shutdown_script); + accept_tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = + state->upfront_shutdown_script[LOCAL]; + } + + msg = towire_accept_channel2(tmpctx, &state->channel_id, + state->accepter_funding, + state->localconf.dust_limit, + state->localconf.max_htlc_value_in_flight, + state->localconf.htlc_minimum, + state->minimum_depth, + state->localconf.to_self_delay, + state->localconf.max_accepted_htlcs, + &state->our_funding_pubkey, + &state->our_points.revocation, + &state->our_points.payment, + &state->our_points.delayed_payment, + &state->our_points.htlc, + &state->first_per_commitment_point[LOCAL], + accept_tlv); + + sync_crypto_write(state->pps, take(msg)); + + peer_billboard(false, "Incoming channel: accepted, now " + "waiting for them to send funding_compose"); + + msg = opening_negotiate_msg(tmpctx, state, false); + if (!msg) + return NULL; + + /* Convert our inputs/outputs to the correct format */ + inputs_to_infos(state, utxos, &our_inputs); + our_outputs = outputs_to_infos(state, outputs); + + /* The next message should be "funding_compose" which tells us the funding + * inputs and outputs they've selected. */ + if (!fromwire_funding_compose(state, msg, &id_in, + &their_inputs, + &their_outputs)) + peer_failed(state->pps, + &state->channel_id, + "Parsing received funding_compose"); + + check_channel_id(state, &id_in, &state->channel_id); + + if (!check_remote_input_outputs(state, OPENER, + their_inputs, + their_outputs, + state->opener_funding)) + return NULL; + + /* Build the funding tx */ + funding_tx = dual_funding_funding_tx(state, chainparams, + &state->funding_txout, + state->feerate_per_kw_funding, + &state->opener_funding, + state->accepter_funding, + their_inputs, our_inputs, + their_outputs, our_outputs, + &state->our_funding_pubkey, + &state->their_funding_pubkey, + &total_funding, + &opener_change, + NULL); + + if (!funding_tx) + peer_failed(state->pps, + &state->channel_id, + "Opener unable to afford funding transaction"); + + bitcoin_txid(funding_tx, &state->funding_txid); + status_debug("dual funding tx is %s", + type_to_string(tmpctx, struct bitcoin_tx, funding_tx)); + + /* Now we send our inputs/outputs to them */ + msg = towire_funding_compose(tmpctx, &state->channel_id, + cast_const2(const struct input_info **, our_inputs), + cast_const2(const struct output_info **, our_outputs)); + + sync_crypto_write(state->pps, take(msg)); + + peer_billboard(false, "Incoming channel: funding_compose sent," + " now waiting for commitment_signed"); + + msg = opening_negotiate_msg(tmpctx, state, false); + if (!msg) + return NULL; + + their_sig.sighash_type = SIGHASH_ALL; + if (!fromwire_commitment_signed(tmpctx, msg, + &id_in, &their_sig.s, &htlc_sigs)) + peer_failed(state->pps, + &state->channel_id, + "Bad commitment_signed %s", tal_hex(msg, msg)); + + peer_billboard(false, "Incoming channel: commitment_signed received," + " composing funding tx"); + + if (!amount_msat_add_sat(&local_msat, state->push_msat, + state->accepter_funding)) + peer_failed(state->pps, + &state->channel_id, + "Overflow adding our funding %s with push_msat %s", + type_to_string(tmpctx, struct amount_sat, + &state->accepter_funding), + type_to_string(tmpctx, struct amount_msat, + &state->push_msat)); + + bool we_funded = !amount_sat_eq(state->accepter_funding, AMOUNT_SAT(0)); + state->channel = new_initial_channel(state, + &state->funding_txid, + state->funding_txout, + state->minimum_depth, + total_funding, + local_msat, + take(new_fee_states(NULL, REMOTE, + &state->feerate_per_kw)), + &state->localconf, + &state->remoteconf, + &state->our_points, + &state->their_points, + &state->our_funding_pubkey, + &state->their_funding_pubkey, + state->option_static_remotekey, + we_funded, + REMOTE); + + /* We don't expect this to fail, but it does do some additional + * internal sanity checks. */ + if (!state->channel) + peer_failed(state->pps, + &state->channel_id, + "We could not create channel with given config"); + + if (tal_count(htlc_sigs)) + peer_failed(state->pps, + &state->channel_id, + "Peer sent HTLCs with initial commitment signed msg"); + + /* We expect to have switched over to using the funding_tx + * derived channel_id as of now */ + derive_channel_id(&state->channel_id, + &state->funding_txid, state->funding_txout); + + /* If this check fails, we know that they've derived a different funding + * tx than we have */ + check_channel_id(state, &id_in, &state->channel_id); + + /* We create *our* initial commitment transaction, and check the + * signature they sent against that. */ + local_commit = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[LOCAL], + LOCAL, &err_reason); + + if (!local_commit) { + negotiation_failed(state, false, + "Could not meet our fees and reserve: %s", err_reason); + return NULL; + } + + if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey, &their_sig)) + peer_failed(state->pps, + &state->channel_id, + "Bad signature %s on tx %s using key %s", + type_to_string(tmpctx, struct bitcoin_signature, + &their_sig), + type_to_string(tmpctx, struct bitcoin_tx, local_commit), + type_to_string(tmpctx, struct pubkey, + &state->their_funding_pubkey)); + + /* Now we generate our commitment sig for them */ + remote_commit = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[REMOTE], + REMOTE, &err_reason); + + if (!remote_commit) { + negotiation_failed(state, true, + "Could not meet their fees and reserve: %s", err_reason); + } + + msg = towire_hsm_sign_remote_commitment_tx(NULL, + remote_commit, + &state->channel->funding_pubkey[REMOTE], + state->channel->funding, + (const struct witscript **) remote_commit->output_witscripts, + &state->first_per_commitment_point[REMOTE], + state->channel->option_static_remotekey); + + wire_sync_write(HSM_FD, take(msg)); + msg = wire_sync_read(tmpctx, HSM_FD); + if (!fromwire_hsm_sign_tx_reply(msg, &our_sig)) + status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s", + tal_hex(tmpctx, msg)); + + /* We generate our witnesses for the funding tx */ + /* FIXME: update with BOLT ref when included + * - MUST set `witness` to the serialized witness data for each of its + * inputs, in funding transaction order. FIXME: link to funding tx order + */ + msg = towire_hsm_dual_funding_sigs(tmpctx, + cast_const2(const struct utxo **, utxos), + state->feerate_per_kw_funding, + state->opener_funding, + state->accepter_funding, + cast_const2(const struct input_info **, their_inputs), + cast_const2(const struct input_info **, our_inputs), + cast_const2(const struct output_info **, their_outputs), + cast_const2(const struct output_info **, our_outputs), + &state->our_funding_pubkey, + &state->their_funding_pubkey, + REMOTE); + + wire_sync_write(HSM_FD, take(msg)); + msg = wire_sync_read(tmpctx, HSM_FD); + if (!fromwire_hsm_dual_funding_sigs_reply(tmpctx, msg, + &our_stack, + &funding_tx)) { + status_failed(STATUS_FAIL_HSM_IO, + "Bad dual_funding_sigs reply %s", + tal_hex(msg, msg)); + } + + /* Verify that it's the same as openingd computed */ + bitcoin_txid(funding_tx, &hsm_funding_txid); + assert(bitcoin_txid_eq(&hsm_funding_txid, &state->funding_txid)); + + + /* We don't send this ourselves: channeld does, because master needs + * to save state to disk before doing so. */ + assert(our_sig.sighash_type == SIGHASH_ALL); + + msg = towire_accepter_sigs(state, &state->channel_id, + &our_sig.s, + cast_const2(const struct witness_stack **, our_stack)); + + /* we send everything to lightning, who commits things to the database etc. + * lightningd will forward the signatures etc over to channeld, who + * sends the final opening sequence message for us. */ + return towire_opening_fundee(state, + &state->remoteconf, + local_commit, + &their_sig, + 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, + state->opener_funding, + state->accepter_funding, + state->push_msat, + channel_flags, + state->feerate_per_kw, + msg, + state->localconf.channel_reserve, + state->upfront_shutdown_script[LOCAL], + state->upfront_shutdown_script[REMOTE]); +} +#endif /* EXPERIMENTAL_FEATURES */ + /*~ The peer sent us an `open_channel`, that means we're the fundee. */ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) { @@ -1569,76 +2078,8 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) "Bad open_channel %s", tal_hex(open_channel_msg, open_channel_msg)); - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - * - the `chain_hash` value is set to a hash of a chain - * that is unknown to the receiver. - */ - if (!bitcoin_blkid_eq(&chain_hash, &chainparams->genesis_blockhash)) { - negotiation_failed(state, false, - "Unknown chain-hash %s", - type_to_string(tmpctx, - struct bitcoin_blkid, - &chain_hash)); + if (!fundee_check_primitives(state, chain_hash)) return NULL; - } - - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - *... - * - `funding_satoshis` is greater than or equal to 2^24 and the receiver does not support - * `option_support_large_channel`. */ - /* We choose to require *negotiation*, not just support! */ - if (!feature_negotiated(state->our_features, state->their_features, - OPT_LARGE_CHANNELS) - && amount_sat_greater(state->opener_funding, chainparams->max_funding)) { - negotiation_failed(state, false, - "funding_satoshis %s too large", - type_to_string(tmpctx, struct amount_sat, - &state->opener_funding)); - return NULL; - } - - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - * ... - * - `push_msat` is greater than `funding_satoshis` * 1000. - */ - if (amount_msat_greater_sat(state->push_msat, state->opener_funding)) { - peer_failed(state->pps, - &state->channel_id, - "Their push_msat %s" - " would be too large for funding_satoshis %s", - type_to_string(tmpctx, struct amount_msat, - &state->push_msat), - type_to_string(tmpctx, struct amount_sat, - &state->opener_funding)); - return NULL; - } - - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - *... - * - it considers `feerate_per_kw` too small for timely processing or - * unreasonably large. - */ - if (state->feerate_per_kw < state->min_feerate) { - negotiation_failed(state, false, - "feerate_per_kw %u below minimum %u", - state->feerate_per_kw, state->min_feerate); - return NULL; - } - - if (state->feerate_per_kw > state->max_feerate) { - negotiation_failed(state, false, - "feerate_per_kw %u above maximum %u", - state->feerate_per_kw, state->max_feerate); - return NULL; - } /* This reserves 1% of the channel (rounded up) */ set_reserve(state); @@ -1918,8 +2359,18 @@ static u8 *handle_peer_in(struct state *state) enum wire_type t = fromwire_peektype(msg); struct channel_id channel_id; - if (t == WIRE_OPEN_CHANNEL) + if (t == WIRE_OPEN_CHANNEL) { + state->use_v2 = false; + /* This is a v1 open; the accepter will not have a funding amount */ + state->accepter_funding = AMOUNT_SAT(0); return fundee_channel(state, msg); + } +#if EXPERIMENTAL_FEATURES + else if (t == WIRE_OPEN_CHANNEL2) { + state->use_v2 = true; + return fundee_channel2(state, msg); + } +#endif /* EXPERIMENTAL_FEATURES */ #if DEVELOPER /* Handle custommsgs */ @@ -2076,6 +2527,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_OPENING_FUNDER_FAILED: case WIRE_OPENING_GOT_OFFER: case WIRE_OPENING_GOT_OFFER_REPLY: + case WIRE_OPENING_GOT_OFFER_REPLY_FUND: break; } From 6f48337bc8bbaddce1b565ba4563c5d04fd87e74 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 30 Sep 2019 18:34:35 -0500 Subject: [PATCH 035/131] openchannel: add dual-funding fields to hook Adds fields that are only relevant for v2 of openchannel protocol to the openchannel hook. Changelog-Added: Plugins, `openchannel` payload now includes fields for the `version` of the initiated openchannel protocol. v2 requests will include `available_funds` and `feerate_per_kw_funding`, the feerate for the funding tx Changelog-Changed: Plugins, `openchanenl` payload member `funding_satoshis` has been renamed `opener_satoshis` (for version 2 openchannels only) --- lightningd/opening_control.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 578a400b730f..1dcd111ab91d 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1005,8 +1005,13 @@ openchannel_hook_serialize(struct openchannel_hook_payload *payload, struct uncommitted_channel *uc = payload->openingd->channel; json_object_start(stream, "openchannel"); json_add_node_id(stream, "id", &uc->peer->id); - json_add_amount_sat_only(stream, "funding_satoshis", - payload->opener_satoshis); + json_add_string(stream, "version", payload->is_v2 ? "2" : "1"); + if (payload->is_v2) + json_add_amount_sat_only(stream, "opener_satoshis", + payload->opener_satoshis); + else + json_add_amount_sat_only(stream, "funding_satoshis", + payload->opener_satoshis); json_add_amount_msat_only(stream, "push_msat", payload->push_msat); json_add_amount_sat_only(stream, "dust_limit_satoshis", payload->dust_limit_satoshis); @@ -1016,7 +1021,13 @@ openchannel_hook_serialize(struct openchannel_hook_payload *payload, payload->channel_reserve_satoshis); json_add_amount_msat_only(stream, "htlc_minimum_msat", payload->htlc_minimum_msat); + if (payload->is_v2) + json_add_amount_sat_only(stream, "available_funds", + payload->available_funds); json_add_num(stream, "feerate_per_kw", payload->feerate_per_kw); + if (payload->is_v2) + json_add_num(stream, "feerate_per_kw_funding", + payload->feerate_per_kw_funding); json_add_num(stream, "to_self_delay", payload->to_self_delay); json_add_num(stream, "max_accepted_htlcs", payload->max_accepted_htlcs); json_add_num(stream, "channel_flags", payload->channel_flags); From d19c83f5b1dc6191ed83463dad6f170ca78379b8 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 9 Oct 2019 20:38:36 -0500 Subject: [PATCH 036/131] plugins: add documentation for openchannel v2 fields Add documentation for new openchannel fields to doc/PLUGINS.md --- doc/PLUGINS.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index a57a0fcb0b8f..4f4a3e5c22b5 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -694,13 +694,17 @@ and it has passed basic sanity checks: { "openchannel": { "id": "03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f", - "funding_satoshis": "100000000msat", + "version": "2", // v2+ + "opening_satoshis": "100000000msat", // v2+ + "funding_satoshis": "100000000msat", // v1 "push_msat": "0msat", "dust_limit_satoshis": "546000msat", "max_htlc_value_in_flight_msat": "18446744073709551615msat", "channel_reserve_satoshis": "1000000msat", "htlc_minimum_msat": "0msat", + "available_funds": "201000msat", // v2+ "feerate_per_kw": 7500, + "feerate_per_kw_funding": 7500, // v2+ "to_self_delay": 5, "max_accepted_htlcs": 483, "channel_flags": 1 @@ -731,6 +735,18 @@ e.g. Note that `close_to` must be a valid address for the current chain; an invalid address will cause the node to exit with an error. +If this is a version "2" openchannel, then it allows for dual-funding. +A plugin can choose to dual-fund a channel by replying with a `continue` +message that contains a `funding_sats` field e.g.: + +```json +{ + "result": "continue", + "funding_sats": "100000sat" + ... +} +``` + ### `htlc_accepted` The `htlc_accepted` hook is called whenever an incoming HTLC is accepted, and From 3fddfecb233f0f2b87bd7eecbebdaf9eb02f1303 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 13 Nov 2019 16:36:17 -0600 Subject: [PATCH 037/131] passback error on overflow replace assert with a passback error ``` it's a bad habit to wrap active code in assert(), because if you define NDEBUG, assert() vanishes along with its contents. prefer a simple if(!xxx) abort(); or status_failed(). ``` Requested-By: @rustyrussell --- common/funding_tx.c | 76 ++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index bfae733215c3..04e109ce9f18 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -60,12 +60,14 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, #if EXPERIMENTAL_FEATURES /* We leave out the change addresses if there's no change left after fees */ -static size_t calculate_input_weights(struct input_info **inputs, - struct amount_sat *total) +/* Returns true if calculated without error, false on overflow */ +static bool calculate_input_weights(struct input_info **inputs, + struct amount_sat *total, + size_t *weight) { - u32 input_weight; u64 scriptlen; - size_t weight = 0, i = 0; + u32 input_weight; + size_t i; *total = AMOUNT_SAT(0); for (i = 0; i < tal_count(inputs); i++) { @@ -81,12 +83,13 @@ static size_t calculate_input_weights(struct input_info **inputs, } input_weight += inputs[i]->max_witness_len; - weight += input_weight; + *weight += input_weight; - assert(amount_sat_add(total, *total, inputs[i]->input_satoshis)); + if (!amount_sat_add(total, *total, inputs[i]->input_satoshis)) + return false; } - return weight; + return true; } static size_t calculate_output_weights(struct output_info **outputs) @@ -102,32 +105,35 @@ static size_t calculate_output_weights(struct output_info **outputs) return output_weights; } -static size_t calculate_weight(struct input_info **opener_inputs, - struct input_info **accepter_inputs, - struct output_info **opener_outputs, - struct output_info **accepter_outputs, - struct amount_sat *opener_total, - struct amount_sat *accepter_total) +/* Returns true if calculated without error, false on overflow */ +static bool calculate_weight(struct input_info **opener_inputs, + struct input_info **accepter_inputs, + struct output_info **opener_outputs, + struct output_info **accepter_outputs, + struct amount_sat *opener_total, + struct amount_sat *accepter_total, + size_t *weight) { - size_t weight; - /* version, input count, output count, locktime */ - weight = (4 + 1 + 1 + 4) * 4; + *weight = (4 + 1 + 1 + 4) * 4; /* add segwit fields: marker + flag */ - weight += 1 + 1; + *weight += 1 + 1; + + if (!calculate_input_weights(opener_inputs, opener_total, weight)) + return false; - weight += calculate_input_weights(opener_inputs, opener_total); - weight += calculate_input_weights(accepter_inputs, accepter_total); + if (!calculate_input_weights(accepter_inputs, accepter_total, weight)) + return false; /* channel funding output: amount, len, scriptpubkey */ - weight += (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WSH_LEN) * 4; + *weight += (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WSH_LEN) * 4; - weight += calculate_output_weights(opener_outputs); - weight += calculate_output_weights(accepter_outputs); + *weight += calculate_output_weights(opener_outputs); + *weight += calculate_output_weights(accepter_outputs); - return weight; + return true; } static const struct output_info *find_change_output(struct output_info **outputs) @@ -140,15 +146,16 @@ static const struct output_info *find_change_output(struct output_info **outputs return NULL; } -static struct amount_sat calculate_output_value(struct output_info **outputs) +static bool calculate_output_value(struct output_info **outputs, + struct amount_sat *total) { size_t i = 0; - struct amount_sat total = AMOUNT_SAT(0); for (i = 0; i < tal_count(outputs); i++) { - assert(amount_sat_add(&total, total, outputs[i]->output_satoshis)); + if (!amount_sat_add(total, *total, outputs[i]->output_satoshis)) + return false; } - return total; + return true; } static void add_inputs(struct bitcoin_tx *tx, struct input_info **inputs) @@ -200,7 +207,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, struct amount_sat *opener_change, const void **input_map) { - size_t weight; + size_t weight = 0; struct amount_sat funding_tx_fee, opener_total_sat, accepter_total_sat, output_val; struct bitcoin_tx *tx; @@ -212,9 +219,12 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, u8 *wscript; /* First, we calculate the weight of the transaction, with change outputs */ - weight = calculate_weight(opener_inputs, accepter_inputs, - opener_outputs, accepter_outputs, - &opener_total_sat, &accepter_total_sat); + if (!calculate_weight(opener_inputs, accepter_inputs, + opener_outputs, accepter_outputs, + &opener_total_sat, &accepter_total_sat, + &weight)) + return NULL; + funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); if (!amount_sat_sub(opener_change, opener_total_sat, *opener_funding)) @@ -225,7 +235,9 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, * outputs, as they might be other funding transaction outputs. The * only 'flexible' / change output that's removable etc is indicated * by a zero value. */ - output_val = calculate_output_value(opener_outputs); + output_val = AMOUNT_SAT(0); + if (!calculate_output_value(opener_outputs, &output_val)) + return NULL; if (!amount_sat_sub(opener_change, *opener_change, output_val)) return NULL; From 70692cfcaf1ece2b51a19143d4e47774d9bee2c6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 13 Nov 2019 16:47:44 -0600 Subject: [PATCH 038/131] no-asserts: move sat addition logic out of asserts Asserts can be stripped at compile time Reported-By: @rustyrussell --- common/funding_tx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 04e109ce9f18..ddd2a0c5c2f0 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -247,8 +247,9 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, if (!change_output) { /* If there's no change output, we put the remainder into * the funding output. TODO: add to spec */ - assert(amount_sat_add(opener_funding, - *opener_funding, *opener_change)); + if (!amount_sat_add(opener_funding, *opener_funding, + *opener_change)) + return NULL; *opener_change = AMOUNT_SAT(0); } @@ -263,7 +264,8 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, /* Any left over gets added to the funding output */ if (amount_sat_sub(opener_change, *opener_change, funding_tx_fee)) { - assert(amount_sat_add(opener_funding, *opener_funding, *opener_change)); + if (!amount_sat_add(opener_funding, *opener_funding, *opener_change)) + return NULL; *opener_change = AMOUNT_SAT(0); goto build_tx; } @@ -296,7 +298,8 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, tal_hex(wscript, wscript)); *total_funding = *opener_funding; - assert(amount_sat_add(total_funding, *total_funding, accepter_funding)); + if (!amount_sat_add(total_funding, *total_funding, accepter_funding)) + return NULL; /* Last check, make sure our funding output is greater than * the dust limit */ From ef0327ca96e16b76e403f8e2dca3a88d1489311d Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 14 Nov 2019 10:38:17 -0600 Subject: [PATCH 039/131] bitcoin_tx: add helper for extracting output amount --- bitcoin/tx.c | 6 ++++++ bitcoin/tx.h | 7 +++++++ lightningd/opening_control.c | 4 +--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/bitcoin/tx.c b/bitcoin/tx.c index a24145a4a9ca..27988bde1d3c 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -238,6 +238,12 @@ const u8 *bitcoin_tx_output_get_script(const tal_t *ctx, return res; } +void bitcoin_tx_output_get_amount_sat(struct bitcoin_tx *tx, int outnum, + struct amount_sat *amount) +{ + amount->satoshis = tx->wtx->outputs[outnum].satoshi; /* Raw: type conversion */ +} + /* FIXME(cdecker) Make the caller pass in a reference to amount_asset, and * return false if unintelligible/encrypted. (WARN UNUSED). */ struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx, diff --git a/bitcoin/tx.h b/bitcoin/tx.h index c8f2b6da2807..cac9193366a4 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -121,6 +121,13 @@ void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum, */ const u8 *bitcoin_tx_output_get_script(const tal_t *ctx, const struct bitcoin_tx *tx, int outnum); +/** bitcoin_tx_output_get_amount_sat - Helper to get transaction output's amount + * + * Internally we use a `wally_tx` to represent the transaction. The + * satoshi amount isn't a struct amount_sat, so we need a conversion + */ +void bitcoin_tx_output_get_amount_sat(struct bitcoin_tx *tx, int outnum, + struct amount_sat *amount); /** * Helper to just get an amount_sat for the output amount. */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 1dcd111ab91d..a6087d5a9e21 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -567,9 +567,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, } - /* Pull out the funding amount */ - total_funding.satoshis /* Raw: type conversion */ - = utx->tx->wtx->outputs[funding_txout].satoshi; /* Raw: type conversion */ + bitcoin_tx_output_get_amount_sat(utx->tx, funding_txout, &total_funding); bitcoin_txid(funding_tx, &funding_txid); /* Consumes uc */ From 42e5a5b8967ac542bf3dde0dc2ae6bc0f60cdc16 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 14 Nov 2019 10:45:29 -0600 Subject: [PATCH 040/131] df: report overflows in remote inputs/outputs as peer err Use `peer_failed`, not `status_failed`, as overflow values from peer is a distinctly peer error. Reported-By: @rustyrussell --- openingd/openingd.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 3c77b38f2a5b..ce080c1c4a24 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -898,25 +898,24 @@ static void derive_input_output_info(const tal_t *ctx, } } -static bool check_remote_inputs(struct input_info **remote_inputs, +static bool check_remote_inputs(struct state *state, + struct input_info **remote_inputs, struct amount_sat *input_funding) { size_t i = 0; - // FIXME: we should check that they don't also - // turn in the funding output - // and maybe check that none of their outputs - // are duplicates?? + // FIXME: we should check that they don't include the funding output + // and maybe check that none of their outputs are duplicates?? *input_funding = AMOUNT_SAT(0); for (i = 0; i < tal_count(remote_inputs); i++) { if (!amount_sat_add(input_funding, *input_funding, remote_inputs[i]->input_satoshis)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Overflow in remote input amount %s + %s", - type_to_string(tmpctx, struct amount_sat, - &remote_inputs[i]->input_satoshis), - type_to_string(tmpctx, struct amount_sat, - input_funding)); + peer_failed(state->pps, &state->channel_id, + "Overflow in remote input amounts %s + %s", + type_to_string(tmpctx, struct amount_sat, + &remote_inputs[i]->input_satoshis), + type_to_string(tmpctx, struct amount_sat, + input_funding)); /** TODO: add BOLT reference when merged * - MUST ensure each `input_info` refers to a non-malleable (segwit) UTXO. */ /* P2SH wrapped inputs send the redeemscript, which we can check */ @@ -974,7 +973,7 @@ static bool check_remote_input_outputs(struct state *state, REMOTE_CONTRIB_LIMIT); } - if (!check_remote_inputs(remote_inputs, &funding)) + if (!check_remote_inputs(state, remote_inputs, &funding)) peer_failed(state->pps, &state->channel_id, "Peer sent malleable (non-Segwit) input."); @@ -991,12 +990,12 @@ static bool check_remote_input_outputs(struct state *state, has_change_address = true; } if (!amount_sat_add(&other_outputs, other_outputs, remote_outputs[i]->output_satoshis)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Overflow in remote outher_outputs satoshis %s + %s", - type_to_string(tmpctx, struct amount_sat, - &other_outputs), - type_to_string(tmpctx, struct amount_sat, - &remote_outputs[i]->output_satoshis)); + peer_failed(state->pps, &state->channel_id, + "Overflow in remote output satoshi sum %s + %s", + type_to_string(tmpctx, struct amount_sat, + &other_outputs), + type_to_string(tmpctx, struct amount_sat, + &remote_outputs[i]->output_satoshis)); /* TODO: add BOLT reference when merged * - MUST ensure the `output_info`.`script` is a standard script From 412fde8f79bf8a07bc2eab0664088372c0ea2f65 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 14 Nov 2019 10:53:47 -0600 Subject: [PATCH 041/131] openchannel: make open_channel_version a number, not a string Feedback on review was to make this an int value, not a string. --- lightningd/opening_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a6087d5a9e21..979e627c4319 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -353,7 +353,7 @@ static void funding_started_success(struct funding_channel *fc, json_add_hex_talarr(response, "close_to", fc->our_upfront_shutdown_script); } - json_add_string(response, "open_channel_version", fc->is_v2 ? "2" : "1"); + json_add_num(response, "open_channel_version", fc->is_v2 ? 2 : 1); /* Clear this so cancel doesn't think it's still in progress */ fc->cmd = NULL; From 665454a73aff323221b1c4a831cddd3a8f7cda70 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 14 Nov 2019 11:40:23 -0600 Subject: [PATCH 042/131] df: update BOLT refs to match PR also include a few more fixme's for outstanding work --- common/funding_tx.c | 1 + lightningd/opening_control.c | 7 +- openingd/channel_establishment.h | 25 +++++- openingd/openingd.c | 133 ++++++++++++++++++++----------- 4 files changed, 116 insertions(+), 50 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index ddd2a0c5c2f0..35f429daad43 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -328,6 +328,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, /* Sort outputs */ permute_outputs(tx, NULL, o_map); + /* Set funding_output index for caller */ for (i = 0; i < output_count; i++) { if (o_map[i] == int2ptr(0)) { if (outnum) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 979e627c4319..4ec5b723f3ac 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1155,10 +1155,10 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS, &fee_estimate, &change); /* Verify that we're still under the max remote that is allowed */ - if (tal_count(pf->utxos) > REMOTE_CONTRIB_LIMIT) { + if (tal_count(pf->utxos) > REMOTE_ACCEPTER_INPUT_LIMIT) { log_info(openingd->log, "Too many utxos selected (%zu), only %"PRIu16" allowed", - tal_count(pf->utxos), REMOTE_CONTRIB_LIMIT - 1); + tal_count(pf->utxos), REMOTE_ACCEPTER_INPUT_LIMIT); pf->utxos = tal_free(pf->utxos); change = AMOUNT_SAT(0); } @@ -1270,8 +1270,7 @@ static void opening_got_offer(struct subd *openingd, /* We use one less than the contribution count limit * to leave room for a change output */ wallet_compute_max(openingd->ld->wallet, - /* Leave space for change */ - REMOTE_CONTRIB_LIMIT - 1, + REMOTE_ACCEPTER_INPUT_LIMIT, &payload->available_funds); } else uc->pf = NULL; diff --git a/openingd/channel_establishment.h b/openingd/channel_establishment.h index 71bc0cb42ee3..c821b14bcda7 100644 --- a/openingd/channel_establishment.h +++ b/openingd/channel_establishment.h @@ -2,7 +2,30 @@ #define LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H #include -#define REMOTE_CONTRIB_LIMIT 4 +/** + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `opener`: + * ... + * - MUST NOT send a total count of more than 64 inputs, + * across all `funding_add_input` messages. + */ +#define REMOTE_OPENER_INPUT_LIMIT 64 + +/* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * + * - if is the `accepter`: + * ... + * - MUST NOT send a total count of more than 16 inputs, + * across all `funding_add_input` messages. + */ +#define REMOTE_ACCEPTER_INPUT_LIMIT 16 + +/* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `accepter`: + * - MUST NOT send a total count of more than 8 outputs, + * across all `funding_add_output` messages. + */ +#define REMOTE_OUTPUT_LIMIT 8 /* Designator for flagging what role a peer * is playing in channel establishment (v2) diff --git a/openingd/openingd.c b/openingd/openingd.c index ce080c1c4a24..f6073c31eda0 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -616,7 +616,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) } /* For now, we use the same feerate for funding + commitment tx */ - /* FIXME: allow these to be done separately? */ + /* FIXME: allow these to be set separately */ state->feerate_per_kw_funding = state->feerate_per_kw; msg = towire_open_channel2(NULL, &chainparams->genesis_blockhash, @@ -862,10 +862,11 @@ static void derive_input_output_info(const tal_t *ctx, in->max_witness_len = 1 + 1 + 73 + 1 + 33; /* - * FIXME: add BOLT reference when merged. - * `input_info`.`script` is the scriptPubkey data for the input. - * NB: for native SegWit inputs (P2WPKH and P2WSH) inputs, the `script` field - * will be empty. + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * `input_info`.`script` is the scriptSig field for the input. Only applicable + * for P2SH-wrapped inputs. + * Native SegWit inputs (P2WPKH and P2WSH) inputs, will have + * an empty `script` field */ if (utxos[i]->is_p2sh) { in->script = tal_arr(in, u8, tx->wtx->inputs[i].script_len); @@ -885,7 +886,7 @@ static void derive_input_output_info(const tal_t *ctx, wo = tx->wtx->outputs[i]; /* This is a hack that excludes P2WSH outputs - * which for us, now are exclusively funding outputs */ + * which for our implementation, are funding outputs */ if (exclude_funding_output && wo.script_len == 34) continue; @@ -904,8 +905,13 @@ static bool check_remote_inputs(struct state *state, { size_t i = 0; - // FIXME: we should check that they don't include the funding output - // and maybe check that none of their outputs are duplicates?? + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * The sending node: + * ... + * - MUST NOT re-transmit inputs it has already received from the peer + */ + // FIXME(nifty): check this ^^^ *input_funding = AMOUNT_SAT(0); for (i = 0; i < tal_count(remote_inputs); i++) { @@ -916,8 +922,9 @@ static bool check_remote_inputs(struct state *state, &remote_inputs[i]->input_satoshis), type_to_string(tmpctx, struct amount_sat, input_funding)); - /** TODO: add BOLT reference when merged - * - MUST ensure each `input_info` refers to a non-malleable (segwit) UTXO. */ + + /** BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - MUST ensure each `input_info` refers to a non-malleable (segwit) UTXO. */ /* P2SH wrapped inputs send the redeemscript, which we can check */ if (remote_inputs[i]->script) { if (!is_p2wpkh(remote_inputs[i]->script, NULL) @@ -943,34 +950,50 @@ static bool check_remote_input_outputs(struct state *state, struct amount_sat funding, other_outputs, funding_tx_sats; bool has_change_address; - /** - * BOLT-737016aef544011f385a9e081f85eca34eb61ab6 - * - if is the `opener`: - * - MUST NOT send zero inputs (`num_inputs` cannot be zero). - */ if (remote_role == OPENER) { + /** + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `opener`: + * - MUST send at least one `funding_add_input` message + * - MUST NOT send a total count of more than 64 inputs, + * across all `funding_add_input` messages. + */ if (!tal_count(remote_inputs)) peer_failed(state->pps, &state->channel_id, "Opener sent no funding inputs"); + + if (tal_count(remote_inputs) > REMOTE_OPENER_INPUT_LIMIT) + peer_failed(state->pps, + &state->channel_id, + "Opener sent no funding inputs"); } else { /** - * BOLT-737016aef544011f385a9e081f85eca34eb61ab6 + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - if is the `accepter`: - * - consider the `contribution count` the total of their `num_inputs` plus - * `num_outputs' - * - MUST NOT send a `funding_compose` message where the `contribution count` - * exceeds the limit of 4. + * - MUST NOT send a total count of more than 16 inputs, across + * all `funding_add_input` messages. */ - if (tal_count(remote_inputs) + tal_count(remote_outputs) > REMOTE_CONTRIB_LIMIT) + if (tal_count(remote_inputs) > REMOTE_ACCEPTER_INPUT_LIMIT) peer_failed(state->pps, &state->channel_id, - "Too many remote contributions. " - "Received %ld inputs, %ld outputs; " - "max allowed is %d", + "Too many inputs added. " + "Received %ld inputs, max allowed is %d", tal_count(remote_inputs), + REMOTE_ACCEPTER_INPUT_LIMIT); + + /* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `accepter`: + * - MUST NOT send a total count of more than 8 outputs, + * across all `funding_add_output` messages. + */ + if (tal_count(remote_outputs) > REMOTE_OUTPUT_LIMIT) + peer_failed(state->pps, + &state->channel_id, + "Too many outputs added. " + "Received %ld outputs, max allowed is %d", tal_count(remote_outputs), - REMOTE_CONTRIB_LIMIT); + REMOTE_OUTPUT_LIMIT); } if (!check_remote_inputs(state, remote_inputs, &funding)) @@ -981,13 +1004,21 @@ static bool check_remote_input_outputs(struct state *state, other_outputs = AMOUNT_SAT(0); has_change_address = false; for (i = 0; i < tal_count(remote_outputs); i++) { - if (amount_sat_eq(AMOUNT_SAT(0), remote_outputs[i]->output_satoshis)) { - if (has_change_address) - peer_failed(state->pps, - &state->channel_id, - "Peer sent more than one change outputs."); - - has_change_address = true; + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `opener`: + * - MAY specify an output with value zero, which will be used + * as the change address for any resulting funds after fees are deducted + */ + if (remote_role == OPENER) { + if (amount_sat_eq(AMOUNT_SAT(0), remote_outputs[i]->output_satoshis)) { + if (has_change_address) + peer_failed(state->pps, + &state->channel_id, + "Peer sent more than one change output."); + + has_change_address = true; + } } if (!amount_sat_add(&other_outputs, other_outputs, remote_outputs[i]->output_satoshis)) peer_failed(state->pps, &state->channel_id, @@ -997,7 +1028,8 @@ static bool check_remote_input_outputs(struct state *state, type_to_string(tmpctx, struct amount_sat, &remote_outputs[i]->output_satoshis)); - /* TODO: add BOLT reference when merged + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - MUST ensure the `output_info`.`script` is a standard script */ if (!is_known_scripttype(remote_outputs[i]->script)) @@ -1005,17 +1037,27 @@ static bool check_remote_input_outputs(struct state *state, &state->channel_id, "Peer sent non-standard output script."); + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - MUST NOT include the channel funding output. + */ + // FIXME(nifty): check this ^^^ + } - /** TODO: add BOLT reference when merged + /** + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * The receiving node: - * - if the total `input_info`.`satoshis` is less than the total `output_info`.`satoshis` - * - MUST fail the channel. + * - MUST fail the channel if: + * ... + * - the total satoshis of the senders inputs is less than their outputs plus + * the `funding_satoshis`, specified earlier */ if (!amount_sat_sub(&funding_tx_sats, funding, other_outputs)) peer_failed(state->pps, &state->channel_id, - "Total remote input satoshi less than output satoshis. change:%s inputs:%s", + "Total remote input satoshi less than output satoshis. " + "change:%s inputs:%s", type_to_string(tmpctx, struct amount_sat, &other_outputs), type_to_string(tmpctx, struct amount_sat, @@ -1597,10 +1639,10 @@ static void inputs_to_infos(const tal_t *ctx, struct utxo **utxos, info->max_witness_len = 1 + 1 + 73 + 1 + 33; /* - * BOLT-1a9a018f5e2fa7239ae25f333c0be1f294f6c5e9 - * `input_info`.`script` is the scriptPubkey data for the input. - * NB: for native SegWit inputs (P2WPKH and P2WSH) inputs, the `script` field - * will be empty. + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * + * `input_info`.`script` is the scriptSig field for the input. Only applicable + * for P2SH-wrapped inputs. */ if (tal_count(utxos[i]->scriptSig)) info->script = tal_dup_arr(info, u8, utxos[i]->scriptSig, @@ -1939,11 +1981,12 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s", tal_hex(tmpctx, msg)); - /* We generate our witnesses for the funding tx */ - /* FIXME: update with BOLT ref when included - * - MUST set `witness` to the serialized witness data for each of its - * inputs, in funding transaction order. FIXME: link to funding tx order + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - MUST set `witness` to the serialized witness data for the input + * corresponding to `prevtx_txid`:`prevtx_vout` */ + /* We generate our witnesses for the funding tx */ msg = towire_hsm_dual_funding_sigs(tmpctx, cast_const2(const struct utxo **, utxos), state->feerate_per_kw_funding, From 55beabeb62f981d0f62cde6d45666c7efe90001f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 15 Nov 2019 17:27:54 -0600 Subject: [PATCH 043/131] df: add BOLT references for dual funding to funding_tx + test --- common/funding_tx.c | 113 ++++++++++++++++++++++++------ common/test/run-funding_tx_dual.c | 58 ++++++++++++++- 2 files changed, 149 insertions(+), 22 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 35f429daad43..76ce67960d62 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -69,6 +69,18 @@ static bool calculate_input_weights(struct input_info **inputs, u32 input_weight; size_t i; + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * The *expected weight* of a funding transaction is calculated as follows: + * inputs: 40 bytes + var_int + `scriptlen` + * - previous_out_point: 36 bytes + * - hash: 32 bytes + * - index: 4 bytes + * - var_int: ? bytes (dependent on `scriptlen`) + * - script_sig: `scriptlen` + * - witness <---- Cost for "witness" data calculated separately. + * - sequence: 4 bytes + */ *total = AMOUNT_SAT(0); for (i = 0; i < tal_count(inputs); i++) { /* prev_out hash + index + sequence */ @@ -96,6 +108,15 @@ static size_t calculate_output_weights(struct output_info **outputs) { size_t i, output_weights = 0, scriptlen; + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * The *expected weight* of a funding transaction is calculated as follows: + * ... + * non_funding_outputs: 8 bytes + var_int + `scriptlen` + * - value: 8 bytes + * - var_int: ? bytes (dependent on `scriptlen`) + * - script_sig: `scriptlen` + */ for (i = 0; i < tal_count(outputs); i++) { scriptlen = tal_bytelen(outputs[i]->script); /* amount field + script + scriptlen varint */ @@ -127,7 +148,15 @@ static bool calculate_weight(struct input_info **opener_inputs, if (!calculate_input_weights(accepter_inputs, accepter_total, weight)) return false; - /* channel funding output: amount, len, scriptpubkey */ + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * The *expected weight* of a funding transaction is calculated as follows: + * ... + * funding_output: 43 bytes + * - value: 8 bytes + * - var_int: 1 byte + * - script: 34 bytes + */ *weight += (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WSH_LEN) * 4; *weight += calculate_output_weights(opener_outputs); @@ -208,7 +237,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, const void **input_map) { size_t weight = 0; - struct amount_sat funding_tx_fee, opener_total_sat, + struct amount_sat est_tx_fee, opener_total_sat, accepter_total_sat, output_val; struct bitcoin_tx *tx; const struct output_info *change_output; @@ -225,11 +254,18 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, &weight)) return NULL; - funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); - + /* Does the opener provide enough sats to cover their funding */ if (!amount_sat_sub(opener_change, opener_total_sat, *opener_funding)) return NULL; + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * - MUST calculate the `est_tx_fee` as: + * 1. Multiply (funding_transaction_weight + witness_weight) by `feerate_per_kw_funding` + * and divide by 1000 (rounding down). + */ + est_tx_fee = amount_tx_fee(feerate_kw_funding, weight); + /* Check that the remaining amount at least covers the other * indicated output values. We have to cover these other * outputs, as they might be other funding transaction outputs. The @@ -241,12 +277,31 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, if (!amount_sat_sub(opener_change, *opener_change, output_val)) return NULL; + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * For channel establishment v2, fees are paid by the opener (the node that + * sends the `open_channel` message). Change, if any, is paid to the + * opener's change address, a zero value output in their output set. + */ change_output = find_change_output(opener_outputs); - if (amount_sat_sub(opener_change, *opener_change, funding_tx_fee) && + + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * - MUST calculate the `est_tx_fee` as: + * ... + * 2. Confirm that `change_satoshis` is greater than `dust_limit_satoshis`. + */ + if (amount_sat_sub(opener_change, *opener_change, est_tx_fee) && amount_sat_greater(*opener_change, chainparams->dust_limit)) { if (!change_output) { - /* If there's no change output, we put the remainder into - * the funding output. TODO: add to spec */ + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * - if no change address is provided or `change_satoshis` is less + * than or equal to the negotiated `dust_limit_satoshis`: + * ... + * 2. As there is no change_output, any remaining `change_satoshis` + * will be added to the funding output, and credited to the opener's + * initial channel balance. */ if (!amount_sat_add(opener_funding, *opener_funding, *opener_change)) return NULL; @@ -256,14 +311,23 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, goto build_tx; } - /* Try removing opener's change output to fit fees */ - if (change_output) { + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * - if ... `change_satoshis` is less than or equal to the + * negotiated `dust_limit_satoshis`: + * - MUST calculate the `est_tx_fee` without the change output (if provided) as: + */ + if (change_output) { scriptlen = tal_count(change_output->script); weight -= (8 + scriptlen + varint_size(scriptlen)) * 4; - funding_tx_fee = amount_tx_fee(feerate_kw_funding, weight); - - /* Any left over gets added to the funding output */ - if (amount_sat_sub(opener_change, *opener_change, funding_tx_fee)) { + est_tx_fee = amount_tx_fee(feerate_kw_funding, weight); + + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * 2. As there is no change_output, any remaining `change_satoshis` + * will be added to the funding output, and credited to the opener's + * initial channel balance. */ + if (amount_sat_sub(opener_change, *opener_change, est_tx_fee)) { if (!amount_sat_add(opener_funding, *opener_funding, *opener_change)) return NULL; *opener_change = AMOUNT_SAT(0); @@ -271,7 +335,12 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, } } - if (!amount_sat_sub(opener_funding, opener_total_sat, funding_tx_fee) || + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * - if the resulting `change_satoshis` is less than zero: + * - sum(`funding_satoshis`) will be decreased by the difference. + */ + if (!amount_sat_sub(opener_funding, opener_total_sat, est_tx_fee) || !amount_sat_sub(opener_funding, *opener_funding, output_val)) return NULL; @@ -283,10 +352,11 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, output_count = tal_count(opener_outputs) + tal_count(accepter_outputs) + 1; - /* If they had supplied a change output, but we removed it because + /* If they had supplied a change output, but we removed it because of fees, * remove it from the count */ if (change_output && amount_sat_eq(AMOUNT_SAT(0), *opener_change)) { output_count -= 1; + /* There should at least be a funding output */ assert(output_count > 0); } @@ -294,19 +364,22 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, /* Add the funding output */ wscript = bitcoin_redeem_2of2(tx, local_fundingkey, remote_fundingkey); - SUPERVERBOSE("# funding witness script = %s\n", - tal_hex(wscript, wscript)); + SUPERVERBOSE("# funding witness script = %s\n", tal_hex(wscript, wscript)); *total_funding = *opener_funding; if (!amount_sat_add(total_funding, *total_funding, accepter_funding)) return NULL; - /* Last check, make sure our funding output is greater than - * the dust limit */ + /* + * BOLT-82ccaed20022ddf3eb7927052429f6551e8dac45 #2 + * + * - if the `funding_output` of the resulting transaction is less than + * the `dust_limit` ([BOLT #3: Calculating `est_tx_fee`](03-transactions.md#channel-establishment-v2-funding-transaction-fees)): + * - MUST fail the channel + */ if (!amount_sat_greater(*total_funding, chainparams->dust_limit)) return NULL; - const void *o_map[output_count]; for (i = 0; i < output_count; i++) o_map[i] = int2ptr(i); diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index 4d32b2464607..eca0dc8408c3 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -98,8 +98,62 @@ static u8 *hex_to_u8(const tal_t *ctx, char *str) return tal_hexdata(ctx, str, strlen(str)); } -/* Test case from the 03 Appendix F, in the RFC */ -/* FIXME: add bolt reference for this */ +/* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 + * # Appendix F: Dual Funded Transaction Test Vectors + * ... + * Expected Opener's `funding_compose.input_info` (inputs 0+1 above): + * ``` + * num_inputs: 2 + * input_info:[ + * { + * satoshis: 250000000, + * prev_txid: 4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9, + * prev_vout: 0, + * prev_scriptpubkey_len: 34, + * prev_scriptpubkey: 0020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946, + * max_witness_len: 75, + * scriptlen: 0, + * script: null + * },{ + * satoshis: 250000000, + * prev_txid: 4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9, + * prev_vout: 1, + * prev_scriptpubkey_len: 23, + * prev_scriptpubkey: a9146a235d064786b49e7043e4a042d4cc429f7eb69487, + * max_witness_len: 75, + * scriptlen: 34, + * script: 0020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946 + * } + * ] + * ``` + * + * Expected Accepter's `funding_compose.input_info` (inputs 2+3 above): + * ``` + * num_inputs: 2 + * input_info:[ + * { + * satoshis: 250000000, + * prev_txid: 4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9, + * prev_vout: 2, + * prev_scriptpubkey_len: 22, + * prev_scriptpubkey: 0014fbb4db9d85fba5e301f4399e3038928e44e37d32, + * max_witness_len: 109, + * scriptlen: 0, + * script: null + * },{ + * satoshis: 250000000, + * prev_txid: 4303ca8ff10c6c345b9299672a66f111c5b81ae027cc5b0d4d39d09c66b032b9, + * prev_vout: 3, + * prev_scriptpubkey_len: 23, + * prev_scriptpubkey: a9147ecd1b519326bc13b0ec716e469b58ed02b112a087, + * max_witness_len: 109, + * scriptlen: 22, + * script: 0014fbb4db9d85fba5e301f4399e3038928e44e37d32 + * } + *] + *``` +*/ static struct test_case test1(const tal_t *ctx) { struct bitcoin_txid txid; From 9e57c88c7279af42ccffcf0cbfc99bfbe125d2a9 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 19 Nov 2019 17:25:06 -0600 Subject: [PATCH 044/131] DB: do not swallow error on channel load --- wallet/wallet.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wallet/wallet.c b/wallet/wallet.c index 0845095c446c..9d451e1c1989 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1197,6 +1197,12 @@ static bool wallet_channels_load_active(struct wallet *w) } count++; } + + if (stmt->error) { + log_broken(w->log, "Error loading channels: %s", stmt->error); + ok = false; + } + log_debug(w->log, "Loaded %d channels from DB", count); tal_free(stmt); return ok; From c9e494192882c49d1f60ae9498724b572d16e254 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 21 Nov 2019 15:46:39 -0600 Subject: [PATCH 045/131] df: check that inputs are unique if peer sends inputs that we sent, fail --- openingd/openingd.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index f6073c31eda0..782e24fe8c20 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -899,22 +899,39 @@ static void derive_input_output_info(const tal_t *ctx, } } +static bool inputs_eq(const struct input_info *a, const struct input_info *b) +{ + return bitcoin_txid_eq(&a->prevtx_txid, &b->prevtx_txid) + && a->prevtx_vout == b->prevtx_vout; +} + static bool check_remote_inputs(struct state *state, + struct input_info **local_inputs, struct input_info **remote_inputs, struct amount_sat *input_funding) { - size_t i = 0; + size_t i, j; - /* - * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * The sending node: - * ... - * - MUST NOT re-transmit inputs it has already received from the peer - */ - // FIXME(nifty): check this ^^^ *input_funding = AMOUNT_SAT(0); for (i = 0; i < tal_count(remote_inputs); i++) { + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * The sending node: + * ... + * - MUST NOT re-transmit inputs it has already received from the peer + */ + /* Ugly brute force search for a match in our inputs */ + for (j = 0; j < tal_count(local_inputs); j++) { + if (inputs_eq(local_inputs[j], remote_inputs[i])) + peer_failed(state->pps, &state->channel_id, + "Remote replied with one of our inputs %s:%u", + type_to_string(tmpctx, struct bitcoin_txid, + &remote_inputs[i]->prevtx_txid), + remote_inputs[i]->prevtx_vout); + + } + if (!amount_sat_add(input_funding, *input_funding, remote_inputs[i]->input_satoshis)) peer_failed(state->pps, &state->channel_id, "Overflow in remote input amounts %s + %s", @@ -942,6 +959,7 @@ static bool check_remote_inputs(struct state *state, /* Check that the tx info your peer sent you is kosher */ static bool check_remote_input_outputs(struct state *state, enum role remote_role, + struct input_info **local_inputs, struct input_info **remote_inputs, struct output_info **remote_outputs, struct amount_sat stated_funding_sats) @@ -996,7 +1014,7 @@ static bool check_remote_input_outputs(struct state *state, REMOTE_OUTPUT_LIMIT); } - if (!check_remote_inputs(state, remote_inputs, &funding)) + if (!check_remote_inputs(state, local_inputs, remote_inputs, &funding)) peer_failed(state->pps, &state->channel_id, "Peer sent malleable (non-Segwit) input."); @@ -1126,7 +1144,8 @@ static u8 *funder_finalize_channel_setup2(struct state *state, "Parsing received funding_compose %s", tal_hex(msg, msg)); if (!check_remote_input_outputs(state, ACCEPTER, - remote_ins, remote_outs, + local_ins, remote_ins, + remote_outs, state->accepter_funding)) return NULL; @@ -1833,6 +1852,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) check_channel_id(state, &id_in, &state->channel_id); if (!check_remote_input_outputs(state, OPENER, + our_inputs, their_inputs, their_outputs, state->opener_funding)) From 93030ef22d8ae357c3c96900280104f3c7eaa7ea Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 21 Nov 2019 16:01:25 -0600 Subject: [PATCH 046/131] df: verify that funding output not included a peer's output set should never include the funding output --- openingd/openingd.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 782e24fe8c20..6b915fd27b91 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -967,6 +967,7 @@ static bool check_remote_input_outputs(struct state *state, size_t i = 0; struct amount_sat funding, other_outputs, funding_tx_sats; bool has_change_address; + u8 *wscript; if (remote_role == OPENER) { /** @@ -1021,6 +1022,10 @@ static bool check_remote_input_outputs(struct state *state, other_outputs = AMOUNT_SAT(0); has_change_address = false; + /* Compute the funding output script */ + wscript = bitcoin_redeem_2of2(tmpctx, &state->our_funding_pubkey, + &state->their_funding_pubkey); + for (i = 0; i < tal_count(remote_outputs); i++) { /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 @@ -1059,8 +1064,12 @@ static bool check_remote_input_outputs(struct state *state, * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - MUST NOT include the channel funding output. */ - // FIXME(nifty): check this ^^^ - + if (memeq(remote_outputs[i]->script, + tal_count(remote_outputs[i]->script), + wscript, tal_count(wscript))) + peer_failed(state->pps, + &state->channel_id, + "Peer included funding output in output set"); } /** From 74b3df732f6984895cb4511b7906a0f576c29369 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 21 Nov 2019 17:48:36 -0600 Subject: [PATCH 047/131] df: port to new input/output dance updates to use the newer funding_add messages. --- channeld/channeld.c | 6 +- common/funding_tx.c | 12 +- common/test/run-funding_tx_dual.c | 26 +- gossipd/gossipd.c | 6 +- openingd/openingd.c | 237 ++++++++++++++---- tools/generate-wire.py | 1 + ..._3f9f65d3ad5a21835994f9d9226ed9e0e4066662} | 47 ++-- wire/peer_wire.c | 12 +- wire/test/run-peer-wire.c | 201 ++++++++++----- 9 files changed, 382 insertions(+), 166 deletions(-) rename wire/{extracted_peer_experimental_737016aef => extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662} (75%) diff --git a/channeld/channeld.c b/channeld/channeld.c index 45fde77d6ce2..7142ee839a3b 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1970,8 +1970,10 @@ static void peer_in(struct peer *peer, const u8 *msg) #if EXPERIMENTAL_FEATURES case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_COMPOSE: - case WIRE_ACCEPTER_SIGS: + case WIRE_FUNDING_ADD_INPUT: + case WIRE_FUNDING_ADD_OUTPUT: + case WIRE_FUNDING_ADD_COMPLETE: + case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ diff --git a/common/funding_tx.c b/common/funding_tx.c index 76ce67960d62..36e7e01bb117 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -97,7 +97,7 @@ static bool calculate_input_weights(struct input_info **inputs, input_weight += inputs[i]->max_witness_len; *weight += input_weight; - if (!amount_sat_add(total, *total, inputs[i]->input_satoshis)) + if (!amount_sat_add(total, *total, inputs[i]->sats)) return false; } @@ -169,7 +169,7 @@ static const struct output_info *find_change_output(struct output_info **outputs { size_t i = 0; for (i = 0; i < tal_count(outputs); i++) { - if (amount_sat_eq(outputs[i]->output_satoshis, AMOUNT_SAT(0))) + if (amount_sat_eq(outputs[i]->sats, AMOUNT_SAT(0))) return outputs[i]; } return NULL; @@ -181,7 +181,7 @@ static bool calculate_output_value(struct output_info **outputs, size_t i = 0; for (i = 0; i < tal_count(outputs); i++) { - if (!amount_sat_add(total, *total, outputs[i]->output_satoshis)) + if (!amount_sat_add(total, *total, outputs[i]->sats)) return false; } return true; @@ -193,7 +193,7 @@ static void add_inputs(struct bitcoin_tx *tx, struct input_info **inputs) for (i = 0; i < tal_count(inputs); i++) { bitcoin_tx_add_input(tx, &inputs[i]->prevtx_txid, inputs[i]->prevtx_vout, BITCOIN_TX_DEFAULT_SEQUENCE, - inputs[i]->input_satoshis, inputs[i]->script); + inputs[i]->sats, inputs[i]->script); } } @@ -206,13 +206,13 @@ static void add_outputs(struct bitcoin_tx *tx, struct output_info **outputs, for (i = 0; i < tal_count(outputs); i++) { /* Is this the change output?? */ - if (change && amount_sat_eq(outputs[i]->output_satoshis, AMOUNT_SAT(0))) { + if (change && amount_sat_eq(outputs[i]->sats, AMOUNT_SAT(0))) { /* If there's no change amount, we leave it out */ if (amount_sat_eq(*change, AMOUNT_SAT(0))) continue; value = *change; } else - value = outputs[i]->output_satoshis; + value = outputs[i]->sats; script = tal_dup_arr(tx, u8, outputs[i]->script, tal_count(outputs[i]->script), 0); diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index eca0dc8408c3..08e319284e91 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -163,7 +163,7 @@ static struct test_case test1(const tal_t *ctx) struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 2); struct input_info *input_one = tal(ctx, struct input_info); - input_one->input_satoshis = AMOUNT_SAT(250000000); + input_one->sats = AMOUNT_SAT(250000000); input_one->prevtx_txid = txid; input_one->prevtx_vout = 0; input_one->prevtx_scriptpubkey = hex_to_u8(ctx, "220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946"); @@ -172,7 +172,7 @@ static struct test_case test1(const tal_t *ctx) opener_inputs[0] = input_one; struct input_info *input_two = tal(ctx, struct input_info); - input_two->input_satoshis = AMOUNT_SAT(250000000); + input_two->sats = AMOUNT_SAT(250000000); input_two->prevtx_txid = txid; input_two->prevtx_vout = 1; input_two->prevtx_scriptpubkey = hex_to_u8(ctx, "a9146a235d064786b49e7043e4a042d4cc429f7eb69487"); @@ -182,7 +182,7 @@ static struct test_case test1(const tal_t *ctx) struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 2); struct input_info *input_three = tal(ctx, struct input_info); - input_three->input_satoshis = AMOUNT_SAT(250000000); + input_three->sats = AMOUNT_SAT(250000000); input_three->prevtx_txid = txid; input_three->prevtx_vout = 2; input_three->prevtx_scriptpubkey = hex_to_u8(ctx, "160014fbb4db9d85fba5e301f4399e3038928e44e37d32"); @@ -191,7 +191,7 @@ static struct test_case test1(const tal_t *ctx) accepter_inputs[0] = input_three; struct input_info *input_four = tal(ctx, struct input_info); - input_four->input_satoshis = AMOUNT_SAT(250000000); + input_four->sats = AMOUNT_SAT(250000000); input_four->prevtx_txid = txid; input_four->prevtx_vout = 3; input_four->prevtx_scriptpubkey = hex_to_u8(ctx, "a9147ecd1b519326bc13b0ec716e469b58ed02b112a087"); @@ -201,13 +201,13 @@ static struct test_case test1(const tal_t *ctx) struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 1); struct output_info *output_one = tal(ctx, struct output_info); - output_one->output_satoshis = AMOUNT_SAT(0); + output_one->sats = AMOUNT_SAT(0); output_one->script = hex_to_u8(ctx, "00141ca1cca8855bad6bc1ea5436edd8cff10b7e448b"); opener_outputs[0] = output_one; struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); struct output_info *output_two = tal(ctx, struct output_info); - output_two->output_satoshis = AMOUNT_SAT(200000000); + output_two->sats = AMOUNT_SAT(200000000); output_two->script = hex_to_u8(ctx, "001444cb0c39f93ecc372b5851725bd29d865d333b10"); accepter_outputs[0] = output_two; @@ -241,7 +241,7 @@ static struct input_info *input_one(const tal_t *ctx, int vout, const char* txid struct bitcoin_txid txid; bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); struct input_info *input_one = tal(ctx, struct input_info); - input_one->input_satoshis = AMOUNT_SAT(500000); + input_one->sats = AMOUNT_SAT(500000); input_one->prevtx_txid = txid; input_one->prevtx_vout = vout; input_one->prevtx_scriptpubkey = hex_to_u8(ctx, "0014ca5cc81df579bd589a428c0d29dceb81513fce8d"); @@ -256,7 +256,7 @@ static struct input_info *input_two(const tal_t *ctx, const char *txid_str) bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); struct input_info *input_two = tal(ctx, struct input_info); - input_two->input_satoshis = AMOUNT_SAT(1000000); + input_two->sats = AMOUNT_SAT(1000000); input_two->prevtx_txid = txid; input_two->prevtx_vout = 0; input_two->prevtx_scriptpubkey = hex_to_u8(ctx, "001483440596268132e6c99d44dae2d151dabd9a2b23"); @@ -271,7 +271,7 @@ static struct input_info *input_three(const tal_t *ctx, int vout, const char *tx bitcoin_txid_from_hex(txid_str, strlen(txid_str), &txid); struct input_info *input = tal(ctx, struct input_info); - input->input_satoshis = AMOUNT_SAT(1500000); + input->sats = AMOUNT_SAT(1500000); input->prevtx_txid = txid; input->prevtx_vout = vout; input->prevtx_scriptpubkey = hex_to_u8(ctx, "0014d1f40e954d7a792284b6fb19a2e0bf777441d83e"); @@ -287,7 +287,7 @@ static struct input_info *input_four(const tal_t *ctx) bitcoin_txid_from_hex(txid_str_two, strlen(txid_str_two), &txid); struct input_info *input = tal(ctx, struct input_info); - input->input_satoshis = AMOUNT_SAT(2000000); + input->sats = AMOUNT_SAT(2000000); input->prevtx_txid = txid; input->prevtx_vout = 1; input->prevtx_scriptpubkey = hex_to_u8(ctx, "0014fd9658fbd476d318f3b825b152b152aafa49bc92"); @@ -299,7 +299,7 @@ static struct input_info *input_four(const tal_t *ctx) static struct output_info *output_one(const tal_t *ctx, u64 amount) { struct output_info *output_one = tal(ctx, struct output_info); - output_one->output_satoshis = (struct amount_sat){ amount }; + output_one->sats = (struct amount_sat){ amount }; output_one->script = hex_to_u8(ctx, "00140f0963bc774334ebc14d11ce940c35cfa6986415"); return output_one; } @@ -307,7 +307,7 @@ static struct output_info *output_one(const tal_t *ctx, u64 amount) static struct output_info *output_two(const tal_t *ctx, u64 amount) { struct output_info *output = tal(ctx, struct output_info); - output->output_satoshis = (struct amount_sat){ amount }; + output->sats = (struct amount_sat){ amount }; output->script = hex_to_u8(ctx, "0014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5"); return output; } @@ -315,7 +315,7 @@ static struct output_info *output_two(const tal_t *ctx, u64 amount) static struct output_info *output_three(const tal_t *ctx, u64 amount) { struct output_info *output = tal(ctx, struct output_info); - output->output_satoshis = (struct amount_sat){ amount }; + output->sats = (struct amount_sat){ amount }; output->script = hex_to_u8(ctx, "0014d295f76da2319791f36df5759e45b15d5e105221"); return output; } diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 86092198d052..5db3bbe4d95d 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -492,8 +492,10 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_ONION_MESSAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_COMPOSE: - case WIRE_ACCEPTER_SIGS: + case WIRE_FUNDING_ADD_INPUT: + case WIRE_FUNDING_ADD_OUTPUT: + case WIRE_FUNDING_ADD_COMPLETE: + case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ diff --git a/openingd/openingd.c b/openingd/openingd.c index 6b915fd27b91..f7125b1ba803 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -852,7 +852,7 @@ static void derive_input_output_info(const tal_t *ctx, struct input_info *in; in = tal(*inputs, struct input_info); - in->input_satoshis = utxos[i]->amount; + in->sats = utxos[i]->amount; in->prevtx_txid = utxos[i]->txid; in->prevtx_vout = utxos[i]->outnum; in->prevtx_scriptpubkey = tal_dup_arr(in, u8, utxos[i]->scriptPubkey, @@ -891,7 +891,7 @@ static void derive_input_output_info(const tal_t *ctx, continue; out = tal(*outputs, struct output_info); - out->output_satoshis.satoshis = wo.satoshi; /* Raw: type conversion */ + out->sats.satoshis = wo.satoshi; /* Raw: type conversion */ out->script = tal_arr(out, u8, wo.script_len); memcpy(out->script, wo.script, wo.script_len); @@ -932,11 +932,11 @@ static bool check_remote_inputs(struct state *state, } - if (!amount_sat_add(input_funding, *input_funding, remote_inputs[i]->input_satoshis)) + if (!amount_sat_add(input_funding, *input_funding, remote_inputs[i]->sats)) peer_failed(state->pps, &state->channel_id, "Overflow in remote input amounts %s + %s", type_to_string(tmpctx, struct amount_sat, - &remote_inputs[i]->input_satoshis), + &remote_inputs[i]->sats), type_to_string(tmpctx, struct amount_sat, input_funding)); @@ -1034,7 +1034,7 @@ static bool check_remote_input_outputs(struct state *state, * as the change address for any resulting funds after fees are deducted */ if (remote_role == OPENER) { - if (amount_sat_eq(AMOUNT_SAT(0), remote_outputs[i]->output_satoshis)) { + if (amount_sat_eq(AMOUNT_SAT(0), remote_outputs[i]->sats)) { if (has_change_address) peer_failed(state->pps, &state->channel_id, @@ -1043,13 +1043,13 @@ static bool check_remote_input_outputs(struct state *state, has_change_address = true; } } - if (!amount_sat_add(&other_outputs, other_outputs, remote_outputs[i]->output_satoshis)) + if (!amount_sat_add(&other_outputs, other_outputs, remote_outputs[i]->sats)) peer_failed(state->pps, &state->channel_id, "Overflow in remote output satoshi sum %s + %s", type_to_string(tmpctx, struct amount_sat, &other_outputs), type_to_string(tmpctx, struct amount_sat, - &remote_outputs[i]->output_satoshis)); + &remote_outputs[i]->sats)); /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 @@ -1102,6 +1102,168 @@ static bool check_remote_input_outputs(struct state *state, return true; } + +static bool send_receive_funding_tx_info(struct state *state, + enum role role, + struct input_info ***local_inputs, + struct output_info ***local_outputs, + struct input_info ***remote_inputs, + struct output_info ***remote_outputs) + +{ + struct channel_id id_in; + bool complete; + size_t i; + u8 *msg; + + /* + * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 + * + * - if is the `opener`: + * - MUST send at least one `funding_add_input` message + * ... + * - if is the `accepter`: + * - MAY omit this message + */ + if (tal_count(*local_inputs) > 0) { + msg = towire_funding_add_input(tmpctx, &state->channel_id, + cast_const2(const struct input_info **, + *local_inputs)); + sync_crypto_write(state->pps, take(msg)); + + peer_billboard(false, "Opening channel: funding_add_input sent"); + } else + assert(role == ACCEPTER); + + + /* + * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 + * + * Either node: + * - MAY omit this message + */ + if (tal_count(*local_outputs) > 0) { + msg = towire_funding_add_output(tmpctx, &state->channel_id, + cast_const2(const struct output_info **, + *local_outputs)); + sync_crypto_write(state->pps, take(msg)); + peer_billboard(false, "Opening channel: funding_add_output sent"); + } + + + /* + * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 + * + * Both nodes: + * - MUST send this message after `accept_channel2` has been sent/received. + * + * The sending node: + * - MUST ensure that the `num_inputs` corresponds to the total sum of all `num_inputs` + * sent in all `funding_add_input` messages that originated from them + * - MUST ensure that the `num_outputs` corresponds to the total sum of all `num_outputs` + * sent in all `funding_add_output` messages that originated from them + */ + /* FIXME: allow for more interactive input/output composition */ + msg = towire_funding_add_complete(tmpctx, &state->channel_id, + tal_count(*local_inputs), + tal_count(*local_outputs)); + + sync_crypto_write(state->pps, take(msg)); + + peer_billboard(false, "Opening channel: funding_add_complete sent"); + + /* We expect the peer to send us their inputs/outputs. Read + * until we get funding_add_complete */ + complete = false; + *remote_inputs = tal_arr(state, struct input_info *, 0); + *remote_outputs = tal_arr(state, struct output_info *, 0); + + while (!complete) { + struct input_info **inputs; + struct output_info **outputs; + u16 num_ins, num_outs; + int type; + + msg = opening_negotiate_msg(tmpctx, state, role == OPENER); + if (!msg) + return false; + + type = fromwire_peektype(msg); + switch (type) { + case WIRE_FUNDING_ADD_INPUT: + if (!fromwire_funding_add_input(state, msg, &id_in, &inputs)) + peer_failed(state->pps, &state->channel_id, + "Parsing received funding_add_input %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + + // FIXME: is there a more succinct way to do this? + for (i = 0; i < tal_count(inputs); i++) + tal_arr_expand(remote_inputs, inputs[i]); + break; + case WIRE_FUNDING_ADD_OUTPUT: + if (!fromwire_funding_add_output(state, msg, &id_in, &outputs)) + peer_failed(state->pps, &state->channel_id, + "Parsing received funding_add_output %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + + // FIXME: is there a more succinct way to do this? + for (i = 0; i < tal_count(outputs); i++) + tal_arr_expand(remote_outputs, outputs[i]); + break; + case WIRE_FUNDING_ADD_COMPLETE: + if (!fromwire_funding_add_complete(msg, &id_in, + &num_ins, &num_outs)) + peer_failed(state->pps, &state->channel_id, + "Parsing received funding_add_complete %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + /* + * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 + * + * The receiving node: + * - MUST fail the channel if: + * - the `num_inputs` does not correspond to the total + * sum of all `num_inputs` received in all + * `funding_add_input` messages + * - the `num_outputs` does not correspond to the total + * sum of all `num_outputs` received in all + * `funding_add_output` messages + */ + if (tal_count(*remote_inputs) != num_ins) + peer_failed(state->pps, &state->channel_id, + "Expected %u inputs, received %zu :%s", + num_ins, tal_count(*remote_inputs), + tal_hex(msg, msg)); + + /** + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if is the `opener`: + * - MUST send at least one `funding_add_input` message + */ + if (num_ins == 0 && role != OPENER) + peer_failed(state->pps, &state->channel_id, + "Opener must send at lease one input"); + + if (tal_count(*remote_outputs) != num_outs) + peer_failed(state->pps, &state->channel_id, + "Expected %u outputs, received %zu :%s", + num_outs, tal_count(*remote_outputs), + tal_hex(msg, msg)); + complete = true; + break; + default: + peer_failed(state->pps, + &state->channel_id, + "Expected a funding_add_ message, got %s", + tal_hex(msg, msg)); + + } + } + + return true; +} #endif static u8 *funder_finalize_channel_setup2(struct state *state, @@ -1122,36 +1284,19 @@ static u8 *funder_finalize_channel_setup2(struct state *state, size_t i, input_count; struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; - const struct witness_stack **remote_witnesses; + + // FIXME!! (don't set NULL) + const struct witness_stack **remote_witnesses = NULL; /* Derive components, omitting the funding output */ derive_input_output_info(state, *tx, utxos, true, &local_ins, &local_outs); - /* Send them to the peer */ - msg = towire_funding_compose(tmpctx, &state->channel_id, - cast_const2(const struct input_info **, local_ins), - cast_const2(const struct output_info **, local_outs)); - - sync_crypto_write(state->pps, take(msg)); - - peer_billboard(false, - "Opening channel: funding_compose sent, " - "waiting for funding_compose reply"); - - msg = opening_negotiate_msg(tmpctx, state, false); - if (!msg) + if (!send_receive_funding_tx_info(state, OPENER, + &local_ins, &local_outs, + &remote_ins, &remote_outs)) return NULL; - /* The next message is "funding_compose", which tells us the funding - * inputs and outputs they've selected. */ - if (!fromwire_funding_compose(state, msg, &id_in, - &remote_ins, - &remote_outs)) - peer_failed(state->pps, - &state->channel_id, - "Parsing received funding_compose %s", tal_hex(msg, msg)); - if (!check_remote_input_outputs(state, ACCEPTER, local_ins, remote_ins, remote_outs, @@ -1256,12 +1401,14 @@ static u8 *funder_finalize_channel_setup2(struct state *state, return NULL; their_sig.sighash_type = SIGHASH_ALL; + /* FIXME!!! if (!fromwire_accepter_sigs(state, msg, &id_in, &their_sig.s, (struct witness_stack ***)&remote_witnesses)) peer_failed(state->pps, &state->channel_id, "Bad accepter_sigs in %s", tal_hex(msg, msg)); + */ peer_billboard(false, "Opening channel: accepter_sigs received"); @@ -1656,7 +1803,7 @@ static void inputs_to_infos(const tal_t *ctx, struct utxo **utxos, for (i = 0; i < tal_count(utxos); i++) { struct input_info *info; info = tal(*input_infos, struct input_info); - info->input_satoshis = utxos[i]->amount; + info->sats = utxos[i]->amount; info->prevtx_txid = utxos[i]->txid; info->prevtx_vout = utxos[i]->outnum; @@ -1694,7 +1841,7 @@ static struct output_info **outputs_to_infos(const tal_t *ctx, struct bitcoin_tx info->script = tal_dup_arr(info, u8, outputs[i]->script, tal_count(outputs[i]->script), 0); - info->output_satoshis = outputs[i]->amount; + info->sats = outputs[i]->amount; infos[i] = info; } @@ -1849,16 +1996,10 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) inputs_to_infos(state, utxos, &our_inputs); our_outputs = outputs_to_infos(state, outputs); - /* The next message should be "funding_compose" which tells us the funding - * inputs and outputs they've selected. */ - if (!fromwire_funding_compose(state, msg, &id_in, - &their_inputs, - &their_outputs)) - peer_failed(state->pps, - &state->channel_id, - "Parsing received funding_compose"); - - check_channel_id(state, &id_in, &state->channel_id); + if (!send_receive_funding_tx_info(state, ACCEPTER, + &our_inputs, &our_outputs, + &their_inputs, &their_outputs)) + return NULL; if (!check_remote_input_outputs(state, OPENER, our_inputs, @@ -1890,16 +2031,8 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) status_debug("dual funding tx is %s", type_to_string(tmpctx, struct bitcoin_tx, funding_tx)); - /* Now we send our inputs/outputs to them */ - msg = towire_funding_compose(tmpctx, &state->channel_id, - cast_const2(const struct input_info **, our_inputs), - cast_const2(const struct output_info **, our_outputs)); - - sync_crypto_write(state->pps, take(msg)); - - peer_billboard(false, "Incoming channel: funding_compose sent," - " now waiting for commitment_signed"); + /* We expect to get commitment_signed here */ msg = opening_negotiate_msg(tmpctx, state, false); if (!msg) return NULL; @@ -2048,9 +2181,11 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) * to save state to disk before doing so. */ assert(our_sig.sighash_type == SIGHASH_ALL); + /* FIXME: commitment_signed send dance etc!! msg = towire_accepter_sigs(state, &state->channel_id, &our_sig.s, cast_const2(const struct witness_stack **, our_stack)); + */ /* we send everything to lightning, who commits things to the database etc. * lightningd will forward the signatures etc over to channeld, who diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 032be83e82cc..37937e4f966a 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -242,6 +242,7 @@ class Type(FieldSet): ('amt', 'u64'): ('amount_msat', False), ('msat', 'u64'): ('amount_msat', False), ('satoshis', 'u64'): ('amount_sat', False), + ('sats', 'u64'): ('amount_sat', False), ('node_id', 'pubkey', 'channel_announcement'): ('node_id', False), ('node_id', 'pubkey', 'node_announcement'): ('node_id', False), ('temporary_channel_id', 'u8'): ('channel_id', True), diff --git a/wire/extracted_peer_experimental_737016aef b/wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 similarity index 75% rename from wire/extracted_peer_experimental_737016aef rename to wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 index a1048abd4475..f1c50080fb7d 100644 --- a/wire/extracted_peer_experimental_737016aef +++ b/wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 @@ -1,10 +1,10 @@ ---- wire/extracted_peer_wire_csv 2019-08-21 13:30:32.219341098 -0500 -+++ - 2019-09-11 17:38:34.177415676 -0500 -@@ -77,6 +77,89 @@ +--- wire/extracted_peer_wire_csv 2019-11-21 16:04:36.972045004 -0600 ++++ - 2019-11-21 16:20:28.611476176 -0600 +@@ -77,6 +77,96 @@ msgtype,funding_locked,36 msgdata,funding_locked,channel_id,channel_id, msgdata,funding_locked,next_per_commitment_point,point, -+msgtype,open_channel2,56 ++msgtype,open_channel2,64 +msgdata,open_channel2,chain_hash,chain_hash, +msgdata,open_channel2,temporary_channel_id,byte,32 +msgdata,open_channel2,funding_satoshis,u64, @@ -27,7 +27,7 @@ +tlvtype,opening_tlvs,option_upfront_shutdown_script,1 +tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, +tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len -+msgtype,accept_channel2,57 ++msgtype,accept_channel2,65 +msgdata,accept_channel2,temporary_channel_id,byte,32 +msgdata,accept_channel2,funding_satoshis,u64, +msgdata,accept_channel2,dust_limit_satoshis,u64, @@ -46,14 +46,12 @@ +tlvtype,accept_tlvs,option_upfront_shutdown_script,1 +tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, +tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len -+msgtype,funding_compose,58 -+msgdata,funding_compose,temporary_channel_id,byte,32 -+msgdata,funding_compose,num_inputs,u16, -+msgdata,funding_compose,input_info,input_info,num_inputs -+msgdata,funding_compose,num_outputs,u16, -+msgdata,funding_compose,output_info,output_info,num_outputs ++msgtype,funding_add_input,66 ++msgdata,funding_add_input,temporary_channel_id,byte,32 ++msgdata,funding_add_input,num_inputs,u16, ++msgdata,funding_add_input,input_info,input_info,num_inputs +subtype,input_info -+subtypedata,input_info,input_satoshis,u64, ++subtypedata,input_info,sats,u64, +subtypedata,input_info,prevtx_txid,sha256, +subtypedata,input_info,prevtx_vout,u32, +subtypedata,input_info,prevtx_scriptpubkey_len,u16, @@ -61,22 +59,31 @@ +subtypedata,input_info,max_witness_len,u16, +subtypedata,input_info,scriptlen,u16, +subtypedata,input_info,script,byte,scriptlen ++msgtype,funding_add_output,67 ++msgdata,funding_add_output,temporary_channel_id,byte,32 ++msgdata,funding_add_output,num_outputs,u16, ++msgdata,funding_add_output,output_info,output_info,num_outputs +subtype,output_info -+subtypedata,output_info,output_satoshis,u64, ++subtypedata,output_info,sats,u64, +subtypedata,output_info,scriptlen,u16, +subtypedata,output_info,script,byte,scriptlen -+msgtype,accepter_sigs,60 -+msgdata,accepter_sigs,channel_id,channel_id, -+msgdata,accepter_sigs,commitment_signature,signature, -+msgdata,accepter_sigs,num_witnesses,u16, -+msgdata,accepter_sigs,witness_stack,witness_stack,num_witnesses ++msgtype,funding_add_complete,68 ++msgdata,funding_add_complete,temporary_channel_id,byte,32 ++msgdata,funding_add_complete,num_inputs,u16, ++msgdata,funding_add_complete,num_outputs,u16, ++msgtype,funding_signed2,69 ++msgdata,funding_signed2,channel_id,channel_id, ++msgdata,funding_signed2,num_witnesses,u16, ++msgdata,funding_signed2,witness_stack,witness_stack,num_witnesses +subtype,witness_stack ++subtypedata,witness_stack,prevtx_txid,sha256, ++subtypedata,witness_stack,prevtx_vout,u32, +subtypedata,witness_stack,num_input_witness,u16, +subtypedata,witness_stack,witness_element,witness_element,num_input_witness +subtype,witness_element +subtypedata,witness_element,len,u16, +subtypedata,witness_element,witness,byte,len -+msgtype,init_rbf,62 ++msgtype,init_rbf,70 +msgdata,init_rbf,channel_id,channel_id, +msgdata,init_rbf,funding_satoshis,u64, +msgdata,init_rbf,feerate_per_kw,u32, @@ -85,7 +92,7 @@ +msgdata,init_rbf,input_info,input_info,num_additional_inputs +msgdata,init_rbf,num_outputs,u16, +msgdata,init_rbf,output_info,output_info,num_outputs -+msgtype,ack_rbf,63 ++msgtype,ack_rbf,71 +msgdata,ack_rbf,channel_id,channel_id, msgtype,shutdown,38 msgdata,shutdown,channel_id,channel_id, diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 607b7a3fbdba..bf78e5254448 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -35,8 +35,10 @@ static bool unknown_type(enum wire_type t) case WIRE_ONION_MESSAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_COMPOSE: - case WIRE_ACCEPTER_SIGS: + case WIRE_FUNDING_ADD_INPUT: + case WIRE_FUNDING_ADD_OUTPUT: + case WIRE_FUNDING_ADD_COMPLETE: + case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ @@ -81,8 +83,10 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_ONION_MESSAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_COMPOSE: - case WIRE_ACCEPTER_SIGS: + case WIRE_FUNDING_ADD_INPUT: + case WIRE_FUNDING_ADD_OUTPUT: + case WIRE_FUNDING_ADD_COMPLETE: + case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 46befd781afc..ca9945956ef6 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -290,14 +290,21 @@ struct msg_accept_channel2 { struct pubkey first_per_commitment_point; struct tlv_accept_tlvs *tlv; }; -struct msg_funding_compose { +struct msg_funding_add_input { struct channel_id temporary_channel_id; struct input_info **input_infos; +}; +struct msg_funding_add_output { + struct channel_id temporary_channel_id; struct output_info **output_infos; }; -struct msg_accepter_sigs { +struct msg_funding_add_complete { + struct channel_id temporary_channel_id; + u16 num_inputs; + u16 num_outputs; +}; +struct msg_funding_signed2 { struct channel_id channel_id; - secp256k1_ecdsa_signature commitment_signature; struct witness_stack **witness_stacks; }; struct msg_init_rbf { @@ -946,41 +953,72 @@ static struct msg_accept_channel2 *fromwire_struct_accept_channel2(const tal_t * return s; return tal_free(s); } -static void *towire_struct_funding_compose(const tal_t *ctx, - struct msg_funding_compose *s) +static void *towire_struct_funding_add_input(const tal_t *ctx, + struct msg_funding_add_input *s) { - return towire_funding_compose(ctx, + return towire_funding_add_input(ctx, &s->temporary_channel_id, - (const struct input_info **)s->input_infos, - (const struct output_info **)s->output_infos); + (const struct input_info **)s->input_infos); } -static struct msg_funding_compose *fromwire_struct_funding_compose(const tal_t *ctx, const void *p) + +static struct msg_funding_add_input *fromwire_struct_funding_add_input(const tal_t *ctx, const void *p) { - struct msg_funding_compose *s = tal(ctx, struct msg_funding_compose); + struct msg_funding_add_input *s = tal(ctx, struct msg_funding_add_input); - if (fromwire_funding_compose(ctx, p, + if (fromwire_funding_add_input(ctx, p, &s->temporary_channel_id, - &s->input_infos, - &s->output_infos)) + &s->input_infos)) + return s; + return tal_free(s); +} +static void *towire_struct_funding_add_output(const tal_t *ctx, + struct msg_funding_add_output *s) +{ + return towire_funding_add_output(ctx, + &s->temporary_channel_id, + (const struct output_info **)s->output_infos); +} +static struct msg_funding_add_output *fromwire_struct_funding_add_output(const tal_t *ctx, const void *p) +{ + struct msg_funding_add_output *s = tal(ctx, struct msg_funding_add_output); + + if (fromwire_funding_add_output(ctx, p, + &s->temporary_channel_id, + &s->output_infos)) return s; return tal_free(s); } -static void *towire_struct_accepter_sigs(const tal_t *ctx, - struct msg_accepter_sigs *s) +static void *towire_struct_funding_add_complete(const tal_t *ctx, + struct msg_funding_add_complete *s) +{ + return towire_funding_add_complete(ctx, &s->temporary_channel_id, + s->num_inputs, + s->num_outputs); +} +static struct msg_funding_add_complete *fromwire_struct_funding_add_complete(const tal_t *ctx, const void *p) { - return towire_accepter_sigs(ctx, + struct msg_funding_add_complete *s = tal(ctx, struct msg_funding_add_complete); + + if (fromwire_funding_add_complete(p, &s->temporary_channel_id, + &s->num_inputs, + &s->num_outputs)) + return s; + return tal_free(s); +} +static void *towire_struct_funding_signed2(const tal_t *ctx, + struct msg_funding_signed2 *s) +{ + return towire_funding_signed2(ctx, &s->channel_id, - &s->commitment_signature, (const struct witness_stack **)s->witness_stacks); } -static struct msg_accepter_sigs *fromwire_struct_accepter_sigs(const tal_t *ctx, const void *p) +static struct msg_funding_signed2 *fromwire_struct_funding_signed2(const tal_t *ctx, const void *p) { - struct msg_accepter_sigs *s = tal(ctx, struct msg_accepter_sigs); + struct msg_funding_signed2 *s = tal(ctx, struct msg_funding_signed2); - if (fromwire_accepter_sigs(ctx, p, - &s->channel_id, - &s->commitment_signature, - &s->witness_stacks)) { + if (fromwire_funding_signed2(ctx, p, + &s->channel_id, + &s->witness_stacks)) { return s; } return tal_free(s); @@ -1050,7 +1088,7 @@ static bool input_info_eq(struct input_info *a, static bool output_info_eq(struct output_info *a, struct output_info *b) { - return eq_with(a, b, output_satoshis) + return eq_with(a, b, sats) && eq_var(a, b, script); } @@ -1066,7 +1104,8 @@ static bool witness_stack_eq(struct witness_stack *a, { bool ok = true; eq_struct_set(a, b, witness_element, witness_element); - return ok; + return ok && eq_field(a, b, prevtx_txid) + && eq_field(a, b, prevtx_vout); } @@ -1104,17 +1143,29 @@ static bool accept_channel2_eq(const struct msg_accept_channel2 *a, && accept_tlv_eq(a->tlv, b->tlv); } -static bool funding_compose_eq(const struct msg_funding_compose *a, - const struct msg_funding_compose *b) +static bool funding_add_input_eq(const struct msg_funding_add_input *a, + const struct msg_funding_add_input *b) { bool ok = true; eq_struct_set(a, b, input_infos, input_info); - eq_struct_set(a, b, output_infos, output_info); return ok && eq_upto(a, b, input_infos); } -static bool accepter_sigs_eq(const struct msg_accepter_sigs *a, - const struct msg_accepter_sigs *b) +static bool funding_add_output_eq(const struct msg_funding_add_output *a, + const struct msg_funding_add_output *b) +{ + bool ok = true; + eq_struct_set(a, b, output_infos, output_info); + return ok && eq_upto(a, b, output_infos); +} + +static bool funding_add_complete_eq(const struct msg_funding_add_complete *a, + const struct msg_funding_add_complete *b) +{ + return eq_with(a, b, num_outputs); +} +static bool funding_signed2_eq(const struct msg_funding_signed2 *a, + const struct msg_funding_signed2 *b) { bool ok = true; eq_struct_set(a, b, witness_stacks, witness_stack); @@ -1368,8 +1419,10 @@ int main(void) /* v2 channel establishment */ struct msg_open_channel2 ocv2, *ocv22; struct msg_accept_channel2 acv2, *acv22; - struct msg_funding_compose fcom, *fcom2; - struct msg_accepter_sigs acs, *acs2; + struct msg_funding_add_input fai, *fai2; + struct msg_funding_add_output fao, *fao2; + struct msg_funding_add_complete fac, *fac2; + struct msg_funding_signed2 fsv2, *fsv22; struct msg_init_rbf irbf, *irbf2; struct msg_ack_rbf arbf, *arbf2; #endif /* EXPERIMENTAL_FEATURES */ @@ -1604,51 +1657,63 @@ int main(void) assert(accept_channel2_eq(&acv2, acv22)); test_corruption_tlv(&acv2, acv22, accept_channel2); - memset(&fcom, 2, sizeof(fcom)); - fcom.input_infos = tal_arr(ctx, struct input_info *, 2); - memset(fcom.input_infos, 2, sizeof(struct input_info *) * 2); + memset(&fai, 2, sizeof(fai)); + fai.input_infos = tal_arr(ctx, struct input_info *, 2); + memset(fai.input_infos, 2, sizeof(struct input_info *) * 2); for (i = 0; i < 2; i++) { - fcom.input_infos[i] = tal(ctx, struct input_info); - memset(fcom.input_infos[i], 2, sizeof(struct input_info)); - fcom.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); - memset(fcom.input_infos[i]->prevtx_scriptpubkey, 2, 2); - fcom.input_infos[i]->script = tal_arr(ctx, u8, 2); - memset(fcom.input_infos[i]->script, 2, 2); - } - fcom.output_infos = tal_arr(ctx, struct output_info *, 2); - memset(fcom.output_infos, 2, sizeof(struct output_info *)*2); - for (i = 0; i < 2; i++) { - fcom.output_infos[i] = tal(ctx, struct output_info); - memset(fcom.output_infos[i], 2, sizeof(struct output_info)); - fcom.output_infos[i]->script = tal_arr(ctx, u8, 2); - memset(fcom.output_infos[i]->script, 2, 2); + fai.input_infos[i] = tal(ctx, struct input_info); + memset(fai.input_infos[i], 2, sizeof(struct input_info)); + fai.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); + memset(fai.input_infos[i]->prevtx_scriptpubkey, 2, 2); + fai.input_infos[i]->script = tal_arr(ctx, u8, 2); + memset(fai.input_infos[i]->script, 2, 2); } + msg = towire_struct_funding_add_input(ctx, &fai); + fai2 = fromwire_struct_funding_add_input(ctx, msg); + assert(funding_add_input_eq(&fai, fai2)); + test_corruption(&fai, fai2, funding_add_input); - msg = towire_struct_funding_compose(ctx, &fcom); - fcom2 = fromwire_struct_funding_compose(ctx, msg); - assert(funding_compose_eq(&fcom, fcom2)); - test_corruption(&fcom, fcom2, funding_compose); - memset(&acs, 2, sizeof(acs)); - acs.witness_stacks = tal_arr(ctx, struct witness_stack *, 2); - memset(acs.witness_stacks, 2, sizeof(struct witness_stack *) * 2); + memset(&fao, 2, sizeof(fao)); + fao.output_infos = tal_arr(ctx, struct output_info *, 2); + memset(fao.output_infos, 2, sizeof(struct output_info *)*2); + for (i = 0; i < 2; i++) { + fao.output_infos[i] = tal(ctx, struct output_info); + memset(fao.output_infos[i], 2, sizeof(struct output_info)); + fao.output_infos[i]->script = tal_arr(ctx, u8, 2); + memset(fao.output_infos[i]->script, 2, 2); + } + msg = towire_struct_funding_add_output(ctx, &fao); + fao2 = fromwire_struct_funding_add_output(ctx, msg); + assert(funding_add_output_eq(&fao, fao2)); + test_corruption(&fao, fao2, funding_add_output); + + memset(&fac, 2, sizeof(fac)); + msg = towire_struct_funding_add_complete(ctx, &fac); + fac2 = fromwire_struct_funding_add_complete(ctx, msg); + assert(funding_add_complete_eq(&fac, fac2)); + test_corruption(&fac, fac2, funding_add_complete); + + memset(&fsv2, 2, sizeof(fsv2)); + fsv2.witness_stacks = tal_arr(ctx, struct witness_stack *, 2); + memset(fsv2.witness_stacks, 2, sizeof(struct witness_stack *) * 2); for (i = 0; i < 2; i++) { - acs.witness_stacks[i] = tal(ctx, struct witness_stack); - memset(acs.witness_stacks[i], 2, sizeof(struct witness_stack)); - acs.witness_stacks[i]->witness_element = tal_arr(ctx, struct witness_element *, 2); - memset(acs.witness_stacks[i]->witness_element, 2, sizeof(struct witness_element *) * 2); + fsv2.witness_stacks[i] = tal(ctx, struct witness_stack); + memset(fsv2.witness_stacks[i], 2, sizeof(struct witness_stack)); + fsv2.witness_stacks[i]->witness_element = tal_arr(ctx, struct witness_element *, 2); + memset(fsv2.witness_stacks[i]->witness_element, 2, sizeof(struct witness_element *) * 2); for (size_t j = 0; j < 2; j++) { - acs.witness_stacks[i]->witness_element[j] = tal(ctx, struct witness_element); - memset(acs.witness_stacks[i]->witness_element[j], 2, sizeof(struct witness_element)); - acs.witness_stacks[i]->witness_element[j]->witness = tal_arr(ctx, u8, 2); - memset(acs.witness_stacks[i]->witness_element[j]->witness, 2, 2); + fsv2.witness_stacks[i]->witness_element[j] = tal(ctx, struct witness_element); + memset(fsv2.witness_stacks[i]->witness_element[j], 2, sizeof(struct witness_element)); + fsv2.witness_stacks[i]->witness_element[j]->witness = tal_arr(ctx, u8, 2); + memset(fsv2.witness_stacks[i]->witness_element[j]->witness, 2, 2); } } - msg = towire_struct_accepter_sigs(ctx, &acs); - acs2 = fromwire_struct_accepter_sigs(ctx, msg); - assert(accepter_sigs_eq(&acs, acs2)); - test_corruption(&acs, acs2, accepter_sigs); + msg = towire_struct_funding_signed2(ctx, &fsv2); + fsv22 = fromwire_struct_funding_signed2(ctx, msg); + assert(funding_signed2_eq(&fsv2, fsv22)); + test_corruption(&fsv2, fsv22, funding_signed2); memset(&irbf, 2, sizeof(irbf)); irbf.input_infos = tal_arr(ctx, struct input_info *, 2); From 86adfed00cafec9ec34bac7cb62298901c9bddd3 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 2 Dec 2019 13:00:26 -0600 Subject: [PATCH 048/131] df: include input info on witness data Since inputs/outputs can be shared in an ad-hoc manner, we're now including the input identifying information with the witness sig. This adds the data to all witnesses we send --- hsmd/hsmd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index d1aac2867c6d..920339b1525e 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1722,6 +1722,10 @@ static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, status_failed(STATUS_FAIL_INTERNAL_ERROR, "Unable to find index for input"); + /* Copy over info for which input this belongs to */ + memcpy(&stack->prevtx_txid, &our_utxos[i]->txid, sizeof(struct bitcoin_txid)); + stack->prevtx_vout = our_utxos[i]->outnum; + sign_input(tx, our_utxos[i], &inkey, &sig, input_index); witnesses = bitcoin_witness_p2wpkh(tmpctx, &sig, &inkey); From 07c1119fea50e3cf37e92dd05d090b28aad9fbfd Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 2 Dec 2019 13:05:33 -0600 Subject: [PATCH 049/131] df: add remote's witnesses to unreleased tx object now uses the lookup info to match up remote peer's witnesses with their sent inputs --- lightningd/opening_control.c | 56 +++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 4ec5b723f3ac..629697c8fb69 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -398,17 +398,48 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp, } #if EXPERIMENTAL_FEATURES +// FIXME: Switch to PSBT, not unreleased tx +static bool add_remote_witnesses(struct unreleased_tx *utx, + struct witness_stack **witnesses) +{ + size_t i, j; + + assert(tal_count(witnesses) == tal_count(utx->inputs)); + for (i = 0; i < tal_count(witnesses); i++) { + struct witness_stack *witness = witnesses[i]; + + /* Convert witness stack into array of witnesses */ + u8 **witnesses_arr = tal_arr(NULL, u8 *, tal_count(witness->witness_element)); + for (j = 0; j < tal_count(witness->witness_element); j++) { + witnesses_arr[j] = + tal_dup_arr(witnesses_arr, u8, + witness->witness_element[j]->witness, + tal_count(witness->witness_element[j]->witness), + 0); + } + + /* Find the corresponding input in the transaction */ + for (j = 0; j < tal_count(utx->inputs); j++) { + if (bitcoin_txid_eq(&utx->inputs[j]->txid, &witness->prevtx_txid) && + utx->inputs[j]->index == witness->prevtx_vout) { + utx->inputs[j]->witness = tal_steal(utx->inputs[j], witnesses_arr); + break; + } + } + } + + return true; +} + static bool update_unreleased_tx(struct unreleased_tx *utx, struct bitcoin_tx *tx, u32 *input_map, - struct amount_sat opener_change, - struct witness_stack **witnesses) + struct amount_sat opener_change) { size_t i, j, num_other_ins, num_utxo; num_utxo = tal_count(utx->wtx->utxos); num_other_ins = tx->wtx->num_inputs - num_utxo; - assert(num_other_ins == tal_count(witnesses)); utx->inputs = tal_free(utx->inputs); utx->inputs = tal_arr(utx, struct bitcoin_tx_input *, num_other_ins); @@ -450,17 +481,6 @@ static bool update_unreleased_tx(struct unreleased_tx *utx, } else in->script = NULL; - in->witness = tal_arr(in, u8 *, - tal_count(witnesses[i]->witness_element)); - for (j = 0; j < tal_count(witnesses[i]->witness_element); j++) { - in->witness[j] = - tal_dup_arr(in->witness, - u8, - witnesses[i]->witness_element[j]->witness, - tal_count(witnesses[i]->witness_element[j]->witness), - 0); - } - utx->inputs[i] = in; } @@ -513,7 +533,6 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, struct funding_channel *fc = uc->fc; struct unreleased_tx *utx = fc->utx; u32 *input_map; - struct witness_stack **witnesses = NULL; /* This is a new channel_info.their_config so set its ID to 0 */ channel_info.their_config.id = 0; @@ -560,12 +579,17 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, } /* Update the funding tx that we have for this */ - if (!update_unreleased_tx(utx, funding_tx, input_map, opener_change, witnesses)) { + if (!update_unreleased_tx(utx, funding_tx, input_map, opener_change)) { log_broken(uc->log, "Unable to update unreleased tx"); uncommitted_channel_disconnect(uc, LOG_BROKEN, "internal error in creating updated tx"); goto cleanup; } + if (!add_remote_witnesses(utx, remote_witnesses)) { + log_broken(uc->log, "Unable to update unreleased tx with witnesses"); + uncommitted_channel_disconnect(uc, LOG_BROKEN, "internal error in updating tx witnesses"); + goto cleanup; + } bitcoin_tx_output_get_amount_sat(utx->tx, funding_txout, &total_funding); bitcoin_txid(funding_tx, &funding_txid); From 0ad86de1f2afefd1dda9a02741fe77334762c8e1 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 2 Dec 2019 13:11:42 -0600 Subject: [PATCH 050/131] df: convert accepter_sigs to new pattern, add input check we're now using funding_signed2 and a commitment_signed instead of the accepter_sigs method --- openingd/openingd.c | 148 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 31 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index f7125b1ba803..28eeded5e83e 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -973,15 +973,10 @@ static bool check_remote_input_outputs(struct state *state, /** * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - if is the `opener`: - * - MUST send at least one `funding_add_input` message + * ... * - MUST NOT send a total count of more than 64 inputs, * across all `funding_add_input` messages. */ - if (!tal_count(remote_inputs)) - peer_failed(state->pps, - &state->channel_id, - "Opener sent no funding inputs"); - if (tal_count(remote_inputs) > REMOTE_OPENER_INPUT_LIMIT) peer_failed(state->pps, &state->channel_id, @@ -1264,7 +1259,68 @@ static bool send_receive_funding_tx_info(struct state *state, return true; } -#endif + +static bool input_outpoint_eq(struct witness_stack *witness, + struct input_info *input) +{ + return bitcoin_txid_eq(&witness->prevtx_txid, &input->prevtx_txid) && + witness->prevtx_vout == input->prevtx_vout; +} + +static u32 sum_witness_len(struct witness_stack *witness) +{ + u32 len = 0; + for (size_t i = 0; i < tal_count(witness->witness_element); i++) + len += tal_count(witness->witness_element[i]->witness); + + return len; +} + +static char *check_remote_witnesses(struct witness_stack **witnesses, + struct input_info **inputs) +{ + size_t i, j; + u16 witness_len; + + if (tal_count(witnesses) != tal_count(inputs)) + return tal_fmt(tmpctx, "Received %zu witnesses for %zu inputs", + tal_count(witnesses), + tal_count(inputs)); + + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - if the `witness_stack` length exceeds `max_witness_len`: + * - MUST error. + */ + for (i = 0; i < tal_count(witnesses); i++) { + bool found = false; + for (j = 0; j < tal_count(inputs); j++) { + if (input_outpoint_eq(witnesses[i], inputs[j])) { + found = true; + witness_len = sum_witness_len(witnesses[i]); + if (witness_len > inputs[j]->max_witness_len) { + return tal_fmt(tmpctx, "Witness %s:%d len %u " + "larger than specified max %u", + type_to_string(tmpctx, + struct bitcoin_txid, + &witnesses[i]->prevtx_txid), + witnesses[i]->prevtx_vout, + witness_len, inputs[j]->max_witness_len); + } + break; + } + } + if (!found) + return tal_fmt(tmpctx, "No matching input found for witness %s:%u", + type_to_string(tmpctx, + struct bitcoin_txid, + &witnesses[i]->prevtx_txid), + witnesses[i]->prevtx_vout); + } + + return NULL; +} +#endif /*EXPERIMENTAL_FEATURES */ static u8 *funder_finalize_channel_setup2(struct state *state, struct utxo **utxos, @@ -1285,8 +1341,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, size_t i, input_count; struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; - // FIXME!! (don't set NULL) - const struct witness_stack **remote_witnesses = NULL; + struct witness_stack **remote_witnesses; /* Derive components, omitting the funding output */ derive_input_output_info(state, *tx, utxos, true, @@ -1401,29 +1456,18 @@ static u8 *funder_finalize_channel_setup2(struct state *state, return NULL; their_sig.sighash_type = SIGHASH_ALL; - /* FIXME!!! - if (!fromwire_accepter_sigs(state, msg, &id_in, - &their_sig.s, - (struct witness_stack ***)&remote_witnesses)) + + if (!fromwire_commitment_signed(state, msg, &id_in, &their_sig.s, NULL)) peer_failed(state->pps, &state->channel_id, - "Bad accepter_sigs in %s", tal_hex(msg, msg)); - */ + "Bad commitment_signed in %s", tal_hex(msg, msg)); peer_billboard(false, - "Opening channel: accepter_sigs received"); + "Opening channel: commitment_signed received"); /* Check that they're using the right channel_id */ check_channel_id(state, &id_in, &state->channel_id); - /* Check that they sent the right count of witnesses */ - if (tal_count(remote_witnesses) != tal_count(remote_ins)) - peer_failed(state->pps, - &state->channel_id, - "Received %zu witnesses for %zu inputs", - tal_count(remote_witnesses), - tal_count(remote_ins)); - /* We create *our* initial commitment transaction, and check the * signature they sent against that. */ local_commit = initial_channel_tx(state, &wscript, state->channel, @@ -1433,6 +1477,11 @@ static u8 *funder_finalize_channel_setup2(struct state *state, negotiation_failed(state, false, "Did not meet fees and reserve: %s", err_reason); + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * The sending node: + * - MUST verify it has received valid commitment signatures from its peer + */ if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey, &their_sig)) peer_failed(state->pps, &state->channel_id, @@ -1444,7 +1493,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->their_funding_pubkey)); peer_billboard(false, - "Opening channel: accepter sigs are acceptable, moving to sign tx %s", + "Opening channel: commitment sigs are acceptable, moving to sign tx %s", type_to_string(state, struct bitcoin_tx, funding_tx)); u32 *i_map = tal_arr(state, u32, input_count); @@ -1452,6 +1501,40 @@ static u8 *funder_finalize_channel_setup2(struct state *state, i_map[i] = ptr2int(map[i]); } + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - MUST set `witness` to the serialized witness data for the input + * corresponding to `prevtx_txid`:`prevtx_vout` + */ + + /* Wait for their funding_signed2 message */ + msg = opening_negotiate_msg(tmpctx, state, true); + if (!msg) + return NULL; + + if (!fromwire_funding_signed2(state, msg, + &id_in, &remote_witnesses)) + peer_failed(state->pps, + &state->channel_id, + "Bad funding_signed2 in %s", tal_hex(msg, msg)); + + /* Check remote witness info */ + err_reason = check_remote_witnesses(remote_witnesses, remote_ins); + if (err_reason) + peer_failed(state->pps, &state->channel_id, + "%s", err_reason); + + + /* Pass back all of the funding and commitment tx info so that + * we can commit to disk. We also start listening for funding confirms + * since as soon as we send our sigs for the funding tx they may + * broadcast (we may never hear back from the peer here) */ + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * The sending node: + * ... + * - MUST remember the details of this funding transaction. + */ return towire_opening_dual_funding_signed(state, state->pps, local_commit, @@ -1459,7 +1542,8 @@ static u8 *funder_finalize_channel_setup2(struct state *state, funding_tx, state->funding_txout, opener_change, - remote_witnesses, + cast_const2(const struct witness_stack **, + remote_witnesses), i_map, state->opener_funding, &state->remoteconf, @@ -2181,11 +2265,13 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) * to save state to disk before doing so. */ assert(our_sig.sighash_type == SIGHASH_ALL); - /* FIXME: commitment_signed send dance etc!! - msg = towire_accepter_sigs(state, &state->channel_id, - &our_sig.s, - cast_const2(const struct witness_stack **, our_stack)); - */ + /* We send our commitment sigs */ + msg = towire_commitment_signed(state, &state->channel_id, &our_sig.s, NULL); + sync_crypto_write(state->pps, take(msg)); + + /* We send funding_signed2 after we've committed this to disk */ + msg = towire_funding_signed2(state, &state->channel_id, + cast_const2(const struct witness_stack **, our_stack)); /* we send everything to lightning, who commits things to the database etc. * lightningd will forward the signatures etc over to channeld, who From d55ffe99c47319521cdb1e6f487cf68383d02147 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 6 Feb 2020 19:43:53 -0600 Subject: [PATCH 051/131] mocks: update the mocks (while rebasing) --- onchaind/test/run-grind_feerate-bug.c | 2 +- onchaind/test/run-grind_feerate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index 73a760bd18e6..bc26d2b09437 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -43,7 +43,7 @@ bool fromwire_onchain_dev_memleak(const void *p UNNEEDED) bool fromwire_onchain_htlc(const void *p UNNEEDED, struct htlc_stub *htlc UNNEEDED, bool *tell_if_missing UNNEEDED, bool *tell_immediately UNNEEDED) { fprintf(stderr, "fromwire_onchain_htlc called!\n"); abort(); } /* Generated stub for fromwire_onchain_init */ -bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *funder UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED) +bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED) { fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); } /* Generated stub for fromwire_onchain_known_preimage */ bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED) diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 41dadcfdfe3a..8d11c154991e 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -47,7 +47,7 @@ bool fromwire_onchain_dev_memleak(const void *p UNNEEDED) bool fromwire_onchain_htlc(const void *p UNNEEDED, struct htlc_stub *htlc UNNEEDED, bool *tell_if_missing UNNEEDED, bool *tell_immediately UNNEEDED) { fprintf(stderr, "fromwire_onchain_htlc called!\n"); abort(); } /* Generated stub for fromwire_onchain_init */ -bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *funder UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED) +bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED) { fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); } /* Generated stub for fromwire_onchain_known_preimage */ bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED) From 4e869922ba9d577395a1ef53c84ed069221c3063 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 2 Dec 2019 14:56:16 -0600 Subject: [PATCH 052/131] df: save incoming peer messages until we return since fundchannel_start / fundchannel_complete splits the control on the funder's side, we need to stash incoming funding_add messages until we're able to process them. --- openingd/openingd.c | 51 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 28eeded5e83e..e691ce9328c4 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -122,6 +122,12 @@ struct state { bool use_v2; struct amount_sat accepter_funding; u32 feerate_per_kw_funding; + + /* List of queued add input/output/completes. + * These get queued up while we're in transition + * between fundchannel_start and fundchannel_complete + */ + u8 **funding_msg_queue; }; static u8 *dev_upfront_shutdown_script(const tal_t *ctx) @@ -177,6 +183,7 @@ static void negotiation_aborted(struct state *state, bool am_opener, * failed. */ memset(&state->channel_id, 0, sizeof(state->channel_id)); state->channel = tal_free(state->channel); + state->funding_msg_queue = tal_free(state->funding_msg_queue); } /*~ For negotiation failures: we tell them the parameter we didn't like. */ @@ -548,6 +555,9 @@ static bool setup_channel_funder(struct state *state) set_reserve(state); } + /* Initialize the msg queue */ + state->funding_msg_queue = tal_arr(state, u8 *, 0); + /*~ Grab a random ID until the funding tx is created (we can't do that * until we know their funding_pubkey) */ temporary_channel_id(&state->channel_id); @@ -821,6 +831,14 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) } #if EXPERIMENTAL_FEATURES +/* Queue a 'pending' add_funding message. We'll + * process these after the break. */ +static void queue_msg(struct state *state, u8 *msg) +{ + tal_arr_expand(&state->funding_msg_queue, + tal_steal(state->funding_msg_queue, msg)); +} + static void check_channel_id(struct state *state, struct channel_id *id_in, struct channel_id *original_channel_id) @@ -1108,7 +1126,7 @@ static bool send_receive_funding_tx_info(struct state *state, { struct channel_id id_in; bool complete; - size_t i; + size_t i, queue_count; u8 *msg; /* @@ -1173,13 +1191,21 @@ static bool send_receive_funding_tx_info(struct state *state, *remote_inputs = tal_arr(state, struct input_info *, 0); *remote_outputs = tal_arr(state, struct output_info *, 0); + queue_count = 0; while (!complete) { struct input_info **inputs; struct output_info **outputs; u16 num_ins, num_outs; int type; - msg = opening_negotiate_msg(tmpctx, state, role == OPENER); + /* First we get messages off the queue, if any */ + if (queue_count < tal_count(state->funding_msg_queue)) { + msg = state->funding_msg_queue[queue_count++]; + } else { + /* We pull it off the wire */ + msg = opening_negotiate_msg(tmpctx, state, role == OPENER); + } + if (!msg) return false; @@ -1257,6 +1283,9 @@ static bool send_receive_funding_tx_info(struct state *state, } } + /* Free the message queue */ + state->funding_msg_queue = tal_free(state->funding_msg_queue); + return true; } @@ -2068,14 +2097,9 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) accept_tlv); sync_crypto_write(state->pps, take(msg)); - peer_billboard(false, "Incoming channel: accepted, now " "waiting for them to send funding_compose"); - msg = opening_negotiate_msg(tmpctx, state, false); - if (!msg) - return NULL; - /* Convert our inputs/outputs to the correct format */ inputs_to_infos(state, utxos, &our_inputs); our_outputs = outputs_to_infos(state, outputs); @@ -2658,10 +2682,18 @@ static u8 *handle_peer_in(struct state *state) return fundee_channel(state, msg); } #if EXPERIMENTAL_FEATURES - else if (t == WIRE_OPEN_CHANNEL2) { + if (t == WIRE_OPEN_CHANNEL2) { state->use_v2 = true; return fundee_channel2(state, msg); } + if (t == WIRE_FUNDING_ADD_INPUT + || t == WIRE_FUNDING_ADD_OUTPUT + || t == WIRE_FUNDING_ADD_COMPLETE) { + /* add to queue for this state/peer because + * it's possible we're off getting ready for multi-fund whatever.*/ + queue_msg(state, msg); + return NULL; + } #endif /* EXPERIMENTAL_FEATURES */ #if DEVELOPER @@ -2910,6 +2942,9 @@ int main(int argc, char *argv[]) = state->upfront_shutdown_script[REMOTE] = NULL; + /* We'll initialize the msg queue for the funder flow */ + state->funding_msg_queue = NULL; + /*~ We need an initial per-commitment point whether we're funding or * they are, and lightningd has reserved a unique dbid for us already, * so we might as well get the hsm daemon to generate it now. */ From 0ab1aaec17f463b40eb2f9314123f3ff5b31e8b3 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 2 Dec 2019 14:57:49 -0600 Subject: [PATCH 053/131] df: fixup, need to pass a not null in to to/from wire pass in an 'unused' htlc placeholder, and verify that it's null --- openingd/openingd.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index e691ce9328c4..f9ba25932604 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1366,6 +1366,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, struct amount_sat total_funding, opener_change; struct bitcoin_signature their_sig, our_sig; struct amount_msat local_funding_msat; + secp256k1_ecdsa_signature *unused_htlcs; size_t i, input_count; struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; @@ -1486,11 +1487,23 @@ static u8 *funder_finalize_channel_setup2(struct state *state, their_sig.sighash_type = SIGHASH_ALL; - if (!fromwire_commitment_signed(state, msg, &id_in, &their_sig.s, NULL)) + if (!fromwire_commitment_signed(state, msg, &id_in, &their_sig.s, &unused_htlcs)) peer_failed(state->pps, &state->channel_id, "Bad commitment_signed in %s", tal_hex(msg, msg)); + /* + * BOLT-0254a8b2ffa21769240d35b33de28b582dc568b2 #2 + * The receiving node: + * - if the message has one or more HTLC's: + * - MUST fail the channel. + */ + if (unused_htlcs != NULL) + peer_failed(state->pps, + &state->channel_id, + "Unexpected HTLCs in commitment_signed %s", + tal_hex(msg, msg)); + peer_billboard(false, "Opening channel: commitment_signed received"); From dd026ff3358a11c9edf5a363b02e16b56ef1c7f0 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 9 Oct 2019 13:41:06 -0500 Subject: [PATCH 054/131] dual-funding: confirm scriptpubkey matches what's onchain For any inputs our peers send, we should verify that the scriptpubkey and amounts are in fact accurate --- lightningd/opening_control.c | 98 ++++++++++++++++++++++++++++++++++++ openingd/opening_wire.csv | 12 +++++ openingd/openingd.c | 31 +++++++++--- 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 629697c8fb69..102f75740655 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -715,6 +717,95 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, tal_free(fc->uc); } +#if EXPERIMENTAL_FEATURES +struct input_set { + u16 last_index; + struct input_info **inputs; + struct subd *openingd; +}; + +static void output_lookup_cb(struct bitcoind *bitcoind, + const struct bitcoin_tx_output *output, + void *arg) + +{ + char *err_msg; + struct input_info *in; + struct input_set *set = (struct input_set *)arg; + + log_debug(bitcoind->log, "checking inputs; last index is %d, count is %ld", + set->last_index, tal_count(set->inputs)); + in = set->inputs[set->last_index]; + + if (output) { + /* Check that output's scriptpubkey matches */ + if (!memeq(in->prevtx_scriptpubkey, tal_count(in->prevtx_scriptpubkey), + output->script, tal_count(output->script))) { + err_msg = tal_fmt(tmpctx, "Output %s:%d found; scripts not equal. " + "Peer provided %s; found onchain %s", + type_to_string(tmpctx, struct bitcoin_txid, + &in->prevtx_txid), + in->prevtx_vout, + tal_hex(tmpctx, in->prevtx_scriptpubkey), + tal_hex(tmpctx, output->script)); + /* Check that output's amount matches */ + } else if (!amount_sat_eq(in->sats, output->amount)) { + err_msg = tal_fmt(tmpctx, "Output %s:%d found; amounts not equal. " + "Peer provided %s; found onchain %s", + type_to_string(tmpctx, struct bitcoin_txid, + &in->prevtx_txid), + in->prevtx_vout, + type_to_string(tmpctx, struct amount_sat, + &in->sats), + type_to_string(tmpctx, struct amount_sat, + &output->amount)); + } else + err_msg = NULL; + } else + err_msg = tal_fmt(tmpctx, "Output %s:%d not found", + type_to_string(tmpctx, struct bitcoin_txid, + &in->prevtx_txid), + in->prevtx_vout); + + set->last_index++; + if (err_msg || set->last_index == tal_count(set->inputs)) { + subd_send_msg(set->openingd, + take(towire_opening_check_inputs_reply( + NULL, (const u8 *)err_msg))); + tal_free(set); + return; + } + + /* There's still more to go, let's go! */ + in = set->inputs[set->last_index]; + bitcoind_getutxout(bitcoind, &in->prevtx_txid, + in->prevtx_vout, + output_lookup_cb, set); +} + +static void verify_inputs(struct subd *openingd, + const u8 *msg, + struct uncommitted_channel *uc) +{ + struct input_set *set; + + set = tal(NULL, struct input_set); + if (!fromwire_opening_check_inputs(set, msg, + &set->inputs)) + fatal("bad OPENING_FUNDEE_REPLY %s", tal_hex(msg, msg)); + + assert(tal_count(set->inputs) > 0); + + set->openingd = openingd; + set->last_index = 0; + bitcoind_getutxout(openingd->ld->topology->bitcoind, + &set->inputs[0]->prevtx_txid, + set->inputs[0]->prevtx_vout, + output_lookup_cb, + (void *)notleak(set)); +} +#endif /* EXPERIMENTAL_FEATURES */ + static void opening_fundee_finished(struct subd *openingd, const u8 *reply, const int *fds, @@ -1360,6 +1451,12 @@ static unsigned int openingd_msg(struct subd *openingd, opening_got_offer(openingd, msg, uc); return 0; + case WIRE_OPENING_CHECK_INPUTS: +#if EXPERIMENTAL_FEATURES + verify_inputs(openingd, msg, uc); +#endif /* EXPERIMENTAL_FEATURES */ + return 0; + /* We send these! */ case WIRE_OPENING_INIT: case WIRE_OPENING_FUNDER_START: @@ -1367,6 +1464,7 @@ static unsigned int openingd_msg(struct subd *openingd, case WIRE_OPENING_FUNDER_CANCEL: case WIRE_OPENING_GOT_OFFER_REPLY: case WIRE_OPENING_GOT_OFFER_REPLY_FUND: + case WIRE_OPENING_CHECK_INPUTS_REPLY: case WIRE_OPENING_DEV_MEMLEAK: /* Replies never get here */ case WIRE_OPENING_DEV_MEMLEAK_REPLY: diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index ae15a1713908..4b1116e9be01 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -176,6 +176,18 @@ msgdata,opening_dual_funding_signed,local_reserve,amount_sat, msgdata,opening_dual_funding_signed,shutdown_len,u16, msgdata,opening_dual_funding_signed,shutdown_scriptpubkey,u8,shutdown_len +# openingd -> master: are these inputs valid? +msgtype,opening_check_inputs,6312 +#if EXPERIMENTAL_FEATURES +msgdata,opening_check_inputs,num_inputs,u32, +msgdata,opening_check_inputs,inputs,input_info,num_inputs + +# master -> openingd: input check result. +# Empty error means ok +msgtype,opening_check_inputs_reply,6314 +msgdata,opening_check_inputs_reply,len,u16, +msgdata,opening_check_inputs_reply,err_msg,u8,len + # master -> openingd: do you have a memleak? msgtype,opening_dev_memleak,6033 diff --git a/openingd/openingd.c b/openingd/openingd.c index f9ba25932604..dd8ea8dc607d 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -982,10 +982,10 @@ static bool check_remote_input_outputs(struct state *state, struct output_info **remote_outputs, struct amount_sat stated_funding_sats) { - size_t i = 0; struct amount_sat funding, other_outputs, funding_tx_sats; bool has_change_address; - u8 *wscript; + size_t i = 0; + u8 *msg, *err_msg, *wscript; if (remote_role == OPENER) { /** @@ -998,7 +998,9 @@ static bool check_remote_input_outputs(struct state *state, if (tal_count(remote_inputs) > REMOTE_OPENER_INPUT_LIMIT) peer_failed(state->pps, &state->channel_id, - "Opener sent no funding inputs"); + "%zu surpassed maximum input limit %u", + tal_count(remote_inputs), + REMOTE_OPENER_INPUT_LIMIT); } else { /** * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 @@ -1113,6 +1115,23 @@ static bool check_remote_input_outputs(struct state *state, type_to_string(tmpctx, struct amount_sat, &funding_tx_sats)); + /* If there's no inputs, there's nothing to check */ + if (!tal_count(remote_inputs)) + return true; + + /* Send their inputs master to verify via bitcoind */ + msg = towire_opening_check_inputs(NULL, + cast_const2(const struct input_info **, + remote_inputs)); + + wire_sync_write(REQ_FD, take(msg)); + msg = wire_sync_read(tmpctx, REQ_FD); + if (!fromwire_opening_check_inputs_reply(tmpctx, msg, &err_msg)) + master_badmsg(WIRE_OPENING_CHECK_INPUTS_REPLY, msg); + + if (err_msg) + peer_failed(state->pps, &state->channel_id, "%s", err_msg); + return true; } @@ -1388,8 +1407,6 @@ static u8 *funder_finalize_channel_setup2(struct state *state, state->accepter_funding)) return NULL; - /* FIXME: send their inputs master to verify via bitcoind */ - input_count = tal_count(local_ins) + tal_count(remote_ins); const void *map[input_count]; for (i = 0; i < input_count; i++) @@ -2033,8 +2050,6 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) if (!fundee_check_primitives(state, chain_hash)) return NULL; - // we do all the reserve checks after we've gotten their amounts - /* Check with lightningd that we can accept this? In particular, * if we have an existing channel, we don't support it. */ msg = towire_opening_got_offer(NULL, @@ -2865,6 +2880,8 @@ static u8 *handle_master_in(struct state *state) case WIRE_OPENING_GOT_OFFER: case WIRE_OPENING_GOT_OFFER_REPLY: case WIRE_OPENING_GOT_OFFER_REPLY_FUND: + case WIRE_OPENING_CHECK_INPUTS: + case WIRE_OPENING_CHECK_INPUTS_REPLY: break; } From ba88dc53c7359cf17d7d0c1569dd8aa489a1cfe4 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 10 Sep 2019 14:12:02 -0500 Subject: [PATCH 055/131] df/wallet: add expiring leases to output reservations dual funding means that we'll now have utxos that have been shared but not spent (this means they might become spent, but they're not longer eligible to be 'unreserved'). this patch adds the ability to track 'reserved' utxos and to record the blockheight that they are 'reserved' at, along with a lease time at which they'll be considered no longer reserved. --- common/utxo.h | 8 ++ wallet/db.c | 2 + wallet/test/run-wallet.c | 67 ++++++++- wallet/wallet.c | 291 ++++++++++++++++++++++++++++++++++++--- wallet/wallet.h | 16 +++ 5 files changed, 361 insertions(+), 23 deletions(-) diff --git a/common/utxo.h b/common/utxo.h index 1652cc2c6e9e..c847d5fcb365 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -39,6 +39,14 @@ struct utxo { /* NULL if not spent yet, otherwise, the block the spending transaction is in */ const u32 *spendheight; + /* NULL if not a timed reservation; otherwise, the block height + * the utxo was reserved at */ + const u32 *reserved_at; + + /* NULL if not a timed reservation; otherwise, the number of + * blocks the utxo is reserved for */ + const u32 *reserved_for; + /* The scriptPubkey if it is known */ u8 *scriptPubkey; diff --git a/wallet/db.c b/wallet/db.c index 3f881d899431..898f9c2194de 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -599,6 +599,8 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channel_htlcs ADD localfailmsg BLOB;"), NULL}, {SQL("UPDATE channel_htlcs SET localfailmsg=decode('2002', 'hex') WHERE malformed_onion != 0 AND direction = 1;"), NULL}, {SQL("ALTER TABLE channels ADD our_funding_satoshi INTEGER DEFAULT 0;"), migrate_our_funding}, + {SQL("ALTER TABLE outputs ADD reserved_at INTEGER DEFAULT NULL;"), NULL}, + {SQL("ALTER TABLE outputs ADD reserved_for INTEGER DEFAULT NULL;"), NULL}, }; /* Leak tracking. */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 990dfea21b7b..f5cac02c6ec3 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -868,6 +868,11 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) struct node_id id; struct amount_sat fee_estimate, change_satoshis; const struct utxo **utxos; + u32 height = 10, reserve_for_blocks = 20; + + /* Set the chaintip height to 15 */ + ld->topology->tip->height = 15; + CHECK(w); memset(&u, 0, sizeof(u)); @@ -932,6 +937,61 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) output_state_spent), "could not change output state ignoring oldstate"); + /* Check for 'reserved' state changes */ + utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + 0 /* no confirmations required */, + &fee_estimate, &change_satoshis); + CHECK(utxos && tal_count(utxos) == 1); + + u = *utxos[0]; + + /* Add expiration to reservation */ + CHECK_MSG(wallet_output_reservation_update(w, &u, height, reserve_for_blocks), + "could not add high watermark for reserved output"); + + /* Now attempt to un-reserve them, should fail since we check + * whether the reservation lease has expired or not */ + tal_free(utxos); + + /* Now should be unable to select 1 sat amount */ + CHECK_MSG(!wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + 0 /* no confirmations required */, + &fee_estimate, &change_satoshis), + "too many utxos available"); + + /* Get reserved utxos */ + utxos = (const struct utxo **)wallet_get_utxos(w, w, output_state_reserved); + CHECK(utxos && tal_count(utxos) == 1); + + /* Check that reserved_at height and reserved_for is set */ + CHECK(*utxos[0]->reserved_at == height); + CHECK(*utxos[0]->reserved_for == reserve_for_blocks); + tal_free(utxos); + + /* Expire the lease! */ + ld->topology->tip->height = height + reserve_for_blocks; + + utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + 0 /* no confirmations required */, + &fee_estimate, &change_satoshis); + CHECK_MSG(utxos && tal_count(utxos) == 1, "utxo count is incorrect"); + + /* Check that we freeing them resets them to available */ + tal_free(utxos); + + /* There should be no reserved utxos */ + utxos = (const struct utxo **)wallet_get_utxos(w, w, output_state_reserved); + CHECK(tal_count(utxos) == 0); + + /* check that we can mark as spent */ + utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + 0 /* no confirmations required */, + &fee_estimate, &change_satoshis); + CHECK_MSG(utxos && tal_count(utxos) == 1, "utxo count is incorrect"); + wallet_confirm_utxos(w, utxos); + + tal_free(utxos); + /* Attempt to save an UTXO with close_info set, no commitment_point */ memset(&u.txid, 2, sizeof(u.txid)); u.amount = AMOUNT_SAT(5); @@ -946,9 +1006,9 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(5), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); - CHECK(utxos && tal_count(utxos) == 2); + CHECK(utxos && tal_count(utxos) == 1); - u = *utxos[1]; + u = *utxos[0]; CHECK(u.close_info->channel_id == 42 && u.close_info->commitment_point == NULL && node_id_eq(&u.close_info->peer_id, &id)); @@ -1450,6 +1510,9 @@ int main(void) /* Only elements in ld we should access */ list_head_init(&ld->peers); + ld->topology = tal(ld, struct chain_topology); + ld->topology->tip = tal(ld, struct block); + node_id_from_hexstr("02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66, &ld->id); /* Accessed in peer destructor sanity check */ htlc_in_map_init(&ld->htlcs_in); diff --git a/wallet/wallet.c b/wallet/wallet.c index 9d451e1c1989..a95fb5dca4e3 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -109,7 +109,9 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, db_bind_int(stmt, 1, utxo->outnum); db_bind_amount_sat(stmt, 2, &utxo->amount); db_bind_int(stmt, 3, wallet_output_type_in_db(type)); + db_bind_int(stmt, 4, output_state_available); + db_bind_int(stmt, 5, utxo->keyindex); if (utxo->close_info) { db_bind_u64(stmt, 6, utxo->close_info->channel_id); @@ -150,7 +152,7 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) { struct utxo *utxo = tal(ctx, struct utxo); - u32 *blockheight, *spendheight; + u32 *blockheight, *spendheight, *reserved_at, *reserved_for; db_column_txid(stmt, 0, &utxo->txid); utxo->outnum = db_column_int(stmt, 1); db_column_amount_sat(stmt, 2, &utxo->amount); @@ -176,6 +178,8 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->spendheight = NULL; utxo->scriptPubkey = NULL; utxo->scriptSig = NULL; + utxo->reserved_at = NULL; + utxo->reserved_for = NULL; if (!db_column_is_null(stmt, 9)) { blockheight = tal(utxo, u32); @@ -194,10 +198,30 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) tal_dup_arr(utxo, u8, db_column_blob(stmt, 11), db_column_bytes(stmt, 11), 0); } + if (!db_column_is_null(stmt, 12)) { + reserved_at = tal(utxo, u32); + *reserved_at = db_column_int(stmt, 12); + utxo->reserved_at = reserved_at; + + reserved_for = tal(utxo, u32); + *reserved_for = db_column_int(stmt, 13); + utxo->reserved_for = reserved_for; + } return utxo; } +static bool reservation_expired(struct wallet *w, const struct utxo *utxo) +{ + return utxo->reserved_at && + *utxo->reserved_at + *utxo->reserved_for >= w->ld->topology->tip->height; +} + +static bool wallet_clear_reservation(struct wallet *w, struct utxo *utxo) +{ + return wallet_output_reservation_update(w, utxo, 0, 0); +} + bool wallet_update_output_status(struct wallet *w, const struct bitcoin_txid *txid, const u32 outnum, enum output_status oldstatus, @@ -227,6 +251,124 @@ bool wallet_update_output_status(struct wallet *w, return changes > 0; } +static bool assert_utxo_status(struct wallet *w, + const struct bitcoin_txid *txid, + const u32 outnum, + const enum output_status state) +{ + struct db_stmt *stmt; + bool res; + + stmt = db_prepare_v2(w->db, SQL("SELECT COUNT(*) FROM outputs " + "WHERE status=? AND prev_out_tx=? " + "AND prev_out_index=?")); + db_bind_int(stmt, 0, output_status_in_db(state)); + db_bind_txid(stmt, 1, txid); + db_bind_int(stmt, 2, outnum); + + db_query_prepared(stmt); + if (db_step(stmt)) { + res = db_column_u64(stmt, 0) > 0; + } else + res = false; + + tal_free(stmt); + return res; +} + +/* Given a utxo, check that it is eligible to be marked as reserved. + * This used to be a simple state check, but since we added 'expireable' + * reservations, we can 're-reserve' inputs if the original reservation + * has expired, while clearing out the expiration info + */ +static bool wallet_reserve_output(struct wallet *w, struct utxo *u) +{ + if (u->status == output_state_reserved) { + assert(reservation_expired(w, u)); + return wallet_clear_reservation(w, u); + + } + + return wallet_update_output_status(w, &u->txid, u->outnum, + output_state_available, output_state_reserved); +} + +bool wallet_output_reservation_update(struct wallet *w, + struct utxo *utxo, + const u32 current_height, + const u32 reserve_for) +{ + struct db_stmt *stmt; + size_t changes; + + /* If not already reserved, say no */ + if (!assert_utxo_status(w, &utxo->txid, utxo->outnum, output_state_reserved)) + return false; + + if (current_height != 0 && current_height + reserve_for < current_height) + fatal("reserved utxo current_height %u + reserve_for wraps %u", + current_height, reserve_for); + + stmt = db_prepare_v2(w->db, + SQL("UPDATE outputs" + " SET reserved_at = ?, reserved_for = ?" + " WHERE prev_out_tx = ? AND prev_out_index = ?")); + if (current_height == 0 || reserve_for == 0) { + db_bind_null(stmt, 0); + db_bind_null(stmt, 1); + } else { + db_bind_int(stmt, 0, current_height); + db_bind_int(stmt, 1, reserve_for); + } + db_bind_sha256d(stmt, 2, &utxo->txid.shad); + db_bind_int(stmt, 3, utxo->outnum); + db_exec_prepared_v2(stmt); + changes = db_count_changes(stmt); + tal_free(stmt); + + return changes > 0; +} + +static struct utxo *wallet_get_utxo(const tal_t *ctx, struct wallet *w, + const struct bitcoin_txid txid, const u32 outnum) +{ + struct utxo *result; + struct db_stmt *stmt; + + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", confirmation_height" + ", spend_height" + ", scriptpubkey" + ", reserved_at" + ", reserved_for" + " FROM outputs" + " WHERE prev_out_tx = ? AND prev_out_index = ?")); + + db_bind_sha256d(stmt, 0, &txid.shad); + db_bind_int(stmt, 1, outnum); + + db_query_prepared(stmt); + + if (!db_step(stmt)) { + tal_free(stmt); + return NULL; + } + + result = wallet_stmt2output(ctx, stmt); + tal_free(stmt); + + return result; +} + struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum output_status state) { struct utxo **results; @@ -246,8 +388,10 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", commitment_point" ", confirmation_height" ", spend_height" - ", scriptpubkey " - "FROM outputs")); + ", scriptpubkey" + ", reserved_at" + ", reserved_for" + " FROM outputs")); } else { stmt = db_prepare_v2(w->db, SQL("SELECT" " prev_out_tx" @@ -261,9 +405,11 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", commitment_point" ", confirmation_height" ", spend_height" - ", scriptpubkey " - "FROM outputs " - "WHERE status= ? ")); + ", scriptpubkey" + ", reserved_at" + ", reserved_for" + " FROM outputs" + " WHERE status= ?")); db_bind_int(stmt, 0, output_status_in_db(state)); } db_query_prepared(stmt); @@ -298,6 +444,8 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, ", confirmation_height" ", spend_height" ", scriptpubkey" + ", reserved_at" + ", reserved_for" " FROM outputs" " WHERE channel_id IS NOT NULL AND " "confirmation_height IS NULL")); @@ -313,16 +461,116 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, return results; } +static struct utxo **wallet_get_expired_reserved_utxos(const tal_t *ctx, + struct wallet *w) +{ + struct db_stmt *stmt; + struct utxo **results; + int i; + + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", confirmation_height" + ", spend_height" + ", scriptpubkey" + ", reserved_at" + ", reserved_for" + " FROM outputs" + " WHERE status = ?" + " AND reserved_at IS NOT NULL" + " AND reserved_at + reserved_for <= ?")); + + db_bind_int(stmt, 0, output_status_in_db(output_state_reserved)); + db_bind_int(stmt, 1, w->ld->topology->tip->height); + + db_query_prepared(stmt); + + if (stmt->error) { + log_broken(w->log, "SQL error: %s", stmt->error); + return NULL; + } + + results = tal_arr(ctx, struct utxo *, 0); + for (i = 0; db_step(stmt); i++) { + struct utxo *u = wallet_stmt2output(results, stmt); + tal_arr_expand(&results, u); + } + tal_free(stmt); + + return results; +} + +/* Reserved utxos are ok, if they're expired. In fact, we really + * want to use those first, so we put them at the head of the + * spendable list */ +// FIXME: we lose this info after an expired utxo is re-reserved +static struct utxo **wallet_get_spendable_utxos(const tal_t *ctx, + struct wallet *w) +{ + struct utxo **reserved, **available; + size_t rcount; + + reserved = wallet_get_expired_reserved_utxos(ctx, w); + available = wallet_get_utxos(ctx, w, output_state_available); + + rcount = tal_count(reserved); + tal_resize(&reserved, rcount + tal_count(available)); + for (size_t i = 0; i < tal_count(available); i++) + reserved[rcount + i] = tal_steal(reserved, available[i]); + + tal_free(available); + return reserved; +} + + + /** * unreserve_utxo - Mark a reserved UTXO as available again */ static void unreserve_utxo(struct wallet *w, const struct utxo *unres) { + struct utxo *utxo; + + /* Check that is currently eligible to be unreserved. + * We refresh from the database to make sure that the underlying + * data hasn't changed out from underneath us */ + utxo = wallet_get_utxo(NULL, w, unres->txid, unres->outnum); + if (utxo && utxo->reserved_at) { + assert(utxo->status == output_state_reserved); + u32 unreserve_at = *utxo->reserved_at + *utxo->reserved_for; + if (*utxo->reserved_at > unreserve_at) + fatal("reserved utxo current_height %u + reserve_for %u wraps", + *utxo->reserved_at, *utxo->reserved_for); + if (w->ld->topology->tip->height < unreserve_at) { + log_info(w->log, "Unable to unreserve utxo %s:%u, height is %u, " + "unreserves at %u", + type_to_string(tmpctx, struct bitcoin_txid, &utxo->txid), + utxo->outnum, + w->ld->topology->tip->height, + unreserve_at); + + tal_free(utxo); + return; + } + + if (!wallet_clear_reservation(w, utxo)) + fatal("Unable to clear utxo reservation"); + + } if (!wallet_update_output_status(w, &unres->txid, unres->outnum, output_state_reserved, - output_state_available)) { + output_state_available)) fatal("Unable to unreserve output"); - } + + tal_free(utxo); } /** @@ -340,9 +588,8 @@ void wallet_confirm_utxos(struct wallet *w, const struct utxo **utxos) for (size_t i = 0; i < tal_count(utxos); i++) { if (!wallet_update_output_status( w, &utxos[i]->txid, utxos[i]->outnum, - output_state_reserved, output_state_spent)) { + output_state_reserved, output_state_spent)) fatal("Unable to mark output as spent"); - } } } @@ -356,7 +603,7 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, struct amount_sat *fee_estimate) { size_t i = 0; - struct utxo **available; + struct utxo **spendable; u64 weight; size_t num_outputs = may_have_change ? 2 : 1; const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0); @@ -394,12 +641,12 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, *fee_estimate = AMOUNT_SAT(0); *satoshi_in = AMOUNT_SAT(0); - available = wallet_get_utxos(ctx, w, output_state_available); + spendable = wallet_get_spendable_utxos(ctx, w); - for (i = 0; i < tal_count(available); i++) { + for (i = 0; i < tal_count(spendable); i++) { size_t input_weight; struct amount_sat needed; - struct utxo *u = tal_steal(utxos, available[i]); + struct utxo *u = tal_steal(utxos, spendable[i]); /* If we require confirmations check that we have a * confirmation height and that it is below the required @@ -412,9 +659,7 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, tal_arr_expand(&utxos, u); - if (!wallet_update_output_status( - w, &available[i]->txid, available[i]->outnum, - output_state_available, output_state_reserved)) + if (!wallet_reserve_output(w, u)) fatal("Unable to reserve output"); /* Input weight: txid + index + sequence */ @@ -437,8 +682,8 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, weight += input_weight; if (!amount_sat_add(satoshi_in, *satoshi_in, u->amount)) - fatal("Overflow in available satoshis %zu/%zu %s + %s", - i, tal_count(available), + fatal("Overflow in spendable satoshis %zu/%zu %s + %s", + i, tal_count(spendable), type_to_string(tmpctx, struct amount_sat, satoshi_in), type_to_string(tmpctx, struct amount_sat, @@ -447,14 +692,14 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, *fee_estimate = amount_tx_fee(feerate_per_kw, weight); if (!amount_sat_add(&needed, sat, *fee_estimate)) fatal("Overflow in fee estimate %zu/%zu %s + %s", - i, tal_count(available), + i, tal_count(spendable), type_to_string(tmpctx, struct amount_sat, &sat), type_to_string(tmpctx, struct amount_sat, fee_estimate)); if (amount_sat_greater_eq(*satoshi_in, needed)) break; } - tal_free(available); + tal_free(spendable); return utxos; } @@ -560,6 +805,8 @@ static struct utxo **sorted_confirmed_utxos(const tal_t *ctx, struct wallet *w, ", confirmation_height" ", spend_height" ", scriptpubkey " + ", reserved_at" + ", reserved_for" " FROM outputs" " WHERE confirmation_height IS NOT NULL" " ORDER BY value DESC")); @@ -577,6 +824,8 @@ static struct utxo **sorted_confirmed_utxos(const tal_t *ctx, struct wallet *w, ", confirmation_height" ", spend_height" ", scriptpubkey " + ", reserved_at" + ", reserved_for" " FROM outputs" " WHERE status = ?" " AND confirmation_height IS NOT NULL" diff --git a/wallet/wallet.h b/wallet/wallet.h index 829431e87775..13f80109c7da 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -364,6 +364,22 @@ bool wallet_update_output_status(struct wallet *w, const u32 outnum, enum output_status oldstatus, enum output_status newstatus); +/** + * wallet_output_reservation_update - Add an expiration for a utxo reservation + * Update a reserved output's reserved_at and reserved_for in the database. + * Will be returned to available upon expiration. + * + * Output must currently be in `reserved` state. Passing in 0 for *either* + * current-height or reserved-for will set both fields to NULL, effectively + * ending the 'expiring' reservation. + * + * @utxo - output to update + * @current_height - current blockeheight + * @reserve_for - number of blocks to hold reservation */ +bool wallet_output_reservation_update(struct wallet *w, + struct utxo *utxo, + const u32 current_height, + const u32 reserved_for); /** * wallet_get_utxos - Retrieve all utxos matching a given state * From d45aeec843a765abc6fd3d4d69b2d1afdc273847 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 6 Dec 2019 12:34:38 -0600 Subject: [PATCH 056/131] wallet/df: set priority on utxo for spending Since we recycle utxos through, we want to be able to keep track of a light 'priority' to spend utxos with, such that expired leased utxos get spent at the first opportunity. We do this instead of 'burning' them, as it's more efficient as presumably we're now spending them with a purpose. --- common/utxo.h | 4 ++++ wallet/db.c | 1 + wallet/test/run-wallet.c | 22 +++++++++++++++++----- wallet/wallet.c | 37 ++++++++++++++++++++++++++++++------- wallet/wallet.h | 9 +++++++++ 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/common/utxo.h b/common/utxo.h index c847d5fcb365..5c3e3820c8a7 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -47,6 +47,10 @@ struct utxo { * blocks the utxo is reserved for */ const u32 *reserved_for; + /* Ordering for spendable utxos, allows us to rank sort utxos + * by priority for spending */ + u8 spend_priority; + /* The scriptPubkey if it is known */ u8 *scriptPubkey; diff --git a/wallet/db.c b/wallet/db.c index 898f9c2194de..e7fbf8a60936 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -601,6 +601,7 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channels ADD our_funding_satoshi INTEGER DEFAULT 0;"), migrate_our_funding}, {SQL("ALTER TABLE outputs ADD reserved_at INTEGER DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE outputs ADD reserved_for INTEGER DEFAULT NULL;"), NULL}, + {SQL("ALTER TABLE outputs ADD spend_priority INTEGER DEFAULT 0;"), NULL}, }; /* Leak tracking. */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index f5cac02c6ec3..4cd22b0a5eb0 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -863,7 +863,7 @@ static struct wallet *create_test_wallet(struct lightningd *ld, const tal_t *ctx static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) { struct wallet *w = create_test_wallet(ld, ctx); - struct utxo u; + struct utxo u, u1; struct pubkey pk; struct node_id id; struct amount_sat fee_estimate, change_satoshis; @@ -966,6 +966,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) /* Check that reserved_at height and reserved_for is set */ CHECK(*utxos[0]->reserved_at == height); CHECK(*utxos[0]->reserved_for == reserve_for_blocks); + CHECK(utxos[0]->spend_priority == spend_first); tal_free(utxos); /* Expire the lease! */ @@ -983,17 +984,28 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) utxos = (const struct utxo **)wallet_get_utxos(w, w, output_state_reserved); CHECK(tal_count(utxos) == 0); - /* check that we can mark as spent */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + /* Add another utxo of the same value, set the spend priority high */ + memset(&u1, 0, sizeof(u1)); + u1.amount = AMOUNT_SAT(1); + memset(&u1.txid, 2, sizeof(u1.txid)); + u1.spend_priority = 2; + CHECK_MSG(wallet_add_utxo(w, &u1, p2sh_wpkh), + "wallet_add_utxo high priority utxo"); + + /* check that we get back two high priority utxos */ + utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(2), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); - CHECK_MSG(utxos && tal_count(utxos) == 1, "utxo count is incorrect"); + CHECK_MSG(utxos && tal_count(utxos) == 2, "utxo count is incorrect"); + CHECK_MSG(utxos[0]->spend_priority == 2, "expected priority 2"); + CHECK_MSG(utxos[1]->spend_priority == 1, "expected priority 1"); + wallet_confirm_utxos(w, utxos); tal_free(utxos); /* Attempt to save an UTXO with close_info set, no commitment_point */ - memset(&u.txid, 2, sizeof(u.txid)); + memset(&u.txid, 3, sizeof(u.txid)); u.amount = AMOUNT_SAT(5); u.close_info = tal(w, struct unilateral_close_info); u.close_info->channel_id = 42; diff --git a/wallet/wallet.c b/wallet/wallet.c index a95fb5dca4e3..136f8223ec25 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -104,7 +104,8 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, ", confirmation_height" ", spend_height" ", scriptpubkey" - ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + ", spend_priority" + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_txid(stmt, 0, &utxo->txid); db_bind_int(stmt, 1, utxo->outnum); db_bind_amount_sat(stmt, 2, &utxo->amount); @@ -142,6 +143,8 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, else db_bind_null(stmt, 11); + db_bind_int(stmt, 12, utxo->spend_priority); + db_exec_prepared_v2(take(stmt)); return true; } @@ -208,6 +211,8 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->reserved_for = reserved_for; } + utxo->spend_priority = db_column_int(stmt, 14); + return utxo; } @@ -311,7 +316,9 @@ bool wallet_output_reservation_update(struct wallet *w, stmt = db_prepare_v2(w->db, SQL("UPDATE outputs" - " SET reserved_at = ?, reserved_for = ?" + " SET reserved_at = ?" + ", reserved_for = ?" + ", spend_priority = ?" " WHERE prev_out_tx = ? AND prev_out_index = ?")); if (current_height == 0 || reserve_for == 0) { db_bind_null(stmt, 0); @@ -320,8 +327,15 @@ bool wallet_output_reservation_update(struct wallet *w, db_bind_int(stmt, 0, current_height); db_bind_int(stmt, 1, reserve_for); } - db_bind_sha256d(stmt, 2, &utxo->txid.shad); - db_bind_int(stmt, 3, utxo->outnum); + + /* Any output with a reservation expiration gets first + * priority for spending. Note that we could also increment + * the spend priority by one every time it passes through + * here, such that expired utxos would ratchet to the front + * for every time they get shared */ + db_bind_int(stmt, 2, spend_first); + db_bind_sha256d(stmt, 3, &utxo->txid.shad); + db_bind_int(stmt, 4, utxo->outnum); db_exec_prepared_v2(stmt); changes = db_count_changes(stmt); tal_free(stmt); @@ -350,6 +364,7 @@ static struct utxo *wallet_get_utxo(const tal_t *ctx, struct wallet *w, ", scriptpubkey" ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE prev_out_tx = ? AND prev_out_index = ?")); @@ -391,7 +406,9 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", scriptpubkey" ", reserved_at" ", reserved_for" - " FROM outputs")); + ", spend_priority" + " FROM outputs " + " ORDER BY spend_priority DESC")); } else { stmt = db_prepare_v2(w->db, SQL("SELECT" " prev_out_tx" @@ -408,8 +425,10 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", scriptpubkey" ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" - " WHERE status= ?")); + " WHERE status= ?" + " ORDER BY spend_priority DESC")); db_bind_int(stmt, 0, output_status_in_db(state)); } db_query_prepared(stmt); @@ -446,6 +465,7 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, ", scriptpubkey" ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE channel_id IS NOT NULL AND " "confirmation_height IS NULL")); @@ -483,6 +503,7 @@ static struct utxo **wallet_get_expired_reserved_utxos(const tal_t *ctx, ", scriptpubkey" ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE status = ?" " AND reserved_at IS NOT NULL" @@ -511,7 +532,6 @@ static struct utxo **wallet_get_expired_reserved_utxos(const tal_t *ctx, /* Reserved utxos are ok, if they're expired. In fact, we really * want to use those first, so we put them at the head of the * spendable list */ -// FIXME: we lose this info after an expired utxo is re-reserved static struct utxo **wallet_get_spendable_utxos(const tal_t *ctx, struct wallet *w) { @@ -807,6 +827,7 @@ static struct utxo **sorted_confirmed_utxos(const tal_t *ctx, struct wallet *w, ", scriptpubkey " ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE confirmation_height IS NOT NULL" " ORDER BY value DESC")); @@ -826,6 +847,7 @@ static struct utxo **sorted_confirmed_utxos(const tal_t *ctx, struct wallet *w, ", scriptpubkey " ", reserved_at" ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE status = ?" " AND confirmation_height IS NOT NULL" @@ -1971,6 +1993,7 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, bitcoin_txid(tx, &utxo->txid); utxo->outnum = output; utxo->close_info = NULL; + utxo->spend_priority = spend_normal; utxo->blockheight = blockheight ? blockheight : NULL; utxo->spendheight = NULL; diff --git a/wallet/wallet.h b/wallet/wallet.h index 13f80109c7da..966cbd521866 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -84,6 +84,13 @@ enum output_status { output_state_any = 255 }; +/* Default spending priorities. Used to sort outputs + * for coin selection */ +enum output_spend_priority { + spend_normal = 0, + spend_first = 1 +}; + static inline enum output_status output_status_in_db(enum output_status s) { switch (s) { @@ -385,6 +392,8 @@ bool wallet_output_reservation_update(struct wallet *w, * * Returns a `tal_arr` of `utxo` structs. Double indirection in order * to be able to steal individual elements onto something else. + * + * Are ordered by spend_priority, from highest to lowest. */ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum output_status state); From 98bdb6daca977479d0fe5070a10dc299c19c7ea6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 6 Dec 2019 13:25:32 -0600 Subject: [PATCH 057/131] wallet: include reserved outputs in listfunds Since we're now going to have 'expiring' outputs, it might be nice to be able to introspect them with list funds. This adds them to the `listfunds` command Changelog-Added: JSON API: `listfunds` now includes "reserved_outputs" a list of outputs currently in the process of being spent Changelog-Added: JSON API: `listfunds` now includes the relative 'spend priority' of an output; defaults to 0 --- doc/lightning-listfunds.7 | 27 ++++++++- doc/lightning-listfunds.7.md | 14 ++++- tests/test_wallet.py | 7 ++- wallet/walletrpc.c | 108 +++++++++++++++++++++++------------ 4 files changed, 112 insertions(+), 44 deletions(-) diff --git a/doc/lightning-listfunds.7 b/doc/lightning-listfunds.7 index a9fb6a0c1acc..8817c6b32efb 100644 --- a/doc/lightning-listfunds.7 +++ b/doc/lightning-listfunds.7 @@ -13,13 +13,15 @@ currently open channels\. .SH RETURN VALUE -On success two arrays will be returned: \fIoutputs\fR with funds currently -locked onchain in UTXOs and \fIchannels\fR with funds readily spendable in +On success three arrays will be returned: \fIoutputs\fR with funds currently +locked onchain in UTXOs, \fIreserved_outputs\fR of outputs currently in the wallet +but internally reserved for a transaction, and \fIchannels\fR with funds readily spendable in channels\. -Each entry in \fIoutputs\fR will include: +Each entry in \fIoutputs\fR and \fIreserved_outputs\fR will include: +.RS .IP \[bu] \fItxid\fR .IP \[bu] @@ -33,10 +35,28 @@ appended) \fIaddress\fR .IP \[bu] \fIstatus\fR (whether \fIunconfirmed\fR, \fIconfirmed\fR, or \fIspent\fR) +.IP \[bu] +\fIblockheight\fR (block the transaction is in, if confirmed) +.IP \[bu] +\fIspend_priority\fR (used internally when funding new transactions) + +.RE + +Each \fIreserved_outputs\fR entry might include: + +.RS +.IP \[bu] +\fIreserved_at_height\fR (blockheight at which expiring reservation was placed on output) +.IP \[bu] +\fIreserved_until\fR (number of blocks for which reservation is valid) +.IP \[bu] +\fIreservation_expired\fR (true if reservation has expired, is eligible to spend) +.RE Each entry in \fIchannels\fR will include: +.RS .IP \[bu] \fIpeer_id\fR - the peer with which the channel is opened\. .IP \[bu] @@ -66,6 +86,7 @@ transaction\. \fIstate\fR - the channel state, in particular \fICHANNELD_NORMAL\fR means the channel can be used normally\. +.RE .SH AUTHOR Felix \fI is mainly responsible\. diff --git a/doc/lightning-listfunds.7.md b/doc/lightning-listfunds.7.md index a3267f2d97f5..0b20e1578268 100644 --- a/doc/lightning-listfunds.7.md +++ b/doc/lightning-listfunds.7.md @@ -16,11 +16,12 @@ currently open channels. RETURN VALUE ------------ -On success two arrays will be returned: *outputs* with funds currently -locked onchain in UTXOs and *channels* with funds readily spendable in +On success three arrays will be returned: *outputs* with funds currently +locked onchain in UTXOs, *reserved_outputs* of outputs currently in the wallet +but internally reserved for a transaction, and *channels* with funds readily spendable in channels. -Each entry in *outputs* will include: +Each entry in *outputs* and *reserved_outputs* will include: - *txid* - *output* (the index of the output in the transaction) - *value* (the output value in satoshis) @@ -28,6 +29,13 @@ Each entry in *outputs* will include: appended) - *address* - *status* (whether *unconfirmed*, *confirmed*, or *spent*) +- *blockheight* (block the transaction is in, if confirmed) +- *spend_priority* (used internally when funding new transactions) + +Each *reserved_outputs* entry might include: +- *reserved_at_height* (blockheight at which expiring reservation was placed on output) +- *reserved_until* (number of blocks for which reservation is valid) +- *reservation_expired* (true if reservation has expired, is eligible to spend) Each entry in *channels* will include: - *peer\_id* - the peer with which the channel is opened. diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 9caa353329a0..d8c0027ccb1a 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -301,7 +301,12 @@ def test_txprepare(node_factory, bitcoind, chainparams): bitcoind.generate_block(1) wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 10) - prep = l1.rpc.txprepare(outputs=[{addr: Millisatoshi(amount * 3 * 1000)}]) + prep = l1.rpc.txprepare([{addr: Millisatoshi(amount * 3 * 1000)}]) + + # Check that reserved outputs get moved to 'reserved_outputs' in list funds + funds = l1.rpc.listfunds() + assert len(funds['reserved_outputs']) + len(funds['outputs']) == 10 + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) assert decode['txid'] == prep['txid'] # 4 inputs, 2 outputs (3 if we have a fee output). diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 62b137b8db23..d9888c2e1364 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -834,6 +834,63 @@ static const struct json_command listaddrs_command = { }; AUTODATA(json_command, &listaddrs_command); +static struct command_result *add_output(struct command *cmd, + struct json_stream *stream, + struct utxo *utxo) +{ + u32 reserved_until; + char* out; + struct pubkey funding_pubkey; + + json_object_start(stream, NULL); + json_add_txid(stream, "txid", &utxo->txid); + json_add_num(stream, "output", utxo->outnum); + json_add_amount_sat_compat(stream, utxo->amount, + "value", "amount_msat"); + + /* @close_info is for outputs that are not yet claimable */ + if (utxo->close_info == NULL) { + bip32_pubkey(cmd->ld->wallet->bip32_base, &funding_pubkey, + utxo->keyindex); + out = encode_pubkey_to_addr(cmd, cmd->ld, + &funding_pubkey, + utxo->is_p2sh, + NULL); + if (!out) { + return command_fail(cmd, LIGHTNINGD, + "p2wpkh address encoding failure."); + } + json_add_string(stream, "address", out); + } else if (utxo->scriptPubkey != NULL) { + out = encode_scriptpubkey_to_addr( + cmd, chainparams, + utxo->scriptPubkey); + if (out) + json_add_string(stream, "address", out); + } + + if (utxo->spendheight) + json_add_string(stream, "status", "spent"); + else if (utxo->blockheight) { + json_add_string(stream, "status", "confirmed"); + json_add_num(stream, "blockheight", *utxo->blockheight); + } else + json_add_string(stream, "status", "unconfirmed"); + + json_add_num(stream, "spend_priority", utxo->spend_priority); + + if (utxo->reserved_at) { + reserved_until = *utxo->reserved_at + *utxo->reserved_for; + json_add_num(stream, "reserved_at_height", *utxo->reserved_at); + json_add_num(stream, "reserved_until", reserved_until); + json_add_bool(stream, "reservation_expired", + cmd->ld->topology->tip->height >= reserved_until); + } + json_object_end(stream); + + return NULL; +} + static struct command_result *json_listfunds(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -842,8 +899,7 @@ static struct command_result *json_listfunds(struct command *cmd, struct json_stream *response; struct peer *p; struct utxo **utxos; - char* out; - struct pubkey funding_pubkey; + struct command_result *res; if (!param(cmd, buffer, params, NULL)) return command_param_failed(); @@ -852,42 +908,20 @@ static struct command_result *json_listfunds(struct command *cmd, response = json_stream_success(cmd); json_array_start(response, "outputs"); for (size_t i = 0; i < tal_count(utxos); i++) { - json_object_start(response, NULL); - json_add_txid(response, "txid", &utxos[i]->txid); - json_add_num(response, "output", utxos[i]->outnum); - json_add_amount_sat_compat(response, utxos[i]->amount, - "value", "amount_msat"); - - /* @close_info is for outputs that are not yet claimable */ - if (utxos[i]->close_info == NULL) { - bip32_pubkey(cmd->ld->wallet->bip32_base, &funding_pubkey, - utxos[i]->keyindex); - out = encode_pubkey_to_addr(cmd, cmd->ld, - &funding_pubkey, - utxos[i]->is_p2sh, - NULL); - if (!out) { - return command_fail(cmd, LIGHTNINGD, - "p2wpkh address encoding failure."); - } - json_add_string(response, "address", out); - } else if (utxos[i]->scriptPubkey != NULL) { - out = encode_scriptpubkey_to_addr( - cmd, chainparams, - utxos[i]->scriptPubkey); - if (out) - json_add_string(response, "address", out); - } - - if (utxos[i]->spendheight) - json_add_string(response, "status", "spent"); - else if (utxos[i]->blockheight) { - json_add_string(response, "status", "confirmed"); - json_add_num(response, "blockheight", *utxos[i]->blockheight); - } else - json_add_string(response, "status", "unconfirmed"); + res = add_output(cmd, response, utxos[i]); + if (res) + return res; + } + json_array_end(response); + utxos = tal_free(utxos); - json_object_end(response); + /* Also print reserved utxo information */ + utxos = wallet_get_utxos(cmd, cmd->ld->wallet, output_state_reserved); + json_array_start(response, "reserved_outputs"); + for (size_t i = 0; i < tal_count(utxos); i++) { + res = add_output(cmd, response, utxos[i]); + if (res) + return res; } json_array_end(response); From 886656ac5441786e5b3ab79539aec0c59b64fc49 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 6 Dec 2019 17:35:34 -0600 Subject: [PATCH 058/131] df: mark reserved accepter utxos with an expiration we reserve utxos for the accepter's side of the funding tx for a set number of blocks. after this, the utxo is eligible to be reused in a different transaction (which would nullify this channel open; to be dealt with however) --- lightningd/opening_control.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 102f75740655..8efda16c7b2d 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -41,6 +41,8 @@ #include #include +#define UTXO_RESERVATION_BLOCKS 18 + /* Channel we're still opening. */ struct uncommitted_channel { /* peer->uncommitted_channel == this */ @@ -909,7 +911,13 @@ static void opening_fundee_finished(struct subd *openingd, &channel->funding_txid)); if (utxos) { - // TODO: mark utxos as shared + u32 tipheight = ld->topology->tip->height; + for (size_t i = 0; i < tal_count(utxos); i++) + wallet_output_reservation_update(ld->wallet, utxos[i], + tipheight, + UTXO_RESERVATION_BLOCKS); + + // FIXME: associate input spend with channel? tal_free(utxos); } From a7e8bbc3855230f6d7c67fc1c82f221da8a8a307 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 11 Dec 2019 18:25:48 -0600 Subject: [PATCH 059/131] wallet watch: track and clean up many inputs:channel opens This commit adds a new database table for tracking our usage of outputs across multiple, concurrent transactions. With the introduction of 'expiring utxo reservations', we now need a way to associate the double spend of a utxo with the channels and txids associated with it. We do this via a new table which associates the utxo with the txid that it's included in and the channel id (optional). In the case where a utxo is used in multiple, valid transactions and one of those transactions is included in a block, we then clean up all other associated channel opens. This will also, in the future, provide us with the basic infra we need to track RBFs across multiple transaction attempts. Note that in order for this to work correctly, we'll need to track every withdrawal as well, which we're not currently doing. --- lightningd/chaintopology.c | 5 ++ lightningd/opening_control.c | 7 ++- lightningd/watch.c | 23 +++++++ lightningd/watch.h | 8 +++ wallet/db.c | 8 +++ wallet/test/run-wallet.c | 8 +++ wallet/wallet.c | 114 +++++++++++++++++++++++++++++++++++ wallet/wallet.h | 15 +++++ 8 files changed, 186 insertions(+), 2 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index adf2b4cba8e5..7e52c9933665 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -97,6 +97,11 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b) /* We did spends first, in case that tells us to watch tx. */ if (watching_txid(topo, &txid) || we_broadcast(topo, &txid)) { + /* If this is a tx we're watching, go ahead and + * see if this cleans up / invalidates any other + * channel opens or RBF'd transactions */ + wallet_find_check_input_tx(topo->ld->wallet, + topo, &txid); wallet_transaction_add(topo->ld->wallet, tx, b->height, i); } diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 8efda16c7b2d..901f340c0f0c 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -614,6 +614,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, fc->our_upfront_shutdown_script, remote_upfront_shutdown_script); + /* Watch for funding confirms */ channel_watch_funding(ld, channel); @@ -912,12 +913,14 @@ static void opening_fundee_finished(struct subd *openingd, if (utxos) { u32 tipheight = ld->topology->tip->height; - for (size_t i = 0; i < tal_count(utxos); i++) + for (size_t i = 0; i < tal_count(utxos); i++) { wallet_output_reservation_update(ld->wallet, utxos[i], tipheight, UTXO_RESERVATION_BLOCKS); + wallet_add_input_tx_tracking(ld->wallet, utxos[i], + channel, &funding_txid); + } - // FIXME: associate input spend with channel? tal_free(utxos); } diff --git a/lightningd/watch.c b/lightningd/watch.c index f5a041295906..4b0a6b2b963e 100644 --- a/lightningd/watch.c +++ b/lightningd/watch.c @@ -149,6 +149,29 @@ struct txwatch *watch_txid(const tal_t *ctx, return w; } +struct channel *del_txwatch(struct chain_topology *topo, + const struct bitcoin_txid *txid, + u64 chan_dbid) +{ + struct txwatch_hash_iter i; + struct txwatch *w; + struct channel *c; + + /* We could have more than one channel watching same txid, + * but we trust that we'll clean that up in another pass */ + for (w = txwatch_hash_getfirst(&topo->txwatches, txid, &i); + w; + w = txwatch_hash_getnext(&topo->txwatches, txid, &i)) { + if (w->channel->dbid == chan_dbid) { + c = w->channel; + tal_free(w); + return c; + } + } + + return NULL; +} + struct txwatch *find_txwatch(struct chain_topology *topo, const struct bitcoin_txid *txid, const struct channel *channel) diff --git a/lightningd/watch.h b/lightningd/watch.h index b5c7f2544231..962aa6ab28a4 100644 --- a/lightningd/watch.h +++ b/lightningd/watch.h @@ -91,4 +91,12 @@ void txwatch_inform(const struct chain_topology *topo, const struct bitcoin_tx *tx_may_steal); void watch_topology_changed(struct chain_topology *topo); + +/* del_txwatch - deletes a transaction watch for the given + * txid and channel dbid. + * + * @returns: the associated channel, if found */ +struct channel *del_txwatch(struct chain_topology *topo, + const struct bitcoin_txid *txid, + u64 channel_dbid); #endif /* LIGHTNING_LIGHTNINGD_WATCH_H */ diff --git a/wallet/db.c b/wallet/db.c index e7fbf8a60936..97c762316fc1 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -602,6 +602,14 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE outputs ADD reserved_at INTEGER DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE outputs ADD reserved_for INTEGER DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE outputs ADD spend_priority INTEGER DEFAULT 0;"), NULL}, + /* For dual-funding RBFs and input reuse, we track input to tx/channel association */ + {SQL("CREATE TABLE output_tracking (" + " prev_out_tx BLOB" + ", prev_out_index INTEGER" + ", txid BLOB" + ", channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE" + ", PRIMARY KEY (prev_out_tx, prev_out_index, txid, channel_id));"), + NULL}, }; /* Leak tracking. */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 4cd22b0a5eb0..f02370e01cb4 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -101,6 +101,11 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } +/* Generated stub for del_txwatch */ +struct channel *del_txwatch(struct chain_topology *topo UNNEEDED, + const struct bitcoin_txid *txid UNNEEDED, + u64 channel_dbid UNNEEDED) +{ fprintf(stderr, "del_txwatch called!\n"); abort(); } /* Generated stub for encode_scriptpubkey_to_addr */ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED, const struct chainparams *chainparams UNNEEDED, @@ -109,6 +114,9 @@ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED, /* Generated stub for fatal */ void fatal(const char *fmt UNNEEDED, ...) { fprintf(stderr, "fatal called!\n"); abort(); } +/* Generated stub for forget_channel */ +void forget_channel(struct channel *channel UNNEEDED, const char *err_msg UNNEEDED) +{ fprintf(stderr, "forget_channel called!\n"); abort(); } /* Generated stub for fromwire_channel_dev_memleak_reply */ bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); } diff --git a/wallet/wallet.c b/wallet/wallet.c index 136f8223ec25..d919e385cd17 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -9,12 +9,15 @@ #include #include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -149,6 +152,117 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, return true; } +bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, + struct channel *channel, struct bitcoin_txid *txid) +{ + struct db_stmt *stmt; + size_t changes; + + stmt = db_prepare_v2(w->db, + SQL("INSERT INTO output_tracking (" + " prev_out_tx" + ", prev_out_index" + ", txid" + ", channel_id" + ") VALUES (?, ?, ?, ?);")); + + db_bind_txid(stmt, 0, &utxo->txid); + db_bind_int(stmt, 1, utxo->outnum); + db_bind_txid(stmt, 2, txid); + db_bind_int(stmt, 3, channel->dbid); + + db_exec_prepared_v2(stmt); + changes = db_count_changes(stmt); + tal_free(stmt); + return changes > 0; +} + +bool wallet_find_check_input_tx(struct wallet *w, struct chain_topology *topo, + struct bitcoin_txid *txid) +{ + struct db_stmt *utxo_stmt, *stmt, *del_stmt; + struct bitcoin_txid utxo_txid, f_txid; + struct channel *chan; + u32 outpoint; + u64 blessed_chan_dbid, chan_dbid; + char *close_error = "input UTXO spent elsewhere"; + + utxo_stmt = db_prepare_v2(w->db, + SQL("SELECT prev_out_tx, prev_out_index" + ", channel_id FROM output_tracking" + " WHERE txid = ?;")); + db_bind_txid(utxo_stmt, 0, txid); + db_query_prepared(utxo_stmt); + + if (utxo_stmt->error) + fatal("%s", utxo_stmt->error); + + + /* Iterate through all of the inputs we cared about for this txid. + * Look up any other tracking records for that input */ + while (db_step(utxo_stmt)) { + /* Pull out the current utxo info */ + db_column_txid(utxo_stmt, 0, &utxo_txid); + outpoint = db_column_int(utxo_stmt, 1); + blessed_chan_dbid = db_column_int(utxo_stmt, 2); + + stmt = db_prepare_v2(w->db, + SQL("SELECT txid, channel_id FROM output_tracking" + " WHERE prev_out_tx = ? AND prev_out_index = ?" + " AND txid != ?;")); + db_bind_txid(stmt, 0, &utxo_txid); + db_bind_int(stmt, 1, outpoint); + db_bind_txid(stmt, 2, txid); + + db_query_prepared(stmt); + if (stmt->error) + fatal("%s", stmt->error); + + while (db_step(stmt)) { + /* Pull out subquery's info */ + db_column_txid(stmt, 0, &f_txid); + chan_dbid = db_column_int(stmt, 1); + + /* Remove the tx_filter for this txid (this isn't ever coming) + * and return the channel object */ + chan = del_txwatch(topo, &f_txid, chan_dbid); + + /* This is a channel cancel; otherwise it's an RBF'd tx. + * Defunct RBFs don't need cleanup as the correction + * to the 'good' txid is taken care of elsewhere + * + * `forget_channel` immediately marks the chan with an error, + * so we check that to see if we're already canceling it (since + * in some paths we require notifying the peer first, which + * is not synchronous. Ultimately, this frees the channel, + * so subsequent lookups of the channel in txwatch should return NULL + * */ + // FIXME: this can/might free channel.. what to do about + // other, possibly existing txwatches? + if (chan && chan_dbid != blessed_chan_dbid && !chan->error) + forget_channel(chan, close_error); + + /* We want to delete all tracking for the + * other outputs associated with this txid; it isn't + * ever coming through. */ + del_stmt = db_prepare_v2(w->db, SQL("DELETE FROM output_tracking" + " WHERE txid = ?;")); + db_bind_txid(del_stmt, 0, &f_txid); + db_exec_prepared_v2(take(del_stmt)); + } + tal_free(stmt); + } + + /* Finally, clean up the existing txid's records */ + del_stmt = db_prepare_v2(w->db, SQL("DELETE FROM output_tracking" + " WHERE txid = ?;")); + db_bind_txid(del_stmt, 0, txid); + db_exec_prepared_v2(take(del_stmt)); + + tal_free(utxo_stmt); + return true; +} + /** * wallet_stmt2output - Extract data from stmt and fill an UTXO */ diff --git a/wallet/wallet.h b/wallet/wallet.h index 966cbd521866..123b44ff536c 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -349,6 +349,21 @@ struct wallet *wallet_new(struct lightningd *ld, struct timers *timers); bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, enum wallet_output_type type); +/* wallet_add_input_tx_tracking - Associate a utxo with a transaction & channel + * + * Associate a UTXO with a channel and funding transaction id. This will allow + * us to 1) clean up channels that aren't opened because of a spend elsewhere + * and 2) track RBFs for channel opens. + */ +bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, + struct channel *chnanel, struct bitcoin_txid *txid); + +/* wallet_find_check_input_tx - Find and clean up any associated funding tx's + * that are no longer valid/spendable because of the inclusion of this + * txid in a block. Cleans up any associated channels and tx-watches as well. + */ +bool wallet_find_check_input_tx(struct wallet *w, struct chain_topology *topo, + struct bitcoin_txid *txid); /** * wallet_confirm_tx - Confirm a tx which contains a UTXO. */ From a0ef6ff1702c8ffcdaa038e05bcd57095cd91931 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Dec 2019 18:09:58 -0600 Subject: [PATCH 060/131] wallet test: add test for utxo tracking cleanup check that how we're cleaning up utxo tracking works as expected. --- wallet/test/run-wallet.c | 181 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 8 deletions(-) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index f02370e01cb4..c91d5d6fe04f 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -101,11 +101,6 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN /* Generated stub for ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } -/* Generated stub for del_txwatch */ -struct channel *del_txwatch(struct chain_topology *topo UNNEEDED, - const struct bitcoin_txid *txid UNNEEDED, - u64 channel_dbid UNNEEDED) -{ fprintf(stderr, "del_txwatch called!\n"); abort(); } /* Generated stub for encode_scriptpubkey_to_addr */ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED, const struct chainparams *chainparams UNNEEDED, @@ -114,9 +109,6 @@ char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED, /* Generated stub for fatal */ void fatal(const char *fmt UNNEEDED, ...) { fprintf(stderr, "fatal called!\n"); abort(); } -/* Generated stub for forget_channel */ -void forget_channel(struct channel *channel UNNEEDED, const char *err_msg UNNEEDED) -{ fprintf(stderr, "forget_channel called!\n"); abort(); } /* Generated stub for fromwire_channel_dev_memleak_reply */ bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); } @@ -764,6 +756,32 @@ u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED) void plugin_hook_db_sync(struct db *db UNNEEDED) { } + +/* Let's keep track txids of txwatches that are deleted */ +struct bitcoin_txid **deleted_txid_watches; +u64 *forgotten_channel_ids; + +/* Fake stubs for watch tracking */ +struct channel *del_txwatch(struct chain_topology *topo UNNEEDED, + const struct bitcoin_txid *txid UNNEEDED, + u64 chan_dbid UNNEEDED) +{ + struct channel *channel = tal(tmpctx, struct channel); + + /* Add deleted txid watch to the set, for verification later */ + tal_arr_expand(&deleted_txid_watches, + tal_dup(NULL, struct bitcoin_txid, txid)); + + /* Pass back a 'fake' channel, with correct dbid */ + channel->dbid = chan_dbid; + /* We also need a null chan->error (same as + * normal channel creation) */ + channel->error = NULL; + return channel; +} +void forget_channel(struct channel *channel UNNEEDED, const char *why UNNEEDED) { + tal_arr_expand(&forgotten_channel_ids, channel->dbid); +} bool fromwire_hsm_get_channel_basepoints_reply(const void *p UNNEEDED, struct basepoints *basepoints, struct pubkey *funding_pubkey) @@ -1039,6 +1057,152 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) return true; } +static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) +{ + struct wallet *w = create_test_wallet(ld, ctx); + struct utxo u1, u2, u3, u4; + struct bitcoin_txid txidA, txidB, txidC, txidD, txidE, txid, utxid; + struct pubkey pk; + struct node_id id; + u64 channel_dbid, peer_dbid; + u32 outpoint; + struct channel *channel; + struct db_stmt *stmt; + size_t count; + + /* Initialize the set of deleted tx watches */ + deleted_txid_watches = tal_arr(ctx, struct bitcoin_txid *, 0); + /* Initialize set of forgotten channels */ + forgotten_channel_ids = tal_arr(ctx, u64, 0); + + + CHECK(w); + channel = tal(ctx, struct channel); + + /* Set up utxos */ + memset(&u1, 1, sizeof(u1)); + u1.amount = AMOUNT_SAT(1); + u1.outnum = 1; + memset(&u2, 2, sizeof(u2)); + u2.amount = AMOUNT_SAT(2); + u2.outnum = 2; + memset(&u3, 3, sizeof(u3)); + u3.amount = AMOUNT_SAT(3); + u3.outnum = 3; + memset(&u4, 4, sizeof(u4)); + u4.amount = AMOUNT_SAT(4); + u4.outnum = 4; + + /* Set up bitcoin txids */ + memset(&txidA, 0, sizeof(txidA)); + memset(&txidB, 1, sizeof(txidB)); + memset(&txidC, 2, sizeof(txidC)); + memset(&txidD, 3, sizeof(txidD)); + memset(&txidE, 4, sizeof(txidE)); + + db_begin_transaction(w->db); + + /* Insert channel + peers into the database */ + pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); + node_id_from_pubkey(&id, &pk); + + stmt = db_prepare_v2(w->db, SQL("INSERT INTO peers (node_id) VALUES (?);")); + db_bind_node_id(stmt, 0, &id); + db_exec_prepared_v2(stmt); + peer_dbid = db_last_insert_id_v2(take(stmt)); + + for (size_t i = 0; i < 4; i++) { + stmt = db_prepare_v2(w->db, SQL("INSERT INTO channels " + "(peer_id, id) VALUES (?, ?);")); + db_bind_u64(stmt, 0, peer_dbid); + db_bind_int(stmt, 1, i); + db_exec_prepared_v2(take(stmt)); + } + + /* utxo set (1,2) for channel 0 open AB, txid_A */ + channel->dbid = 0; + CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidA)); + CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidA)); + + /* utxo set (1,2) for channel 1 open AC, &txid_A (same &txid, diff channel) */ + channel->dbid = 1; + CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidA)); + CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidA)); + + /* utxo set (1,3) for channel 2 open AD, &txid_B (diff &txid, diff channel) */ + channel->dbid = 2; + CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidB)); + CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidB)); + + /* utxo set (1,4) for channel 0 open AB, &txid_C (diff &txid, same channel) */ + channel->dbid = 0; + CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidC)); + CHECK(wallet_add_input_tx_tracking(w, &u4, channel, &txidC)); + + /* utxo set (2,3) for channel 2 open AD, &txid_D (diff &txid, diff channel + * , diff input overlap) */ + channel->dbid = 2; + CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidD)); + CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidD)); + + /* utxo set (3,4) for channel 3 open AE, &txid_E (no correlation, untouched) */ + channel->dbid = 3; + CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidE)); + CHECK(wallet_add_input_tx_tracking(w, &u4, channel, &txidE)); + + CHECK_MSG(wallet_find_check_input_tx(w, ld->topology, &txidA), + "Error clearing out related inputs"); + CHECK_MSG(!wallet_err, wallet_err); + + /* check that txid_E, (3,4) are the only things still in table */ + stmt = db_prepare_v2(w->db, SQL("SELECT prev_out_tx, prev_out_index, txid, channel_id" + " FROM output_tracking")); + db_query_prepared(stmt); + + CHECK(!stmt->error); + count = 0; + while (db_step(stmt)) { + db_column_txid(stmt, 0, &utxid); + outpoint = db_column_int(stmt, 1); + db_column_txid(stmt, 2, &txid); + channel_dbid = db_column_int(stmt, 3); + + CHECK_MSG(bitcoin_txid_eq(&txid, &txidE), + tal_fmt(ctx, "expected txidE, got %s channel id %"PRIu64" utxo %s", + type_to_string(ctx, struct bitcoin_txid, &txid), + channel_dbid, + type_to_string(ctx, struct bitcoin_txid, &utxid))); + CHECK_MSG(channel_dbid == 3, + tal_fmt(ctx, "channel_dbid is %"PRIu64", expecting 3", channel_dbid)); + if (bitcoin_txid_eq(&utxid, &u3.txid)) { + CHECK(outpoint == 3); + } else if (bitcoin_txid_eq(&utxid, &u4.txid)) { + CHECK(outpoint == 4); + } else { + CHECK_MSG(false, "utxo incorrect"); + } + count++; + } + + /* Check that watches for txids are deleted. Checks order as well */ + CHECK_MSG(tal_count(deleted_txid_watches) == 3, "Expected three deleted txid watches"); + CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[0], &txidB), "looking for txidB"); + CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[1], &txidC), "looking for txidC"); + CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[2], &txidD), "looking for txidD"); + + /* Because of how the mocks for this work, we'll get channel id '2' back twice */ + CHECK_MSG(tal_count(forgotten_channel_ids) == 2, + tal_fmt(ctx, "expected 2 forgotten channel calls got %zu", + tal_count(forgotten_channel_ids))); + CHECK(forgotten_channel_ids[0] == 2); + CHECK(forgotten_channel_ids[1] == 2); + + tal_free(stmt); + + db_commit_transaction(w->db); + return count > 0; +} + static bool test_shachain_crud(struct lightningd *ld, const tal_t *ctx) { struct wallet_shachain a, b; @@ -1539,6 +1703,7 @@ int main(void) htlc_out_map_init(&ld->htlcs_out); ok &= test_wallet_outputs(ld, tmpctx); + ok &= test_input_tx_assoc(ld, tmpctx); ok &= test_shachain_crud(ld, tmpctx); ok &= test_channel_crud(ld, tmpctx); ok &= test_channel_config_crud(ld, tmpctx); From 21a0330f4c500c57cdcc78d37737a361c2056530 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Dec 2019 18:11:55 -0600 Subject: [PATCH 061/131] wallet tests: print error instead of non-entity make errors more helpful by printing the actual error --- wallet/test/run-wallet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index c91d5d6fe04f..9345d1f3d6a5 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -880,7 +880,7 @@ static struct wallet *create_test_wallet(struct lightningd *ld, const tal_t *ctx db_migrate(ld, w->db); w->db->data_version = 0; db_commit_transaction(w->db); - CHECK_MSG(!wallet_err, "DB migration failed"); + CHECK_MSG(!wallet_err, wallet_err); w->max_channel_dbid = 0; return w; From 1647ffb32c5d9190af6aba814e7b61bc041d8c3b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Dec 2019 18:28:57 -0600 Subject: [PATCH 062/131] df: use correct check for p2sh-wrapped pay to witness This was doing the wrong check on the redeemscript. Now, we actually do check for the redeemscript of a P2SH-wrapped input. --- bitcoin/script.c | 32 ++++++++++++++++++++++++++++++++ bitcoin/script.h | 6 ++++++ openingd/openingd.c | 4 ++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index 02df5b22e524..b912aa79a91c 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -369,6 +369,38 @@ u8 *p2wpkh_scriptcode(const tal_t *ctx, const struct pubkey *key) return script; } +bool is_p2sh_p2wpkh_redeemscript(const u8 *script) +{ + size_t script_len = tal_count(script); + + /* Prefaced by the length */ + if (script_len != BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN + 1) + return false; + if (script[0] != OP_PUSHBYTES(22)) + return false; + if (script[1] != OP_0) + return false; + if (script[2] != OP_PUSHBYTES(20)) + return false; + return true; +} + +bool is_p2sh_p2wsh_redeemscript(const u8 *script) +{ + size_t script_len = tal_count(script); + + /* Is prefaced by the length */ + if (script_len != BITCOIN_SCRIPTPUBKEY_P2WSH_LEN + 1) + return false; + if (script[0] != OP_PUSHBYTES(34)) + return false; + if (script[1] != OP_0) + return false; + if (script[2] != OP_PUSHBYTES(32)) + return false; + return true; +} + bool is_p2pkh(const u8 *script, struct bitcoin_address *addr) { size_t script_len = tal_count(script); diff --git a/bitcoin/script.h b/bitcoin/script.h index 69f46fcde5f3..325e41088bb1 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -123,6 +123,12 @@ u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey); +/* Is this a P2SH-P2WPKH redeemscript? */ +bool is_p2sh_p2wpkh_redeemscript(const u8 *script); + +/* Is this a P2SH-P2WSH redeemscript? */ +bool is_p2sh_p2wsh_redeemscript(const u8 *script); + /* Is this a pay to pubkey hash? (extract addr if not NULL) */ bool is_p2pkh(const u8 *script, struct bitcoin_address *addr); diff --git a/openingd/openingd.c b/openingd/openingd.c index dd8ea8dc607d..e4bb8152ca07 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -962,8 +962,8 @@ static bool check_remote_inputs(struct state *state, * - MUST ensure each `input_info` refers to a non-malleable (segwit) UTXO. */ /* P2SH wrapped inputs send the redeemscript, which we can check */ if (remote_inputs[i]->script) { - if (!is_p2wpkh(remote_inputs[i]->script, NULL) - && !is_p2wsh(remote_inputs[i]->script, NULL)) + if (!is_p2sh_p2wpkh_redeemscript(remote_inputs[i]->script) + && !is_p2sh_p2wsh_redeemscript(remote_inputs[i]->script)) return false; } else if (!is_p2wpkh(remote_inputs[i]->prevtx_scriptpubkey, NULL) && !is_p2wsh(remote_inputs[i]->prevtx_scriptpubkey, NULL)) From 900bd2086e8bba866f53f2e5eeee21b09f08a061 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 13 Dec 2019 18:33:10 -0600 Subject: [PATCH 063/131] channel control: don't forget a channel if we added funds These will get cleaned up eventually when the utxo that was included in it is spent elsewhere (or when the channel finally opens!) --- lightningd/channel_control.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index b567be3696a4..1659286b44d2 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -591,6 +591,13 @@ is_fundee_should_forget(struct lightningd *ld, if (channel->scid) return false; + /* Does not apply if we contributed funds. + * These will get cleaned up when the + * utxo we used to fund them gets spent elsewhere + */ + if (!amount_sat_eq(channel->our_funds, AMOUNT_SAT(0))) + return false; + /* Not even reached previous starting blocknum. * (e.g. if --rescan option is used) */ if (block_height < channel->first_blocknum) From 529ce2bd08ad72c2ca7826507e3f43a419344ebb Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 8 Oct 2019 11:08:54 -0500 Subject: [PATCH 064/131] opening: plumb through amounts for a transaction We're about to enforce some stricter checking in withdraw_tx, which will require inputs to know what their amounts are. Here, we plumb through the input amounts along with the funding_tx, since the serialization process for transactions discards the input amount information. --- lightningd/opening_control.c | 9 +++++---- openingd/opening_wire.csv | 1 + openingd/openingd.c | 6 ++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 901f340c0f0c..6e4a3a8c7b51 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -437,6 +437,7 @@ static bool add_remote_witnesses(struct unreleased_tx *utx, static bool update_unreleased_tx(struct unreleased_tx *utx, struct bitcoin_tx *tx, + struct amount_sat *input_amts, u32 *input_map, struct amount_sat opener_change) { @@ -474,9 +475,7 @@ static bool update_unreleased_tx(struct unreleased_tx *utx, bitcoin_tx_input_get_txid(tx, index, &in->txid); in->index = wi.index; in->sequence_number = wi.sequence; - - /* Amount is unknown here */ - in->amount = AMOUNT_SAT(0); + in->amount = input_amts[index]; /* Copy over input's scriptpubkey */ if (wi.script_len) { @@ -537,6 +536,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, struct funding_channel *fc = uc->fc; struct unreleased_tx *utx = fc->utx; u32 *input_map; + struct amount_sat *input_amts; /* This is a new channel_info.their_config so set its ID to 0 */ channel_info.their_config.id = 0; @@ -549,6 +549,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, &funding_txout, &opener_change, &remote_witnesses, + &input_amts, &input_map, &local_funding, &channel_info.their_config, @@ -583,7 +584,7 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, } /* Update the funding tx that we have for this */ - if (!update_unreleased_tx(utx, funding_tx, input_map, opener_change)) { + if (!update_unreleased_tx(utx, funding_tx, input_amts, input_map, opener_change)) { log_broken(uc->log, "Unable to update unreleased tx"); uncommitted_channel_disconnect(uc, LOG_BROKEN, "internal error in creating updated tx"); goto cleanup; diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 4b1116e9be01..25ee01d69fa5 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -161,6 +161,7 @@ msgdata,opening_dual_funding_signed,opener_change,amount_sat, msgdata,opening_dual_funding_signed,num_witnesses,u16, msgdata,opening_dual_funding_signed,remote_witnesses,witness_stack,num_witnesses msgdata,opening_dual_funding_signed,num_inputs,u32, +msgdata,opening_dual_funding_signed,input_amts,amount_sat,num_inputs msgdata,opening_dual_funding_signed,input_map,u32,num_inputs msgdata,opening_dual_funding_signed,local_funding,amount_sat, msgdata,opening_dual_funding_signed,their_config,channel_config, diff --git a/openingd/openingd.c b/openingd/openingd.c index e4bb8152ca07..0079a8ce2009 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1555,9 +1555,14 @@ static u8 *funder_finalize_channel_setup2(struct state *state, "Opening channel: commitment sigs are acceptable, moving to sign tx %s", type_to_string(state, struct bitcoin_tx, funding_tx)); + struct amount_sat *input_amts = tal_arr(state, struct amount_sat, input_count); u32 *i_map = tal_arr(state, u32, input_count); for (size_t i = 0; i < input_count; i++) { i_map[i] = ptr2int(map[i]); + if (funding_tx->input_amounts[i]) + input_amts[i] = *funding_tx->input_amounts[i]; + else + input_amts[i] = AMOUNT_SAT(0); } /* @@ -1603,6 +1608,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, opener_change, cast_const2(const struct witness_stack **, remote_witnesses), + input_amts, i_map, state->opener_funding, &state->remoteconf, From 7b8bcb5e76d38e2cd84f897907c4dd700bfc9556 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 8 Oct 2019 11:10:21 -0500 Subject: [PATCH 065/131] withdraw: sanity checks in hsm check that our withdrawal amounts are sane -- no empty outputs, input and output amounts are in sync, we're below a max fee amount --- hsmd/hsmd.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 920339b1525e..f3ebd662588e 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1805,7 +1805,9 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, struct bitcoin_tx_output **outputs; u32 nlocktime; - size_t input_count, i, j; + size_t input_count, i, j, offset; + struct amount_sat input_sat, output_sat; + int input_index; if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &inputs, &outputs, @@ -1817,20 +1819,58 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, for (i = 0; i < input_count; i++) map[i] = int2ptr(i); + /* Do some 'light' transaction verification */ + output_sat = AMOUNT_SAT(0); + for (i = 0; i < tal_count(outputs); i++) { + if (amount_sat_eq(outputs[i]->amount, AMOUNT_SAT(0))) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Transaction has zero value output"); + if (!amount_sat_add(&output_sat, output_sat, outputs[i]->amount)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Overflow adding output values"); + } + + input_sat = AMOUNT_SAT(0); + for (i = 0; i < tal_count(inputs); i++) { + if (!amount_sat_add(&input_sat, input_sat, inputs[i]->amount)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Overflow adding input values"); + } + + for (i = 0; i < tal_count(utxos); i++) { + if (!amount_sat_add(&input_sat, input_sat, utxos[i]->amount)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Overflow adding utxo values"); + } + + if (!amount_sat_sub(&input_sat, input_sat, output_sat)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Not enough inputs to cover outputs. %s < %s", + type_to_string(tmpctx, struct amount_sat, &input_sat), + type_to_string(tmpctx, struct amount_sat, &output_sat)); + + /* Let's say 100k sats in miners fees is to many */ + if (amount_sat_greater(input_sat, AMOUNT_SAT(100000))) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Fees deemed exorbitant: %s", + type_to_string(tmpctx, struct amount_sat, + &input_sat)); + tx = withdraw_tx(tmpctx, c->chainparams, cast_const2(const struct utxo **, utxos), inputs, outputs, NULL, nlocktime, (const void **)&map); + /* Put our signatures on the transaction */ sign_our_inputs(tx, utxos, (const void **)&map, input_count); /* Add any 3rd party signatures */ for (i = 0; i < tal_count(inputs); i++) { if (inputs[i]->witness) { - size_t offset = tal_count(utxos) + i; - int input_index = -1; + offset = tal_count(utxos) + i; + input_index = -1; /* Find the index */ for (j = 0; j < input_count; j++) { From c8007b5fb81d357e72387367686618249db94fb1 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 16 Dec 2019 12:33:29 -0600 Subject: [PATCH 066/131] df: initialize change input --- common/test/run-funding_tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 8035bbcea9d0..62b63f7e88a2 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -187,6 +187,7 @@ int main(void) if (!amount_sat_sub(&change, utxo.amount, funding_sat) || !amount_sat_sub(&change, change, fee)) abort(); + change = AMOUNT_SAT(0); funding = funding_tx(tmpctx, chainparams, &funding_outnum, utxomap, funding_sat, From bcab452e7bf9aa1230fb13fd13fe255b1b5ced29 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 8 Oct 2019 11:11:36 -0500 Subject: [PATCH 067/131] df: add tests for burning + df Basic test for checking that burns clean up and that dual funding works (basic) --- tests/plugins/funder.py | 30 ++++++ tests/test_opening.py | 229 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100755 tests/plugins/funder.py create mode 100644 tests/test_opening.py diff --git a/tests/plugins/funder.py b/tests/plugins/funder.py new file mode 100755 index 000000000000..9aa54b88ae97 --- /dev/null +++ b/tests/plugins/funder.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""This plugin is used for an accepter to dual fund a channel. + + If the funding is even, we send back the same amount that they + asked for, ignoring our own limits. + + If funding is odd, we send back our max amount, ignoring what + they've requested. +""" + +from lightning import Plugin, Millisatoshi + +plugin = Plugin() + + +@plugin.hook("openchannel") +def on_openchannel(openchannel, plugin, **kwargs): + if openchannel['version'] == "1": + raise ValueError("Not to be used with v1") + + their_funds = Millisatoshi(openchannel['opener_satoshis']) + # We send back our maximum available funds + if their_funds.to_satoshi() % 2 == 1: + our_funds = Millisatoshi(openchannel['available_funds']) + return {'result': 'continue', 'funding_sats': our_funds} + else: + return {'result': 'continue', 'funding_sats': their_funds} + + +plugin.run() diff --git a/tests/test_opening.py b/tests/test_opening.py new file mode 100644 index 000000000000..4d50cf3b0420 --- /dev/null +++ b/tests/test_opening.py @@ -0,0 +1,229 @@ +from decimal import Decimal +from fixtures import * # noqa: F401,F403 +from flaky import flaky # noqa: F401 +from lightning import RpcError +from utils import EXPERIMENTAL_FEATURES, only_one, wait_for, sync_blockheight + +import os +import pytest +import unittest + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_two_sided_open(node_factory, bitcoind): + # We need a plugin to get l2 to contribute funds + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + fund_amount = 200000 + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + + l2_utxos = l2.rpc.listfunds()['outputs'] + assert(only_one(l2_utxos)) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + # We use an even amount, so l2 wil match + l1.rpc.fundchannel(l2.info['id'], fund_amount) + l1.bitcoin.generate_block(1) + sync_blockheight(bitcoind, [l1, l2]) + + # Check that channel established correctly + for node in [l1, l2]: + node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL') + channel = node.rpc.listpeers()['peers'][0]['channels'][0] + # Funding amount should be double + assert fund_amount * 2 * 1000 == channel['msatoshi_total'] + assert fund_amount * 1000 == channel['msatoshi_to_us'] + # Reserve should be 1% or the dust limit + assert channel['their_channel_reserve_satoshis'] == max(fund_amount * 2 // 100, 546) + assert channel['our_channel_reserve_satoshis'] == max(fund_amount * 2 // 100, 546) + + # Check that l2's original utxos have been spent + for o in l2.rpc.listfunds()['outputs']: + assert(o.status == 'confirmed') + for t in l2_utxos: + assert(not (o['txid'] == t['txid'] and o['output'] == t['output'])) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_burn_on_cancel(node_factory, bitcoind): + # If our peer cancels us, we should burn the tx + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node(may_reconnect=True) + l2 = node_factory.get_node(options={'plugin': plugin_path}, + may_reconnect=True) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + + amount = 200000 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + # Fund external wallet + addr = l1.rpc.newaddr()['bech32'] + l1.bitcoin.rpc.sendtoaddress(addr, 0.1) + bitcoind.generate_block(1) + wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1) + + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.00200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.00200000'): + txout = 1 + else: + assert False + + txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l1.rpc.listpeers()['peers'])['channels'] is not None + + # Funds should be committed to this channel open + chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) + assert chan['msatoshi_to_us'] == amount * 1000 + assert len(l2.rpc.listfunds()['outputs']) == 0 + + # Have l1 cancel + l1.rpc.fundchannel_cancel(l2.info['id']) + assert len(l1.rpc.listpeers()['peers']) == 0 + + l2.daemon.wait_for_log(r'1 utxo burned in tx') + only_one(l2.rpc.listfunds()['outputs']) + assert len(l2.rpc.listpeers()['peers']) == 0 + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + assert len(only_one(l1.rpc.listpeers()['peers'])['channels']) == 0 + assert len(only_one(l2.rpc.listpeers()['peers'])['channels']) == 0 + + # Clean up prepped tx, otherwise we leak on quit + l1.rpc.txdiscard(txid) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_peer_publish_afterburn(node_factory, bitcoind): + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node(may_reconnect=True) + l2 = node_factory.get_node(options={'plugin': plugin_path}, + may_reconnect=True) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + + amount = 1000000 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l1.rpc.txprepare([{funding_addr: amount}]) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.01000000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.01000000'): + txout = 1 + else: + assert False + + complete = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout) + assert complete['commitments_secured'] + txid = complete['txid'] + + # First prevent the burn from happening + def mock_sendrawtransaction(r): + return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}} + + # Prevent funder from broadcasting funding tx (any tx really). + l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction) + + # Spin up a burn, but fail to publish it + l2.bitcoin.generate_block(132 + 25) + sync_blockheight(bitcoind, [l2]) + + # We should have been blocked from sending transaction + l2.daemon.wait_for_log(r'Unable to publish burn transaction. Errno 100') + assert len(l2.rpc.listfunds()['outputs']) == 0 + assert len(l1.rpc.listfunds()['outputs']) == 0 + + # Remove the block, try again + l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', None) + l2.bitcoin.generate_block(25) + sync_blockheight(bitcoind, [l2]) + + # Shared txs should have burned, now + l2.daemon.wait_for_log(r'Found 1 burnable output at blockheight') + only_one(l2.rpc.listfunds()['outputs']) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + only_one(l1.rpc.listpeers()['peers'])['channels'] is None + + # Try sending the transaction + with pytest.raises(RpcError, match=r'Error broadcasting transaction:'): + l1.rpc.txsend(txid) + + # tx should not be around anymore + with pytest.raises(RpcError, match=r'not an unreleased txid'): + l1.rpc.txdiscard(txid) + + assert only_one(l1.rpc.listfunds()['outputs']) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_accepter_burns(node_factory, bitcoind): + # We need a plugin to get l2 to contribute funds + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node(may_reconnect=True) + l2 = node_factory.get_node(may_reconnect=True) + l3 = node_factory.get_node(options={'plugin': plugin_path}, + may_reconnect=True) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + l3.fundwallet(200000000) + l3.fundwallet(100000000) + + assert len(l3.rpc.listfunds()['outputs']) == 2 + + fund_amount = 200000 + + def mock_sendrawtransaction(r): + return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}} + + # Have two nodes attempt to connect with l3 + for node in [l1, l2]: + # Prevent funder from broadcasting funding tx (any tx really). + node.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction) + node.rpc.connect(l3.info['id'], 'localhost', l3.port) + with pytest.raises(RpcError): + node.rpc.fundchannel(l3.info['id'], fund_amount) + + # Outputs should be in 'shared' state + assert len(l3.rpc.listfunds()['outputs']) == 0 + + # Advance the blockchain til we hit the burn + l3.bitcoin.generate_block(132 + 25) + sync_blockheight(bitcoind, [l3]) + + # Shared txs should have burned + l3.daemon.wait_for_log(r'Found 2 burnable outputs at blockheight') + o = only_one(l3.rpc.listfunds()['outputs']) + + # Should be one utxo roughly the value of the two orignal + # utxos, minus fees + assert(o['value'] < 300000000 and o['value'] > 299900000) + + # Check that channel has been cancelled/forgotten + for node in [l1, l2]: + node.rpc.connect(l3.info['id'], 'localhost', l3.port) + only_one(node.rpc.listpeers()['peers'])['channels'] is None + assert only_one(node.rpc.listfunds()['outputs'])['value'] == 200000000 From ecafa3af2be4e2e160d51decc690bbf13baf5c2b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 16 Dec 2019 21:44:58 -0600 Subject: [PATCH 068/131] df: make version an int not a string --- lightningd/opening_control.c | 2 +- plugins/fundchannel.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 6e4a3a8c7b51..2eb9f2f6a3b3 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1130,7 +1130,7 @@ openchannel_hook_serialize(struct openchannel_hook_payload *payload, struct uncommitted_channel *uc = payload->openingd->channel; json_object_start(stream, "openchannel"); json_add_node_id(stream, "id", &uc->peer->id); - json_add_string(stream, "version", payload->is_v2 ? "2" : "1"); + json_add_num(stream, "version", payload->is_v2 ? 2 : 1); if (payload->is_v2) json_add_amount_sat_only(stream, "opener_satoshis", payload->opener_satoshis); diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 2acc418634e7..c598e52a6da0 100644 --- a/plugins/fundchannel.c +++ b/plugins/fundchannel.c @@ -247,6 +247,7 @@ static struct command_result *fundchannel_start_done(struct command *cmd, struct funding_req *fr) { struct out_req *req; + u32 version; /* Save the outscript so we can fund the outnum later */ fr->out_script = json_tok_bin_from_hex(fr, buf, @@ -257,8 +258,8 @@ static struct command_result *fundchannel_start_done(struct command *cmd, json_get_member(buf, result, "funding_address")); /* Is this a v2 request? */ - fr->is_v2 = json_tok_streq(buf, - json_get_member(buf, result, "open_channel_version"), "2"); + json_to_number(buf, json_get_member(buf, result, "open_channel_version"), &version); + fr->is_v2 = version == 2; /* Now that we're ready to go, cancel the reserved tx */ req = jsonrpc_request_start(cmd->plugin, cmd, "txdiscard", From bd0a9442969224d505686f0f3448c5b7111a3774 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 17 Dec 2019 19:00:16 -0600 Subject: [PATCH 069/131] df: fixup miscalculation in funding transaction builder Fixes miscalculation when change is less than dust. We were incorrectly subtracting the fees out twice from the amount added back into the funding output on behalf of the opener. This fixes it, plus adds a test that exposes the error. --- common/funding_tx.c | 16 +++++++------- common/test/run-funding_tx_dual.c | 35 +++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 36e7e01bb117..0e37c0154305 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -238,7 +238,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, { size_t weight = 0; struct amount_sat est_tx_fee, opener_total_sat, - accepter_total_sat, output_val; + accepter_total_sat, output_val, change; struct bitcoin_tx *tx; const struct output_info *change_output; @@ -274,6 +274,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, output_val = AMOUNT_SAT(0); if (!calculate_output_value(opener_outputs, &output_val)) return NULL; + if (!amount_sat_sub(opener_change, *opener_change, output_val)) return NULL; @@ -291,8 +292,8 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, * ... * 2. Confirm that `change_satoshis` is greater than `dust_limit_satoshis`. */ - if (amount_sat_sub(opener_change, *opener_change, est_tx_fee) && - amount_sat_greater(*opener_change, chainparams->dust_limit)) { + if (amount_sat_sub(&change, *opener_change, est_tx_fee) && + amount_sat_greater(change, chainparams->dust_limit)) { if (!change_output) { /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #3 @@ -303,10 +304,11 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, * will be added to the funding output, and credited to the opener's * initial channel balance. */ if (!amount_sat_add(opener_funding, *opener_funding, - *opener_change)) + change)) return NULL; *opener_change = AMOUNT_SAT(0); - } + } else + *opener_change = change; goto build_tx; } @@ -327,8 +329,8 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, * 2. As there is no change_output, any remaining `change_satoshis` * will be added to the funding output, and credited to the opener's * initial channel balance. */ - if (amount_sat_sub(opener_change, *opener_change, est_tx_fee)) { - if (!amount_sat_add(opener_funding, *opener_funding, *opener_change)) + if (amount_sat_sub(&change, *opener_change, est_tx_fee)) { + if (!amount_sat_add(opener_funding, *opener_funding, change)) return NULL; *opener_change = AMOUNT_SAT(0); goto build_tx; diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index 08e319284e91..cdb35fc65742 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -86,6 +86,7 @@ struct test_case { struct amount_sat opener_funding; struct amount_sat accepter_funding; struct amount_sat expected_funding; + struct amount_sat expected_change; struct bitcoin_tx *expected_tx; char *local_pubkey_str; char *remote_pubkey_str; @@ -224,6 +225,7 @@ static struct test_case test1(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "02e16172a41e928cbd78f761bd1c657c4afc7495a1244f7f30166b654fbf7661e3", .local_pubkey_str = "0292edb5f7bbf9e900f7e024be1c1339c6d149c11930e613af3a983d2565f4e41e", + .expected_change = AMOUNT_SAT(98282), }; assert(test1.expected_tx); @@ -347,6 +349,7 @@ static struct test_case test2(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(9745), }; assert(test.expected_tx); @@ -381,6 +384,7 @@ static struct test_case test3(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -415,6 +419,7 @@ static struct test_case test_no_change(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -450,6 +455,7 @@ static struct test_case test_change(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(868), }; assert(test.expected_tx); @@ -485,6 +491,7 @@ static struct test_case test_change_trimmed(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -492,9 +499,9 @@ static struct test_case test_change_trimmed(const tal_t *ctx) return test; } - -/* With change trimmed, funding increases */ -static struct test_case test_change_trimmed_positive(const tal_t *ctx) +/* With dusty change trimmed, funding increases + * (change - fee is positive but less than dust) */ +static struct test_case test_dust_change_trimmed(const tal_t *ctx) { struct input_info **opener_inputs = tal_arr(ctx, struct input_info *, 1); struct input_info **accepter_inputs = tal_arr(ctx, struct input_info *, 1); @@ -502,28 +509,27 @@ static struct test_case test_change_trimmed_positive(const tal_t *ctx) accepter_inputs[0] = input_two(ctx, txid_str_one); struct output_info **opener_outputs = tal_arr(ctx, struct output_info *, 2); - opener_outputs[0] = output_one(ctx, 5000); + opener_outputs[0] = output_one(ctx, 6500); opener_outputs[1] = output_three(ctx, 0); struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - // fee = 1310 - // change = 0 - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5aaa3160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0364190000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d588a2160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { - .feerate = 1300, + .feerate = 100, .opener_inputs = opener_inputs, .accepter_inputs = accepter_inputs, .opener_outputs = opener_outputs, .accepter_outputs = accepter_outputs, .opener_funding = AMOUNT_SAT(493000), .accepter_funding = AMOUNT_SAT(990000), - .expected_funding = AMOUNT_SAT(1483690.0), + .expected_funding = AMOUNT_SAT(1483400), .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -556,6 +562,7 @@ static struct test_case test_less_than_dust(const tal_t *ctx) .expected_tx = NULL, .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; return test; @@ -587,6 +594,7 @@ static struct test_case test_less_than_dust_with_accepter(const tal_t *ctx) .expected_tx = NULL, .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; return test; @@ -615,6 +623,7 @@ static struct test_case test_one_input(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -646,6 +655,7 @@ static struct test_case test_two_input(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; assert(test.expected_tx); @@ -685,6 +695,7 @@ static struct test_case test_full_set(const tal_t *ctx) .expected_tx = bitcoin_tx_from_hex(ctx, expected_tx_str, strlen(expected_tx_str)), .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(1893322), }; assert(test.expected_tx); @@ -714,6 +725,7 @@ static struct test_case test_more_than_input(const tal_t *ctx) .expected_tx = NULL, .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; return test; @@ -743,16 +755,16 @@ static struct test_case test_culmulative_more_than_input(const tal_t *ctx) .expected_tx = NULL, .remote_pubkey_str = "03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", .local_pubkey_str = "03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", + .expected_change = AMOUNT_SAT(0), }; return test; } - #define num_tests 14 static struct test_case (*test_cases[num_tests])(const tal_t *ctx) = { test1, test2, test3, test_no_change, test_change, test_change_trimmed, - test_change_trimmed_positive, test_less_than_dust, test_one_input, + test_less_than_dust, test_one_input, test_dust_change_trimmed, test_two_input, test_full_set, test_less_than_dust_with_accepter, test_more_than_input, test_culmulative_more_than_input, }; @@ -819,6 +831,7 @@ int main(void) abort(); assert(amount_sat_eq(total_funding, test.expected_funding)); + assert(amount_sat_eq(opener_change, test.expected_change)); assert(bitcoin_tx_eq(funding, test.expected_tx)); } From 5a3398ae213585704ee18013eefb44bc67d60980 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 17 Dec 2019 19:02:26 -0600 Subject: [PATCH 070/131] funding: fixup broken unit test for funding calc we leave off a change output if there's no change; update the tests to correctly deal with this. --- common/test/run-funding_tx.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 62b63f7e88a2..247ddffbec31 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -187,7 +187,9 @@ int main(void) if (!amount_sat_sub(&change, utxo.amount, funding_sat) || !amount_sat_sub(&change, change, fee)) abort(); - change = AMOUNT_SAT(0); + + /* Make a funding tx with change */ + change = AMOUNT_SAT(1); funding = funding_tx(tmpctx, chainparams, &funding_outnum, utxomap, funding_sat, @@ -201,10 +203,16 @@ int main(void) asset = bitcoin_tx_output_get_amount(funding, !funding_outnum); assert(amount_asset_is_main(&asset)); tmpamt = amount_asset_to_sat(&asset); + assert(amount_sat_eq(tmpamt, change)); printf("change: %s\n", type_to_string(tmpctx, struct amount_sat, &tmpamt)); + asset = bitcoin_tx_output_get_amount(funding, funding_outnum); + assert(amount_asset_is_main(&asset)); + tmpamt = amount_asset_to_sat(&asset); + assert(amount_sat_eq(tmpamt, funding_sat)); + printf("funding output: %u\n", funding_outnum); pubkey_to_hash160(&inputkey, &addr.addr); @@ -217,6 +225,22 @@ int main(void) printf("funding tx: %s\n", tal_hex(tmpctx, linearize_tx(tmpctx, funding))); + /* Make a funding tx without change */ + change = AMOUNT_SAT(0); + funding = funding_tx(tmpctx, chainparams, + &funding_outnum, utxomap, + funding_sat, + &local_funding_pubkey, + &remote_funding_pubkey, + change, + &inputkey, NULL); + + assert(funding->wtx->num_outputs == 1); + asset = bitcoin_tx_output_get_amount(funding, funding_outnum); + assert(amount_asset_is_main(&asset)); + tmpamt = amount_asset_to_sat(&asset); + assert(amount_sat_eq(tmpamt, funding_sat)); + /* No memory leaks please */ secp256k1_context_destroy(secp256k1_ctx); tal_free(tmpctx); From 77227be6bfa134707ee4bd27f55381fa647a9593 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 17 Dec 2019 19:18:34 -0600 Subject: [PATCH 071/131] gitignore: ignore external lib libbase58 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0ff353425168..a91db8880228 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ config.vars external/libbacktrace-build/ external/libbacktrace.a external/libbacktrace.la +external/libbase58/ +external/libbase58.a test/test_protocol test/test_sphinx tests/.pytest.restart From cdcfa3706b6c02054e0cbd9d7c02f54a91b9af87 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 17 Dec 2019 19:18:58 -0600 Subject: [PATCH 072/131] gitignore: ignore release directory this is where built binaries are sent; we don't need it in git --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a91db8880228..2a7ed297a6df 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ contrib/pylightning/pylightning.egg-info/ contrib/pyln-*/build/ contrib/pyln-*/dist/ contrib/pyln-*/pyln_*.egg-info/ -plugins/keysend \ No newline at end of file +plugins/keysend +release/ From 4e2584a11d446255fd5fbc4da4da6bedb91a22a8 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 16 Jan 2020 18:49:48 -0600 Subject: [PATCH 073/131] tx_add_input: fix problems with tx_add_input Fixes for changes introduced in cbfa045f91e3. - allocate empty input_amounts to zero'd out - only free input_amounts if it exists already --- bitcoin/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 27988bde1d3c..725576c765f2 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -170,9 +170,10 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid, /* Now store the input amount if we know it, so we can sign later */ if (tal_count(tx->input_amounts) < tx->wtx->num_inputs) - tal_resize(&tx->input_amounts, tx->wtx->num_inputs); + tal_resizez(&tx->input_amounts, tx->wtx->num_inputs); - tx->input_amounts[i] = tal_free(tx->input_amounts[i]); + if (tx->input_amounts[i]) + tx->input_amounts[i] = tal_free(tx->input_amounts[i]); tx->input_amounts[i] = tal_dup(tx, struct amount_sat, &amount); return i; From 5a70470b6517313dc518927e59cab46115e4c64f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 16 Jan 2020 18:05:55 -0600 Subject: [PATCH 074/131] df: add test for double spending a dual funding input --- tests/test_opening.py | 47 +++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/tests/test_opening.py b/tests/test_opening.py index 4d50cf3b0420..909aad072fa3 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -2,7 +2,7 @@ from fixtures import * # noqa: F401,F403 from flaky import flaky # noqa: F401 from lightning import RpcError -from utils import EXPERIMENTAL_FEATURES, only_one, wait_for, sync_blockheight +from utils import EXPERIMENTAL_FEATURES, only_one, sync_blockheight import os import pytest @@ -50,27 +50,24 @@ def test_two_sided_open(node_factory, bitcoind): @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") -def test_burn_on_cancel(node_factory, bitcoind): - # If our peer cancels us, we should burn the tx +def test_double_spends(node_factory, bitcoind): + # We re-use inputs if the tx hasn't been broadcast within a few hours/blocks + # In the case that this happens, we should gracefully shutdown the + # channels associated with the double-spent utxo plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') - l1 = node_factory.get_node(may_reconnect=True) - l2 = node_factory.get_node(options={'plugin': plugin_path}, - may_reconnect=True) + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + l3 = node_factory.get_node() l1.fundwallet(200000000) l2.fundwallet(200000000) + l3.fundwallet(200000000) amount = 200000 l1.rpc.connect(l2.info['id'], 'localhost', l2.port) funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] - # Fund external wallet - addr = l1.rpc.newaddr()['bech32'] - l1.bitcoin.rpc.sendtoaddress(addr, 0.1) - bitcoind.generate_block(1) - wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1) - prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) assert decode['txid'] == prep['txid'] @@ -89,19 +86,25 @@ def test_burn_on_cancel(node_factory, bitcoind): # Funds should be committed to this channel open chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) assert chan['msatoshi_to_us'] == amount * 1000 - assert len(l2.rpc.listfunds()['outputs']) == 0 + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert not only_one(funds['reserved_outputs'])['reservation_expired'] + + # l1 doesn't broadcast, let's advance 18 blocks (UTXO_RESERVATION_BLOCKS) + l1.bitcoin.generate_block(18) + sync_blockheight(bitcoind, [l2]) - # Have l1 cancel - l1.rpc.fundchannel_cancel(l2.info['id']) - assert len(l1.rpc.listpeers()['peers']) == 0 + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert only_one(funds['reserved_outputs'])['reservation_expired'] - l2.daemon.wait_for_log(r'1 utxo burned in tx') - only_one(l2.rpc.listfunds()['outputs']) - assert len(l2.rpc.listpeers()['peers']) == 0 + # try to fundchannel from l3 <-> l2 now + l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + l3.rpc.fundchannel(l2.info['id'], amount) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - assert len(only_one(l1.rpc.listpeers()['peers'])['channels']) == 0 - assert len(only_one(l2.rpc.listpeers()['peers'])['channels']) == 0 + # since we haven't updated our lookup for available utxos yet, + # we get a warning!! + l2.daemon.wait_for_log(r'Attempting to fund channel for 20000sat when max was set to 0sat') # Clean up prepped tx, otherwise we leak on quit l1.rpc.txdiscard(txid) From 6e0ec1d2e9565486792f2ae3a13a50fe8c94a7ac Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 18 Dec 2019 19:03:25 -0600 Subject: [PATCH 075/131] df: reveal utxo reservation info in listfunds Add utxo reservation information to channel output in listfunds, as this makes it much easier to track utxo sharing/cross use across multiple channel opens (as well as explaining why they disappear when one gets confirmed) Changelog-Added: `listfunds` will display reserved utxos in channel outputs, until funding tx is confirmed --- common/utxo.h | 7 ++ tests/test_opening.py | 155 ++++++++---------------------------------- wallet/wallet.c | 36 ++++++++++ wallet/wallet.h | 8 +++ wallet/walletrpc.c | 28 ++++++++ 5 files changed, 108 insertions(+), 126 deletions(-) diff --git a/common/utxo.h b/common/utxo.h index 5c3e3820c8a7..a0b9ec8105f6 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -58,6 +58,13 @@ struct utxo { u8 *scriptSig; }; +struct utxo_reservation { + struct bitcoin_txid prev_txid; + u32 prev_outnum; + u64 channel_dbid; + struct bitcoin_txid funding_txid; +}; + void towire_utxo(u8 **pptr, const struct utxo *utxo); struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max); diff --git a/tests/test_opening.py b/tests/test_opening.py index 909aad072fa3..9e9decf99217 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1,11 +1,9 @@ from decimal import Decimal from fixtures import * # noqa: F401,F403 from flaky import flaky # noqa: F401 -from lightning import RpcError from utils import EXPERIMENTAL_FEATURES, only_one, sync_blockheight import os -import pytest import unittest @@ -89,6 +87,7 @@ def test_double_spends(node_factory, bitcoind): funds = l2.rpc.listfunds() assert len(funds['outputs']) == 0 assert not only_one(funds['reserved_outputs'])['reservation_expired'] + originally_reserved_at = only_one(funds['reserved_outputs'])['reserved_at_height'] # l1 doesn't broadcast, let's advance 18 blocks (UTXO_RESERVATION_BLOCKS) l1.bitcoin.generate_block(18) @@ -102,131 +101,35 @@ def test_double_spends(node_factory, bitcoind): l3.rpc.connect(l2.info['id'], 'localhost', l2.port) l3.rpc.fundchannel(l2.info['id'], amount) - # since we haven't updated our lookup for available utxos yet, - # we get a warning!! - l2.daemon.wait_for_log(r'Attempting to fund channel for 20000sat when max was set to 0sat') - - # Clean up prepped tx, otherwise we leak on quit - l1.rpc.txdiscard(txid) - - -@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") -def test_peer_publish_afterburn(node_factory, bitcoind): - plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') - - l1 = node_factory.get_node(may_reconnect=True) - l2 = node_factory.get_node(options={'plugin': plugin_path}, - may_reconnect=True) - - l1.fundwallet(200000000) - l2.fundwallet(200000000) - - amount = 1000000 - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] - - prep = l1.rpc.txprepare([{funding_addr: amount}]) - decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) - assert decode['txid'] == prep['txid'] - - # One output will be correct. - if decode['vout'][0]['value'] == Decimal('0.01000000'): - txout = 0 - elif decode['vout'][1]['value'] == Decimal('0.01000000'): - txout = 1 - else: - assert False - - complete = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout) - assert complete['commitments_secured'] - txid = complete['txid'] - - # First prevent the burn from happening - def mock_sendrawtransaction(r): - return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}} - - # Prevent funder from broadcasting funding tx (any tx really). - l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction) - - # Spin up a burn, but fail to publish it - l2.bitcoin.generate_block(132 + 25) - sync_blockheight(bitcoind, [l2]) - - # We should have been blocked from sending transaction - l2.daemon.wait_for_log(r'Unable to publish burn transaction. Errno 100') - assert len(l2.rpc.listfunds()['outputs']) == 0 - assert len(l1.rpc.listfunds()['outputs']) == 0 - - # Remove the block, try again - l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', None) - l2.bitcoin.generate_block(25) + # before the block is confirmed, we should still have both channels available + # and awaiting lock-in + funds = l2.rpc.listfunds() + reserved_out = only_one(funds['reserved_outputs']) + reserved_out['reserved_at_height'] > originally_reserved_at + for c in funds['channels']: + utxo_rez = only_one(c['utxo_reservations']) + assert utxo_rez['txid'] == reserved_out['txid'] and utxo_rez['output'] == reserved_out['output'] + # the reserved output's txid + outpoint should be in each of the pending channels + peers = l2.rpc.listpeers()['peers'] + assert len(peers) == 2 + for p in peers: + assert only_one(p['channels'])['state'] == 'CHANNELD_AWAITING_LOCKIN' + + # Go ahead and sink the funding tx for l2<->l3 + l1.bitcoin.generate_block(1) sync_blockheight(bitcoind, [l2]) - # Shared txs should have burned, now - l2.daemon.wait_for_log(r'Found 1 burnable output at blockheight') - only_one(l2.rpc.listfunds()['outputs']) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - only_one(l1.rpc.listpeers()['peers'])['channels'] is None - - # Try sending the transaction - with pytest.raises(RpcError, match=r'Error broadcasting transaction:'): - l1.rpc.txsend(txid) - - # tx should not be around anymore - with pytest.raises(RpcError, match=r'not an unreleased txid'): - l1.rpc.txdiscard(txid) - - assert only_one(l1.rpc.listfunds()['outputs']) - - -@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") -def test_accepter_burns(node_factory, bitcoind): - # We need a plugin to get l2 to contribute funds - plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') - - l1 = node_factory.get_node(may_reconnect=True) - l2 = node_factory.get_node(may_reconnect=True) - l3 = node_factory.get_node(options={'plugin': plugin_path}, - may_reconnect=True) - - l1.fundwallet(200000000) - l2.fundwallet(200000000) - l3.fundwallet(200000000) - l3.fundwallet(100000000) - - assert len(l3.rpc.listfunds()['outputs']) == 2 - - fund_amount = 200000 - - def mock_sendrawtransaction(r): - return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}} - - # Have two nodes attempt to connect with l3 - for node in [l1, l2]: - # Prevent funder from broadcasting funding tx (any tx really). - node.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction) - node.rpc.connect(l3.info['id'], 'localhost', l3.port) - with pytest.raises(RpcError): - node.rpc.fundchannel(l3.info['id'], fund_amount) + peers = l2.rpc.listpeers()['peers'] + assert len(peers) == 1 + for p in peers: + only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' - # Outputs should be in 'shared' state - assert len(l3.rpc.listfunds()['outputs']) == 0 - - # Advance the blockchain til we hit the burn - l3.bitcoin.generate_block(132 + 25) - sync_blockheight(bitcoind, [l3]) - - # Shared txs should have burned - l3.daemon.wait_for_log(r'Found 2 burnable outputs at blockheight') - o = only_one(l3.rpc.listfunds()['outputs']) - - # Should be one utxo roughly the value of the two orignal - # utxos, minus fees - assert(o['value'] < 300000000 and o['value'] > 299900000) + # Check that the reserved funds have gone away! + funds = l2.rpc.listfunds() + assert len(funds['reserved_outputs']) == 0 + only_one(funds['channels'])['channel_sat'] == amount + only_one(funds['channels'])['channel_total_sat'] == amount * 2 + assert 'utxo_reservations' not in only_one(funds['channels']) - # Check that channel has been cancelled/forgotten - for node in [l1, l2]: - node.rpc.connect(l3.info['id'], 'localhost', l3.port) - only_one(node.rpc.listpeers()['peers'])['channels'] is None - assert only_one(node.rpc.listfunds()['outputs'])['value'] == 200000000 + # Clean up prepped tx, otherwise we leak on quit + l1.rpc.txdiscard(txid) diff --git a/wallet/wallet.c b/wallet/wallet.c index d919e385cd17..98dde3f89890 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -341,6 +341,42 @@ static bool wallet_clear_reservation(struct wallet *w, struct utxo *utxo) return wallet_output_reservation_update(w, utxo, 0, 0); } +struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, + struct wallet *w, + struct channel *c) +{ + struct db_stmt *stmt; + struct utxo_reservation **results; + + stmt = db_prepare_v2(w->db, SQL("SELECT prev_out_tx" + ", prev_out_index" + ", txid" + ", channel_id" + " FROM output_tracking" + " WHERE channel_id = ?;")); + + db_bind_int(stmt, 0, c->dbid); + db_query_prepared(stmt); + if (stmt->error) + fatal("Error fetching channel utxo reservations: %s", stmt->error); + + results = tal_arr(ctx, struct utxo_reservation *, 0); + while (db_step(stmt)) { + struct utxo_reservation *ur = tal(results, struct utxo_reservation); + db_column_txid(stmt, 0, &ur->prev_txid); + ur->prev_outnum = db_column_int(stmt, 1); + db_column_txid(stmt, 2, &ur->funding_txid); + ur->channel_dbid = db_column_int(stmt, 3); + + tal_arr_expand(&results, ur); + } + + tal_free(stmt); + + /* We return NULL if no results found */ + return tal_count(results) ? results : tal_free(results); +} + bool wallet_update_output_status(struct wallet *w, const struct bitcoin_txid *txid, const u32 outnum, enum output_status oldstatus, diff --git a/wallet/wallet.h b/wallet/wallet.h index 123b44ff536c..701f2fb4bd1d 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -386,6 +386,14 @@ bool wallet_update_output_status(struct wallet *w, const u32 outnum, enum output_status oldstatus, enum output_status newstatus); +/** + * wallet_fetch_channel_reservations - Find all current reservations for this channel + * + * Returns NULL if none found. + */ +struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, + struct wallet *w, + struct channel *c); /** * wallet_output_reservation_update - Add an expiration for a utxo reservation * Update a reserved output's reserved_at and reserved_for in the database. diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index d9888c2e1364..0b730affac8a 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -891,6 +891,25 @@ static struct command_result *add_output(struct command *cmd, return NULL; } +static void add_utxo_info(struct command *cmd, + struct json_stream *stream, + struct channel *c) +{ + struct utxo_reservation **rezzies; + size_t i; + + rezzies = wallet_fetch_channel_reservations(cmd, cmd->ld->wallet, c); + json_array_start(stream, "utxo_reservations"); + for (i = 0; i < tal_count(rezzies); i++) { + json_object_start(stream, NULL); + json_add_txid(stream, "txid", &rezzies[i]->prev_txid); + json_add_num(stream, "output", rezzies[i]->prev_outnum); + json_add_txid(stream, "funding_txid", &rezzies[i]->funding_txid); + json_object_end(stream); + } + json_array_end(stream); +} + static struct command_result *json_listfunds(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -937,6 +956,7 @@ static struct command_result *json_listfunds(struct command *cmd, channel_active(c) && c->connected); json_add_string(response, "state", channel_state_name(c)); + if (c->scid) json_add_short_channel_id(response, "short_channel_id", @@ -953,6 +973,14 @@ static struct command_result *json_listfunds(struct command *cmd, &c->funding_txid); json_add_num(response, "funding_output", c->funding_outnum); + + /* If we're in lockin state and no tx has been seen + * on the wire, print out the related utxo info, as + * it'll be useful for figuring out what's going on + * with any utxos in `reserved_outputs` */ + if (c->state == CHANNELD_AWAITING_LOCKIN && !c->scid) + add_utxo_info(cmd, response, c); + json_object_end(response); } } From 1ef814385e5f36add59cc56f30315f449ddafbed Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 19 Dec 2019 17:51:33 -0600 Subject: [PATCH 076/131] reserved: on start, make sure that reserved utxos stay reserved our utxo cleaner was incorrectly moving reserved utxos with a not yet expired reservation lease to available. we fix this by checking the reservation lease before moving it to available. requires us to move the clean utxo check to after the topology is initialized, as we need the tip height to do the reservation check correctly. includes test! --- lightningd/lightningd.c | 5 +++- tests/test_opening.py | 61 +++++++++++++++++++++++++++++++++++++++++ wallet/wallet.c | 35 +++++++++++++++++------ 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 2b0ded7e7ae3..c5b889e679e6 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -901,8 +901,11 @@ int main(int argc, char *argv[]) min_blockheight, max_blockheight); db_begin_transaction(ld->wallet->db); + /*~ Tell the wallet to start figuring out what to do for any reserved - * unspent outputs we may have crashed with. */ + * unspent outputs we may have crashed with. Happens after topology + * is initialized since we need the height to decide on some utxo + * reservation's status */ wallet_clean_utxos(ld->wallet, ld->topology->bitcoind); /*~ Pull peers, channels and HTLCs from db. Needs to happen after the diff --git a/tests/test_opening.py b/tests/test_opening.py index 9e9decf99217..98ca415802ba 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -47,6 +47,67 @@ def test_two_sided_open(node_factory, bitcoind): assert(not (o['txid'] == t['txid'] and o['output'] == t['output'])) +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_reservation_crash(node_factory, bitcoind): + # we shouldn't reset to available if we crash with reserved utxos + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + + amount = 200000 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.00200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.00200000'): + txout = 1 + else: + assert False + + txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l1.rpc.listpeers()['peers'])['channels'] is not None + + # Funds should be committed to this channel open + chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) + assert chan['msatoshi_to_us'] == amount * 1000 + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert not only_one(funds['reserved_outputs'])['reservation_expired'] + + # now we crash l2, who's got some reserved funds + l2.daemon.kill() + l2.start() + + # check that our funds are still marked as reserved + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert not only_one(funds['reserved_outputs'])['reservation_expired'] + + # discard reserved tx so we don't leak on quit + l1.rpc.txdiscard(txid) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_cancel_channel_twice(node_factory): + # check that we can cancel a channel 'twice' (two utxos in a different open) + assert True + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_rbf(node_factory, bitcoind): + assert True + + @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") def test_double_spends(node_factory, bitcoind): # We re-use inputs if the tx hasn't been broadcast within a few hours/blocks diff --git a/wallet/wallet.c b/wallet/wallet.c index 98dde3f89890..52d44c671aa4 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -332,8 +332,10 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) static bool reservation_expired(struct wallet *w, const struct utxo *utxo) { - return utxo->reserved_at && - *utxo->reserved_at + *utxo->reserved_for >= w->ld->topology->tip->height; + if (!utxo->reserved_at || !utxo->reserved_for) + return true; + + return *utxo->reserved_at + *utxo->reserved_for <= w->ld->topology->tip->height; } static bool wallet_clear_reservation(struct wallet *w, struct utxo *utxo) @@ -4171,24 +4173,39 @@ static void process_utxo_result(struct bitcoind *bitcoind, &utxos[0]->txid, utxos[0]->outnum, utxos[0]->status, newstate); - /* If we have more, resolve them too. */ tal_arr_remove(&utxos, 0); - if (tal_count(utxos) != 0) { + /* If we have more, resolve them too. */ + while (tal_count(utxos) != 0) { + if (!reservation_expired(bitcoind->ld->wallet, utxos[0])) { + tal_arr_remove(&utxos, 0); + continue; + } + bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum, process_utxo_result, utxos); - } else - tal_free(utxos); + return; + } + + tal_free(utxos); } void wallet_clean_utxos(struct wallet *w, struct bitcoind *bitcoind) { struct utxo **utxos = wallet_get_utxos(NULL, w, output_state_reserved); - if (tal_count(utxos) != 0) { + /* We skip any utxos that still have a valid reservation */ + while (tal_count(utxos) > 0) { + if (!reservation_expired(w, utxos[0])) { + tal_arr_remove(&utxos, 0); + continue; + } + bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum, process_utxo_result, notleak(utxos)); - } else - tal_free(utxos); + return; + } + + tal_free(utxos); } struct wallet_transaction *wallet_transactions_get(struct wallet *w, const tal_t *ctx) From 6b040d5831165e496046e33003037a147f83a759 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 19 Dec 2019 17:53:52 -0600 Subject: [PATCH 077/131] tests: add test for the original node broadcasting the tx need to fixup how the l3 node handles getting a cancel, however --- tests/test_opening.py | 102 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/test_opening.py b/tests/test_opening.py index 98ca415802ba..7d0943ddc07e 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1,9 +1,11 @@ from decimal import Decimal from fixtures import * # noqa: F401,F403 from flaky import flaky # noqa: F401 +from lightning import RpcError from utils import EXPERIMENTAL_FEATURES, only_one, sync_blockheight import os +import pytest import unittest @@ -194,3 +196,103 @@ def test_double_spends(node_factory, bitcoind): # Clean up prepped tx, otherwise we leak on quit l1.rpc.txdiscard(txid) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_original_publishes(node_factory, bitcoind): + """ Same thing as double_spend test, except that the original + node publishes the tx, after the reservation has expired """ + # We re-use inputs if the tx hasn't been broadcast within a few hours/blocks + # In the case that this happens, we should gracefully shutdown the + # channels associated with the double-spent utxo + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + l3 = node_factory.get_node() + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + l3.fundwallet(200000000) + + amount = 200000 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.00200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.00200000'): + txout = 1 + else: + assert False + + l1_txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l1.rpc.listpeers()['peers'])['channels'] is not None + + # Funds should be committed to this channel open + chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) + assert chan['msatoshi_to_us'] == amount * 1000 + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert not only_one(funds['reserved_outputs'])['reservation_expired'] + + # l1 doesn't broadcast, let's advance 18 blocks (UTXO_RESERVATION_BLOCKS) + l1.bitcoin.generate_block(18) + sync_blockheight(bitcoind, [l2]) + + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert only_one(funds['reserved_outputs'])['reservation_expired'] + + # try to fundchannel from l3 <-> l2 now + l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l3.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l3.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.00200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.00200000'): + txout = 1 + else: + assert False + + l3_txid = l3.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l3.rpc.listpeers()['peers'])['channels'] is not None + + peers = l2.rpc.listpeers()['peers'] + assert len(peers) == 2 + for p in peers: + assert only_one(p['channels'])['state'] == 'CHANNELD_AWAITING_LOCKIN' + + # Go ahead and sink the funding tx for l1<->l2 + l1.rpc.txsend(l1_txid) + l1.bitcoin.generate_block(1) + sync_blockheight(bitcoind, [l2, l3]) + + peers = l2.rpc.listpeers()['peers'] + assert len(peers) == 1 + for p in peers: + only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + + # Check that the reserved funds have gone away! + funds = l2.rpc.listfunds() + assert len(funds['reserved_outputs']) == 0 + only_one(funds['channels'])['channel_sat'] == amount + only_one(funds['channels'])['channel_total_sat'] == amount * 2 + assert 'utxo_reservations' not in only_one(funds['channels']) + + # What happens if l3 tries to broadcast? + with pytest.raises(RpcError, match=r'Missing inputs. Unsent tx discarded'): + l3.rpc.txsend(l3_txid) + + # FIXME: l3 should not be in AWAITING_UNILATERAL state + print(l3.rpc.listpeers()) From 49629336ceccca0ccffa0be4acf19fa3eeb2f8d1 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 20 Dec 2019 12:25:14 -0600 Subject: [PATCH 078/131] test fixup: check for RBF of other channel is triggered An RBF of a different channel should cause us to call forget_channel on that channel twice. We need to check (after RBF is implemented) that we don't actually call forget here twice --- wallet/test/run-wallet.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 9345d1f3d6a5..a6e15f9b8b48 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1061,7 +1061,7 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) { struct wallet *w = create_test_wallet(ld, ctx); struct utxo u1, u2, u3, u4; - struct bitcoin_txid txidA, txidB, txidC, txidD, txidE, txid, utxid; + struct bitcoin_txid txidA, txidB, txidC, txidD, txidE, txidF, txid, utxid; struct pubkey pk; struct node_id id; u64 channel_dbid, peer_dbid; @@ -1099,6 +1099,7 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) memset(&txidC, 2, sizeof(txidC)); memset(&txidD, 3, sizeof(txidD)); memset(&txidE, 4, sizeof(txidE)); + memset(&txidE, 5, sizeof(txidF)); db_begin_transaction(w->db); @@ -1111,7 +1112,7 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) db_exec_prepared_v2(stmt); peer_dbid = db_last_insert_id_v2(take(stmt)); - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < 5; i++) { stmt = db_prepare_v2(w->db, SQL("INSERT INTO channels " "(peer_id, id) VALUES (?, ?);")); db_bind_u64(stmt, 0, peer_dbid); @@ -1134,6 +1135,13 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidB)); CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidB)); + /* utxo set (1,2,3) for channel 2 open AD, &txid_F (diff &txid, diff channel, but RBF + * of previous, txidB) */ + channel->dbid = 2; + CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidF)); + CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidF)); + CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidF)); + /* utxo set (1,4) for channel 0 open AB, &txid_C (diff &txid, same channel) */ channel->dbid = 0; CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidC)); @@ -1141,7 +1149,7 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) /* utxo set (2,3) for channel 2 open AD, &txid_D (diff &txid, diff channel * , diff input overlap) */ - channel->dbid = 2; + channel->dbid = 4; CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidD)); CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidD)); @@ -1185,17 +1193,19 @@ static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) } /* Check that watches for txids are deleted. Checks order as well */ - CHECK_MSG(tal_count(deleted_txid_watches) == 3, "Expected three deleted txid watches"); + CHECK_MSG(tal_count(deleted_txid_watches) == 4, "Expected three deleted txid watches"); CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[0], &txidB), "looking for txidB"); CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[1], &txidC), "looking for txidC"); - CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[2], &txidD), "looking for txidD"); + CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[2], &txidF), "looking for txidF"); + CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[3], &txidD), "looking for txidD"); /* Because of how the mocks for this work, we'll get channel id '2' back twice */ - CHECK_MSG(tal_count(forgotten_channel_ids) == 2, - tal_fmt(ctx, "expected 2 forgotten channel calls got %zu", + CHECK_MSG(tal_count(forgotten_channel_ids) == 3, + tal_fmt(ctx, "expected 3 forgotten channel calls got %zu", tal_count(forgotten_channel_ids))); CHECK(forgotten_channel_ids[0] == 2); CHECK(forgotten_channel_ids[1] == 2); + CHECK(forgotten_channel_ids[2] == 4); tal_free(stmt); From 9a738839eff55c377e643c1e950f4e6dfd1d1345 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 12:36:27 -0600 Subject: [PATCH 079/131] txowatch: pass in chaintopology to callback We're going to need it for the txowatch we'll set on every channel's input. --- lightningd/chaintopology.c | 2 +- lightningd/onchain_control.c | 3 ++- lightningd/peer_control.c | 3 ++- lightningd/test/run-invoice-select-inchan.c | 3 ++- lightningd/watch.c | 12 ++++++++---- lightningd/watch.h | 5 +++-- wallet/test/run-wallet.c | 3 ++- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 7e52c9933665..ffae2c97cc41 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -82,7 +82,7 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b) if (txo) { wallet_transaction_add(topo->ld->wallet, tx, b->height, i); - txowatch_fire(txo, tx, j, b); + txowatch_fire(topo, txo, tx, j, b); } } diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index 4102b5802e72..84115df98425 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -137,7 +137,8 @@ static void onchain_txo_spent(struct channel *channel, const struct bitcoin_tx * /** * Entrypoint for the txowatch callback, stores tx and calls onchain_txo_spent. */ -static enum watch_result onchain_txo_watched(struct channel *channel, +static enum watch_result onchain_txo_watched(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, const struct block *block) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 81dfab9c0444..757568691409 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1111,7 +1111,8 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, return DELETE_WATCH; } -static enum watch_result funding_spent(struct channel *channel, +static enum watch_result funding_spent(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, size_t inputnum UNUSED, const struct block *block) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 40d25a6b17ee..ade1b266214e 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -577,7 +577,8 @@ struct txowatch *watch_txo(const tal_t *ctx UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, unsigned int output UNNEEDED, - enum watch_result (*cb)(struct channel *channel UNNEEDED, + enum watch_result (*cb)(struct chain_topology *topo UNNEEDED, + struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, size_t input_num UNNEEDED, const struct block *block)) diff --git a/lightningd/watch.c b/lightningd/watch.c index 4b0a6b2b963e..99ebb7ef3f31 100644 --- a/lightningd/watch.c +++ b/lightningd/watch.c @@ -49,10 +49,12 @@ struct txowatch { struct txwatch_output out; /* A new tx. */ - enum watch_result (*cb)(struct channel *channel, + enum watch_result (*cb)(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, const struct block *block); + }; struct txwatch { @@ -218,7 +220,8 @@ struct txowatch *watch_txo(const tal_t *ctx, struct channel *channel, const struct bitcoin_txid *txid, unsigned int output, - enum watch_result (*cb)(struct channel *channel, + enum watch_result (*cb)(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, const struct block *block)) @@ -283,7 +286,8 @@ void txwatch_fire(struct chain_topology *topo, txw_fire(txw, txid, depth); } -void txowatch_fire(const struct txowatch *txow, +void txowatch_fire(struct chain_topology *topo, + const struct txowatch *txow, const struct bitcoin_tx *tx, size_t input_num, const struct block *block) @@ -298,7 +302,7 @@ void txowatch_fire(const struct txowatch *txow, txow->out.index, type_to_string(tmpctx, struct bitcoin_txid, &txid)); - r = txow->cb(txow->channel, tx, input_num, block); + r = txow->cb(topo, txow->channel, tx, input_num, block); switch (r) { case DELETE_WATCH: tal_free(txow); diff --git a/lightningd/watch.h b/lightningd/watch.h index 962aa6ab28a4..526f0ff631e1 100644 --- a/lightningd/watch.h +++ b/lightningd/watch.h @@ -65,7 +65,8 @@ struct txowatch *watch_txo(const tal_t *ctx, struct channel *channel, const struct bitcoin_txid *txid, unsigned int output, - enum watch_result (*cb)(struct channel *channel, + enum watch_result (*cb)(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, const struct block *block)); @@ -78,7 +79,7 @@ void txwatch_fire(struct chain_topology *topo, const struct bitcoin_txid *txid, unsigned int depth); -void txowatch_fire(const struct txowatch *txow, +void txowatch_fire(struct chain_topology *topo, const struct txowatch *txow, const struct bitcoin_tx *tx, size_t input_num, const struct block *block); diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a6e15f9b8b48..662edb4f2ac2 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -717,7 +717,8 @@ struct txowatch *watch_txo(const tal_t *ctx UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, unsigned int output UNNEEDED, - enum watch_result (*cb)(struct channel *channel UNNEEDED, + enum watch_result (*cb)(struct chain_topology *topo UNNEEDED, + struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, size_t input_num UNNEEDED, const struct block *block)) From 6b0c1513cf643373321d1246f29b0fc0ff1cdd61 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 12:42:23 -0600 Subject: [PATCH 080/131] utxo watch: wait to initiate watches until after channels are populated this delays when we populate txwatches at start, moving their intiatlization until after the channels have been re-instantiated from the database. doing so removes the edgecase where txwatches don't have channels attached to them, which makes iterating through by channel dbid feasible for all cases of txwatches --- lightningd/chaintopology.c | 15 +++++++-------- lightningd/chaintopology.h | 3 +++ lightningd/lightningd.c | 4 ++++ lightningd/test/run-find_my_abspath.c | 3 +++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index ffae2c97cc41..f79ff77dfcb8 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -285,20 +285,21 @@ static enum watch_result closeinfo_txid_confirmed(struct lightningd *ld, * not already watching: there are not usually many, nor many reorgs, so the * redundancy is OK. */ -static void watch_for_utxo_reconfirmation(struct chain_topology *topo, - struct wallet *wallet) +void watch_for_utxo_reconfirmation(struct chain_topology *topo) { struct utxo **unconfirmed; + struct channel *channel; - unconfirmed = wallet_get_unconfirmed_closeinfo_utxos(tmpctx, wallet); + unconfirmed = wallet_get_unconfirmed_closeinfo_utxos(tmpctx, topo->ld->wallet); for (size_t i = 0; i < tal_count(unconfirmed); i++) { assert(unconfirmed[i]->close_info != NULL); assert(unconfirmed[i]->blockheight == NULL); - if (find_txwatch(topo, &unconfirmed[i]->txid, NULL)) + channel = channel_by_dbid(topo->ld, unconfirmed[i]->close_info->channel_id); + if (find_txwatch(topo, &unconfirmed[i]->txid, channel)) continue; - notleak(watch_txid(topo, topo, NULL, &unconfirmed[i]->txid, + notleak(watch_txid(topo, topo, channel, &unconfirmed[i]->txid, closeinfo_txid_confirmed)); } } @@ -779,7 +780,7 @@ static void remove_tip(struct chain_topology *topo) wallet_block_remove(topo->ld->wallet, b); /* This may have unconfirmed txs: reconfirm as we add blocks. */ - watch_for_utxo_reconfirmation(topo, topo->ld->wallet); + watch_for_utxo_reconfirmation(topo); block_map_del(&topo->block_map, b); tal_free(b); } @@ -960,8 +961,6 @@ static void check_blockcount(struct chain_topology *topo, u32 blockcount) /* Rollback to the given blockheight, so we start track * correctly again */ wallet_blocks_rollback(topo->ld->wallet, topo->max_blockheight); - /* This may have unconfirmed txs: reconfirm as we add blocks. */ - watch_for_utxo_reconfirmation(topo, topo->ld->wallet); } static void retry_check_chain(struct chain_topology *topo); diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 456296a09500..85c2908b84d5 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -12,6 +12,7 @@ #include #include #include +#include struct bitcoin_tx; struct bitcoind; @@ -182,6 +183,8 @@ struct chain_topology *new_topology(struct lightningd *ld, struct log *log); void setup_topology(struct chain_topology *topology, struct timers *timers, u32 min_blockheight, u32 max_blockheight); +void watch_for_utxo_reconfirmation(struct chain_topology *topo); + void begin_topology(struct chain_topology *topo); struct txlocator *locate_tx(const void *ctx, const struct chain_topology *topo, const struct bitcoin_txid *txid); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index c5b889e679e6..ee8c98a6d3fa 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -912,6 +912,10 @@ int main(int argc, char *argv[]) * topology is initialized since some decisions rely on being able to * know the blockheight. */ unconnected_htlcs_in = load_channels_from_wallet(ld); + + /* Now that we have channels initialized, add watches for unconfirmed txs: + * will be reconfirmed as we add blocks. */ + watch_for_utxo_reconfirmation(ld->topology); db_commit_transaction(ld->wallet->db); /*~ Create RPC socket: now lightning-cli can send us JSON RPC commands diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 78382bb5443b..6b29e0eb444a 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -236,6 +236,9 @@ bool wallet_network_check(struct wallet *w UNNEEDED) /* Generated stub for wallet_new */ struct wallet *wallet_new(struct lightningd *ld UNNEEDED, struct timers *timers UNNEEDED) { fprintf(stderr, "wallet_new called!\n"); abort(); } +/* Generated stub for watch_for_utxo_reconfirmation */ +void watch_for_utxo_reconfirmation(struct chain_topology *topo UNNEEDED) +{ fprintf(stderr, "watch_for_utxo_reconfirmation called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ struct log *crashlog; From a3233c121320b2aa0d09d6631f8da89033db2ea5 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 13:15:54 -0600 Subject: [PATCH 081/131] df: send remote's inputs over to lightningd we need to track them so that we know when/how to move this channel into a 'borked' state --- lightningd/opening_control.c | 2 ++ openingd/opening_wire.csv | 2 ++ openingd/openingd.c | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 2eb9f2f6a3b3..6488deab40e6 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -819,6 +819,7 @@ static void opening_fundee_finished(struct subd *openingd, struct channel_info channel_info; struct bitcoin_signature remote_commit_sig; struct bitcoin_tx *remote_commit; + const struct bitcoin_tx_input **remote_inputs; struct lightningd *ld = openingd->ld; struct bitcoin_txid funding_txid; u16 funding_outnum; @@ -853,6 +854,7 @@ static void opening_fundee_finished(struct subd *openingd, &funding_outnum, &opener_funding, &accepter_funding, + (struct bitcoin_tx_input ***)&remote_inputs, &push, &channel_flags, &feerate, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 25ee01d69fa5..c378ded2c4a4 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -133,6 +133,8 @@ msgdata,opening_fundee,funding_txid,bitcoin_txid, msgdata,opening_fundee,funding_txout,u16, msgdata,opening_fundee,opener_funding,amount_sat, msgdata,opening_fundee,accepter_funding,amount_sat, +msgdata,opening_fundee,remote_inputs_len,u16, +msgdata,opening_fundee,remote_inputs,bitcoin_tx_input,remote_inputs_len msgdata,opening_fundee,push_msat,amount_msat, msgdata,opening_fundee,channel_flags,u8, msgdata,opening_fundee,feerate_per_kw,u32, diff --git a/openingd/openingd.c b/openingd/openingd.c index 0079a8ce2009..6c4210b8b7cb 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1997,6 +1997,25 @@ static struct output_info **outputs_to_infos(const tal_t *ctx, struct bitcoin_tx return infos; } +static const struct bitcoin_tx_input **convert_inputs(const tal_t *ctx, + struct input_info **ins) +{ + size_t i; + struct bitcoin_tx_input **res = tal_arr(ctx, struct bitcoin_tx_input *, + tal_count(ins)); + for (i = 0; i < tal_count(ins); i++) { + struct bitcoin_tx_input *n = tal(res, struct bitcoin_tx_input); + n->txid = ins[i]->prevtx_txid; + n->index = ins[i]->prevtx_vout; + n->amount = ins[i]->sats; + n->witness = NULL; + n->script = NULL; + n->sequence_number = UINT32_MAX; + res[i] = n; + } + return cast_const2(const struct bitcoin_tx_input **, res); +} + static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) { struct bitcoin_blkid chain_hash; @@ -2012,6 +2031,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) struct bitcoin_signature their_sig, our_sig; secp256k1_ecdsa_signature *htlc_sigs; struct bitcoin_tx *local_commit, *remote_commit; + const struct bitcoin_tx_input **remote_inputs; struct amount_sat total_funding, opener_change; struct amount_msat local_msat; struct channel_id id_in; @@ -2331,6 +2351,11 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) msg = towire_funding_signed2(state, &state->channel_id, cast_const2(const struct witness_stack **, our_stack)); + /* We convert their inputs to a different format to get around + * the fact that we're sharing this call with the v1 (non EXPERIMENTAL_FEATURES) + * pathway as well */ + remote_inputs = convert_inputs(state, their_inputs); + /* we send everything to lightning, who commits things to the database etc. * lightningd will forward the signatures etc over to channeld, who * sends the final opening sequence message for us. */ @@ -2349,6 +2374,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) state->funding_txout, state->opener_funding, state->accepter_funding, + remote_inputs, state->push_msat, channel_flags, state->feerate_per_kw, @@ -2691,6 +2717,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) state->funding_txout, state->opener_funding, AMOUNT_SAT(0), + NULL, state->push_msat, channel_flags, state->feerate_per_kw, From 9e1ce1b703ae527f685a1e06a5588a01e50f753a Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 13:39:18 -0600 Subject: [PATCH 082/131] remove unused input checking; transitioning to watches --- lightningd/chaintopology.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index f79ff77dfcb8..2b1088d166d4 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -97,11 +97,6 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b) /* We did spends first, in case that tells us to watch tx. */ if (watching_txid(topo, &txid) || we_broadcast(topo, &txid)) { - /* If this is a tx we're watching, go ahead and - * see if this cleans up / invalidates any other - * channel opens or RBF'd transactions */ - wallet_find_check_input_tx(topo->ld->wallet, - topo, &txid); wallet_transaction_add(topo->ld->wallet, tx, b->height, i); } From 0cf447ab5e8623915e982b2650f07c7027e9a669 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 13:42:33 -0600 Subject: [PATCH 083/131] channel: add a field for hanging txowatches off of We're going to watch for a channel's txos. We need a hook to allocate them off of, preferrably something that will also get freed if the channel is freed. Here, we add a field to the channel and instantiate it to a u8 pointer, so that we can use it for allocating txowatch's with --- lightningd/channel.c | 1 + lightningd/channel.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lightningd/channel.c b/lightningd/channel.c index 4e00bbc178ec..3b31035a8b4f 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -198,6 +198,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->dbid = dbid; channel->error = NULL; channel->htlc_timeout = NULL; + channel->txowatches = tal(channel, u8); if (their_shachain) channel->their_shachain = *their_shachain; else { diff --git a/lightningd/channel.h b/lightningd/channel.h index fbd30e01079f..c33f1f5aa2ce 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -133,6 +133,9 @@ struct channel { /* Any commands trying to forget us. */ struct command **forgets; + + /* Anchor to hang txowatches off of, to make cleanup concise */ + u8 *txowatches; }; struct channel *new_channel(struct peer *peer, u64 dbid, From f3e85492bd5e71afe34302d880b65f577f4106c4 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 13:48:45 -0600 Subject: [PATCH 084/131] channel_control: allow forgetter to signal whether to notify peer In the borked channel case, we get into a race where we notify our peer that we're forgetting/erroring the channel out because it has been properly borked. In the case where we delete/remove a channel, we should assume that the peer will also see the same thing and we can safely clean up with issuing an error. TODO: verify if this is decent logic; what are the cases in which we must notify a peer of an error/channel 'forgetting'? --- lightningd/channel_control.c | 8 ++++---- lightningd/channel_control.h | 5 +++-- wallet/test/run-wallet.c | 2 +- wallet/wallet.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 1659286b44d2..c68eb0ecc6e4 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -268,7 +268,7 @@ static void handle_error_channel(struct channel *channel, forget(channel); } -void forget_channel(struct channel *channel, const char *why) +void forget_channel(struct channel *channel, bool notify, const char *why) { struct channel_id cid; @@ -278,10 +278,10 @@ void forget_channel(struct channel *channel, const char *why) /* If the peer is connected, we let them know. Otherwise * we just directly remove the channel */ - if (channel->owner) + if (channel->owner && notify) { subd_send_msg(channel->owner, take(towire_channel_send_error(NULL, why))); - else + } else forget(channel); } @@ -711,7 +711,7 @@ static void process_check_funding_broadcast(struct bitcoind *bitcoind, char *error_reason = "Cancel channel by our RPC " "command before funding " "transaction broadcast."; - forget_channel(cancel, error_reason); + forget_channel(cancel, true, error_reason); } struct command_result *cancel_channel_before_broadcast(struct command *cmd, diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index 10542e77fee2..142af597d93b 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -31,6 +31,7 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, const jsmntok_t *cidtok); /* Forget a channel. Deletes the channel and handles all - * associated waiting commands, if present. Notifies peer if available */ -void forget_channel(struct channel *channel, const char *err_msg); + * associated waiting commands, if present. Notifies peer if available + * and notify is `true` */ +void forget_channel(struct channel *channel, bool notify, const char *err_msg); #endif /* LIGHTNING_LIGHTNINGD_CHANNEL_CONTROL_H */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 662edb4f2ac2..2e718ca66a32 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -780,7 +780,7 @@ struct channel *del_txwatch(struct chain_topology *topo UNNEEDED, channel->error = NULL; return channel; } -void forget_channel(struct channel *channel UNNEEDED, const char *why UNNEEDED) { +void forget_channel(struct channel *channel UNNEEDED, bool notify UNNEEDED, const char *why UNNEEDED) { tal_arr_expand(&forgotten_channel_ids, channel->dbid); } bool fromwire_hsm_get_channel_basepoints_reply(const void *p UNNEEDED, diff --git a/wallet/wallet.c b/wallet/wallet.c index 52d44c671aa4..000ce655643a 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -240,7 +240,7 @@ bool wallet_find_check_input_tx(struct wallet *w, struct chain_topology *topo, // FIXME: this can/might free channel.. what to do about // other, possibly existing txwatches? if (chan && chan_dbid != blessed_chan_dbid && !chan->error) - forget_channel(chan, close_error); + forget_channel(chan, false, close_error); /* We want to delete all tracking for the * other outputs associated with this txid; it isn't From 922e6de8926bf8e0fb26c10d09c3aa7fa53c88b1 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:12:37 -0600 Subject: [PATCH 085/131] funding: track funding inputs until spent If an input to a channel open is spent elsewhere, we channel as 'BORKED' and wait until the 'borking' transaction has been sunk to a depth of 6; wherein we forget the channel entirely and remove all traces of it from the database. Currently, we don't notify the peer of an error when the channel has been sunk appropriately, as we expect them to also be tracking for channel 'borking's and clean up the channel on their own behalf. This removes/changes the way that tracking was being done; now every channel tracks all of its own inputs and updates them using txo watches and a tx watch for the borked transaction. Since this is different from the first attempt at tracking outputs via the database, we remove the test that tracked channel closure/deletions. A few hooks have been added to provide the ability to update a channel's status given certain actions; in the RBF open case we'll need to do more complicated accounting of what input/tx spends permanently bork a channel or open it. Still to come: repopulation of watches at start/restart. --- common/gossip_constants.h | 2 + lightningd/channel_control.c | 19 ++ lightningd/channel_control.h | 23 ++ lightningd/channel_state.h | 10 +- lightningd/opening_control.c | 201 ++++++++++- lightningd/opening_control.h | 2 + lightningd/peer_control.c | 14 + lightningd/test/run-invoice-select-inchan.c | 6 + lightningd/watch.c | 6 + lightningd/watch.h | 4 +- tests/test_opening.py | 357 ++++++++++++++++++-- wallet/test/run-wallet.c | 160 +-------- wallet/wallet.c | 196 ++++++----- wallet/wallet.h | 45 ++- wallet/walletrpc.c | 2 +- 15 files changed, 757 insertions(+), 290 deletions(-) diff --git a/common/gossip_constants.h b/common/gossip_constants.h index 914dcd24f871..dcfdc44a76f5 100644 --- a/common/gossip_constants.h +++ b/common/gossip_constants.h @@ -38,6 +38,8 @@ */ #define ANNOUNCE_MIN_DEPTH 6 +#define BORKED_MIN_DEPTH 6 + /* Gossip timing constants. These can be overridden in --enable-developer * configurations with --dev-fast-gossip, otherwise the argument is ignored */ #define DEV_FAST_GOSSIP(dev_fast_gossip_flag, fast, normal) \ diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index c68eb0ecc6e4..d7b12f29a5cc 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -285,6 +285,25 @@ void forget_channel(struct channel *channel, bool notify, const char *why) forget(channel); } +bool maybe_bork_channel(struct channel *channel, struct bitcoin_txid *txid, + struct bitcoin_txid *input_txid, u32 input_outpoint) +{ + /* If there's no RBF alternative, we move this channel into the 'borked' state */ + /* Returns true if borked */ + // TODO: only update to borked if there's no other eligible 'rbf' + // txids outstanding + channel_set_state(channel, CHANNELD_AWAITING_LOCKIN, CHANNELD_BORKED); + return true; +} + +bool maybe_cleanup_channel(struct channel *channel, const struct bitcoin_txid *txid) +{ + /* in theory, returns false if the channel isn't ready to be cleaned up */ + /* but since we don't do RBF accounting yet... */ + //FIXME: handle removal of txid for an RBF'd tx + return true; +} + static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) { enum channel_wire_type t = fromwire_peektype(msg); diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index 142af597d93b..384e02aa7b83 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -23,6 +23,29 @@ bool channel_tell_depth(struct lightningd *ld, void channel_notify_new_block(struct lightningd *ld, u32 block_height); +/* A utxo for the funding tx of this channel has been spent, + * and not for the txid that we were expecting. Clean up this + * channel, which is now Dead on Arrival. + * + * Note that 'maybe' has to do with the fact that for RBF'd + * channel opens, we may have more eligible txid's issued, + * so the nullification of one doesn't necessarily guarantee + * that this channel is dead */ +bool maybe_cleanup_channel(struct channel *channel, + const struct bitcoin_txid *txid); + +/* A utxo for the funding tx of this channel has been + * spotted as spent. It'll get cleaned up once the + * transaction bearing the 'borking' utxo spend reaches + * sufficient depth. + * + * Note that 'maybe' has to do with the fact that for RBF'd + * channel opens, we may have more eligible txid's issued, + * so the nullification of one doesn't necessarily guarantee + * that this channel is borked */ +bool maybe_bork_channel(struct channel *channel, struct bitcoin_txid *txid, + struct bitcoin_txid *input_txid, u32 input_outpoint); + /* Cancel the channel after `fundchannel_complete` succeeds * but before funding broadcasts. */ struct command_result *cancel_channel_before_broadcast(struct command *cmd, diff --git a/lightningd/channel_state.h b/lightningd/channel_state.h index f1bcd1bc3c36..8c4de7cade69 100644 --- a/lightningd/channel_state.h +++ b/lightningd/channel_state.h @@ -28,8 +28,14 @@ enum channel_state { /* On chain */ ONCHAIN, - /* Final state after we have fully settled on-chain */ - CLOSED + /* Final state after we have fully settled on-chain. Can + * also reach this state if opening transaction gets borked + * (i.e. is never on chain) */ + CLOSED, + + /* A funding input has been spent in a different tx, will never open. + * Waiting for input to get sunk to 6 before deleting/marking CLOSED */ + CHANNELD_BORKED }; #define CHANNEL_STATE_MAX CLOSED diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 6488deab40e6..010f0a9086f9 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -401,6 +401,170 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp, tal_free(fc->uc); } +/* Used semi-recursively, so declared here */ +enum watch_result txo_spent(struct chain_topology *topo, + struct channel *channel, + const struct bitcoin_tx *tx, + size_t input_num, + const struct block *block); + +void reinstate_channel_watches(struct wallet *w, struct channel *c) +{ + size_t i; + struct utxo_reservation **utxo_rs; + /* Pull up all the tx records, for this channel */ + utxo_rs = + wallet_channel_reservations_fetch_all(c->txowatches, + w, c); + + log_debug(c->log, "Reinstating %zu channel watches.", + tal_count(utxo_rs)); + + for (i = 0; i < tal_count(utxo_rs); i++) + watch_txo(c->txowatches, w->ld->topology, c, + &utxo_rs[i]->prev_txid, + utxo_rs[i]->prev_outnum, + txo_spent); + + tal_free(utxo_rs); +} + +/* A channel open was 'borked' by this transaction getting published. We track + * its burial (channel open min depth) and when reached, clean up (i.e. delete) the channel + * and associated commitment transaction information */ +static enum watch_result watch_borked_tx_burial(struct lightningd *ld, struct channel *channel, + const struct bitcoin_txid *txid, + const struct bitcoin_tx *tx, + unsigned int depth) +{ + /* This is a reorg. We need to roll back the channel state + * to AWAITING LOCKIN and re-instate all of the txo watches + * on its inputs */ + if (depth == 0) { + log_info(channel->log, "Reorg for 'borking' tx %s, reinstating channel.", + type_to_string(tmpctx, struct bitcoin_txid, txid)); + reinstate_channel_watches(ld->wallet, channel); + channel_set_state(channel, CHANNELD_BORKED, CHANNELD_AWAITING_LOCKIN); + return DELETE_WATCH; + } + + if (depth < BORKED_MIN_DEPTH) + return KEEP_WATCHING; + + if (maybe_cleanup_channel(channel, txid)) { + log_debug(channel->log, "Forgetting channel, permanently borked"); + + wallet_transaction_delete(ld->wallet, txid); + forget_channel(channel, false, "input UTXO spent elsewhere"); + + return WATCH_DELETED; + } + + /* This one's not the one to clean up the channel entirely, + * but we don't need it anymore */ + return DELETE_WATCH; +} + +enum watch_result txo_spent(struct chain_topology *topo, + struct channel *channel, + const struct bitcoin_tx *tx, + size_t input_num, + const struct block *block) +{ + struct bitcoin_txid txid, input_txid; + u32 input_outnum; + + /* If this is a tx we're watching, go ahead and + * see if this cleans up / invalidates any other + * channel opens or RBF'd transactions */ + bitcoin_txid(tx, &txid); + + /* First, try cleanup by txid, as that's most likely + * to be the actual case, i.e. this is a transaction we're + * expecting. We'll do the right thing for it when we the txwatch for it + * fires */ + if (wallet_input_tx_exists(topo->ld->wallet, &txid, channel->dbid)) { + /* Clear out any other txowatches, and reset them */ + channel->txowatches = tal_free(channel->txowatches); + channel->txowatches = tal(channel, u8); + return WATCH_DELETED; + } + + bitcoin_tx_input_get_txid(tx, input_num, &input_txid); + input_outnum = tx->wtx->inputs[input_num].index; + log_unusual(channel->log, + "input utxo %s:%u for channel funding_txid %s" + " spent in txid %s", + type_to_string(tmpctx, struct bitcoin_txid, &input_txid), + input_outnum, + type_to_string(tmpctx, struct bitcoin_txid, &channel->funding_txid), + type_to_string(tmpctx, struct bitcoin_txid, &txid)); + + /* Check if we need to mark this channel as 'borked' now (RBF will do more + * fancy things here */ + if (maybe_bork_channel(channel, &txid, &input_txid, input_outnum)) { + /* Watch the 'borking' transaction; we'll clean everything up + * when it's reached a depth of BORKED_MIN_DEPTH */ + watch_tx(channel, topo, channel, tx, watch_borked_tx_burial); + + /* Since we've got at least one tx that nullifies this channel + * we can delete all of the other txowatches for it */ + channel->txowatches = tal_free(channel->txowatches); + /* Reset the txowatch object counter */ + channel->txowatches = tal(channel, u8); + + return WATCH_DELETED; + } + + /* This channel is still has valid utxos outstanding. Delete this watch + * but keep looking for other utxos related to it. */ + return DELETE_WATCH; +} + +static void watch_tx_inputs(struct wallet *w, struct channel *c, + struct bitcoin_txid *funding_txid, + const struct bitcoin_tx_input **remote_inputs, + const struct utxo **our_utxos) +{ + size_t i; + struct bitcoin_txid txid; + u32 outpoint; + + /* Ideally this will get pushed out and included in a block + * tout suite but in case not, we should watch not only + * for all of our own inputs but also all of the inputs of our + * peer, so that if they spend them elsewhere we know to cleanup */ + for (i = 0; i < tal_count(remote_inputs); i++) { + txid = remote_inputs[i]->txid; + outpoint = remote_inputs[i]->index; + + wallet_add_input_tx_tracking(w, &txid, outpoint, + c, funding_txid); + /* Also watch it come in */ + watch_txo(c->txowatches, w->ld->topology, c, &txid, + outpoint, txo_spent); + + log_debug(c->log, "added input %s:%u to txo tracking", + type_to_string(tmpctx, struct bitcoin_txid, &txid), + outpoint); + } + + for (i = 0; i < tal_count(our_utxos); i++) { + txid = our_utxos[i]->txid; + outpoint = our_utxos[i]->outnum; + + wallet_add_input_tx_tracking(w, &txid, outpoint, + c, funding_txid); + watch_txo(c->txowatches, w->ld->topology, c, &txid, + outpoint, txo_spent); + + log_debug(c->log, "added input %s:%u to txo tracking", + type_to_string(tmpctx, struct bitcoin_txid, &txid), + outpoint); + } + +} + #if EXPERIMENTAL_FEATURES // FIXME: Switch to PSBT, not unreleased tx static bool add_remote_witnesses(struct unreleased_tx *utx, @@ -616,6 +780,11 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, remote_upfront_shutdown_script); + /* Watch for spends of any of the inputs to the tx */ + watch_tx_inputs(ld->wallet, channel, &channel->funding_txid, + cast_const2(const struct bitcoin_tx_input **, utx->inputs), + utx->wtx->utxos); + /* Watch for funding confirms */ channel_watch_funding(ld, channel); @@ -832,7 +1001,7 @@ static void opening_fundee_finished(struct subd *openingd, struct channel *channel; u8 *remote_upfront_shutdown_script, *local_upfront_shutdown_script; struct per_peer_state *pps; - struct utxo **utxos; + const struct utxo **utxos; log_debug(uc->log, "Got opening_fundee_finish_response"); @@ -885,7 +1054,8 @@ static void opening_fundee_finished(struct subd *openingd, if (uc->pf) /* We steal here, because otherwise gets eaten below */ - utxos = tal_steal(tmpctx, uc->pf->utxos); + utxos = cast_const2(const struct utxo **, + tal_steal(tmpctx, uc->pf->utxos)); else utxos = NULL; @@ -910,22 +1080,23 @@ static void opening_fundee_finished(struct subd *openingd, goto failed_later; } - log_debug(channel->log, "Watching funding tx %s", - type_to_string(reply, struct bitcoin_txid, - &channel->funding_txid)); + /* Add a watch for all the inputs for this channel open */ + watch_tx_inputs(ld->wallet, channel, &channel->funding_txid, + remote_inputs, utxos); - if (utxos) { - u32 tipheight = ld->topology->tip->height; - for (size_t i = 0; i < tal_count(utxos); i++) { - wallet_output_reservation_update(ld->wallet, utxos[i], - tipheight, - UTXO_RESERVATION_BLOCKS); - wallet_add_input_tx_tracking(ld->wallet, utxos[i], - channel, &funding_txid); - } + u32 tipheight = ld->topology->tip->height; + for (size_t i = 0; i < tal_count(utxos); i++) { + wallet_output_reservation_update(ld->wallet, utxos[i], + tipheight, + UTXO_RESERVATION_BLOCKS); + } + if (utxos) tal_free(utxos); - } + + log_debug(channel->log, "Watching funding tx %s", + type_to_string(reply, struct bitcoin_txid, + &channel->funding_txid)); channel_watch_funding(ld, channel); diff --git a/lightningd/opening_control.h b/lightningd/opening_control.h index fbf8ce7156a2..ff48a5588293 100644 --- a/lightningd/opening_control.h +++ b/lightningd/opening_control.h @@ -21,6 +21,8 @@ void peer_start_openingd(struct peer *peer, void kill_uncommitted_channel(struct uncommitted_channel *uc, const char *why); +void reinstate_channel_watches(struct wallet *w, struct channel *c); + #if DEVELOPER struct command; /* Calls report_leak_info() async. */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 757568691409..befefef8a5d0 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -928,6 +928,7 @@ peer_connected_hook_cb(struct peer_connected_hook_payload *payload STEALS, } case CHANNELD_AWAITING_LOCKIN: + case CHANNELD_BORKED: case CHANNELD_NORMAL: case CHANNELD_SHUTTING_DOWN: assert(!channel->owner); @@ -1097,6 +1098,16 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, } } + /* This is a re-org. We need to re-add watches for all associated txos */ + if (depth == 0) { + log_info(channel->log, "Reorg called on channel funding tx %s", + type_to_string(tmpctx, struct bitcoin_txid, txid)); + + /* We re-instate the watches for all of this channel's utxos + * in case something ends up 'borking' this tx open during a reorg */ + reinstate_channel_watches(ld->wallet, channel); + } + /* Try to tell subdaemon */ if (!channel_tell_depth(ld, channel, txid, depth)) return KEEP_WATCHING; @@ -1108,6 +1119,9 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, if (depth < ANNOUNCE_MIN_DEPTH) return KEEP_WATCHING; + /* Ok, we're locked in. Remove any output_tracking for this channel */ + wallet_output_tracking_delete(ld->wallet, channel->dbid); + return DELETE_WATCH; } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index ade1b266214e..de0f67bdbba8 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -380,6 +380,9 @@ void plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook /* Generated stub for plugin_hook_continue */ bool plugin_hook_continue(void *arg UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *toks UNNEEDED) { fprintf(stderr, "plugin_hook_continue called!\n"); abort(); } +/* Generated stub for reinstate_channel_watches */ +void reinstate_channel_watches(struct wallet *w UNNEEDED, struct channel *c UNNEEDED) +{ fprintf(stderr, "reinstate_channel_watches called!\n"); abort(); } /* Generated stub for subd_release_channel */ void subd_release_channel(struct subd *owner UNNEEDED, void *channel UNNEEDED) { fprintf(stderr, "subd_release_channel called!\n"); abort(); } @@ -541,6 +544,9 @@ void wallet_invoice_waitone(const tal_t *ctx UNNEEDED, void (*cb)(const struct invoice * UNNEEDED, void*) UNNEEDED, void *cbarg UNNEEDED) { fprintf(stderr, "wallet_invoice_waitone called!\n"); abort(); } +/* Generated stub for wallet_output_tracking_delete */ +void wallet_output_tracking_delete(struct wallet *w UNNEEDED, u64 channel_dbid UNNEEDED) +{ fprintf(stderr, "wallet_output_tracking_delete called!\n"); abort(); } /* Generated stub for wallet_peer_delete */ void wallet_peer_delete(struct wallet *w UNNEEDED, u64 peer_dbid UNNEEDED) { fprintf(stderr, "wallet_peer_delete called!\n"); abort(); } diff --git a/lightningd/watch.c b/lightningd/watch.c index 99ebb7ef3f31..0beff66fd450 100644 --- a/lightningd/watch.c +++ b/lightningd/watch.c @@ -228,9 +228,13 @@ struct txowatch *watch_txo(const tal_t *ctx, { struct txowatch *w = tal(ctx, struct txowatch); + /* never watch the utxo for an uncommitted channel */ + assert(channel->dbid != 0); + w->topo = topo; w->out.txid = *txid; w->out.index = output; + w->out.chan_dbid = channel->dbid; w->channel = channel; w->cb = cb; @@ -269,6 +273,7 @@ static bool txw_fire(struct txwatch *txw, tal_free(txw); return true; case KEEP_WATCHING: + case WATCH_DELETED: return true; } fatal("txwatch callback %p returned %i\n", txw->cb, r); @@ -308,6 +313,7 @@ void txowatch_fire(struct chain_topology *topo, tal_free(txow); return; case KEEP_WATCHING: + case WATCH_DELETED: return; } fatal("txowatch callback %p returned %i", txow->cb, r); diff --git a/lightningd/watch.h b/lightningd/watch.h index 526f0ff631e1..630e182d0db2 100644 --- a/lightningd/watch.h +++ b/lightningd/watch.h @@ -18,12 +18,14 @@ struct txwatch; enum watch_result { DELETE_WATCH = -1, - KEEP_WATCHING = -2 + KEEP_WATCHING = -2, + WATCH_DELETED = -3 }; struct txwatch_output { struct bitcoin_txid txid; unsigned int index; + u64 chan_dbid; }; const struct txwatch_output *txowatch_keyof(const struct txowatch *w); diff --git a/tests/test_opening.py b/tests/test_opening.py index 7d0943ddc07e..40fd89588c26 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -2,13 +2,34 @@ from fixtures import * # noqa: F401,F403 from flaky import flaky # noqa: F401 from lightning import RpcError -from utils import EXPERIMENTAL_FEATURES, only_one, sync_blockheight +from utils import EXPERIMENTAL_FEATURES, only_one, sync_blockheight, wait_for import os import pytest import unittest +def gen_funding_tx(bitcoind, node1, node2, amount): + """ Creates a valid funding transaction for node1->node2 + for """ + node1.rpc.connect(node2.info['id'], 'localhost', node2.port) + funding_addr = node1.rpc.fundchannel_start(node2.info['id'], amount)['funding_address'] + + prep = node1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal(str(amount / 10 ** 8)): + txout = 0 + elif decode['vout'][1]['value'] == Decimal(str(amount / 10 ** 8)): + txout = 1 + else: + assert False + + return node1.rpc.fundchannel_complete(node2.info['id'], prep['txid'], txout)['txid'] + + @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") def test_two_sided_open(node_factory, bitcoind): # We need a plugin to get l2 to contribute funds @@ -100,14 +121,127 @@ def test_reservation_crash(node_factory, bitcoind): @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") -def test_cancel_channel_twice(node_factory): - # check that we can cancel a channel 'twice' (two utxos in a different open) +def test_rbf(node_factory, bitcoind): + # TODO: implement RBF! assert True @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") -def test_rbf(node_factory, bitcoind): - assert True +def test_cancel_channel_twice(node_factory, bitcoind): + # check that we are ok when a channel comes up for cancel twice + # two utxos in the funding tx, each 'burnt' in a different tx (affects both + # l1 and l2) + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + l3 = node_factory.get_node() + + l1.fundwallet(200000000) + l3.fundwallet(200000000) + + # Two funding inputs for l2 + l2.fundwallet(10000000) + l2.fundwallet(10000000) + assert len(l2.rpc.listfunds()['outputs']) == 2 + + # `amount` is big enough to require 2 inputs from l2 + small_amount = 200000 + amount = 10000000 + small_amount + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.10200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.10200000'): + txout = 1 + else: + assert False + + txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l1.rpc.listpeers()['peers'])['channels'] is not None + + # Funds should be committed to this channel open + chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) + assert chan['msatoshi_to_us'] == amount * 1000 + + # Both got put into the channel funding + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + for o in funds['reserved_outputs']: + assert not o['reservation_expired'] + + # l1 doesn't broadcast, let's advance 18 blocks (UTXO_RESERVATION_BLOCKS) + l1.bitcoin.generate_block(18) + sync_blockheight(bitcoind, [l2]) + + # Check that reservations have expired for reserved outputs + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + for o in funds['reserved_outputs']: + assert o['reservation_expired'] + + # try to fundchannel from l3 <-> l2 now + l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + # Use `small_amount` so we only use one utxo + l3.rpc.fundchannel(l2.info['id'], small_amount) + + # before tx is block-confirmed, both channels are awaiting lock-in + for c in l2.rpc.listfunds()['channels']: + assert c['state'] == 'CHANNELD_AWAITING_LOCKIN' + # check that the l3 channel only has one utxo reservation + if c['peer_id'] == l3.info['id']: + assert len(c['utxo_reservations']) == 1 + else: + # but l1 should have both + assert len(c['utxo_reservations']) == 2 + + # We'll also withdraw a utxo for l2 to ourself, this should spend + # the other utxo in the l1l2 channel open that we're borking + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all') + + # Go ahead and sink the funding tx for l2<->l3 and the withdrawal + l1.bitcoin.generate_block(1) + sync_blockheight(bitcoind, [l1, l2, l3]) + + funds = l2.rpc.listfunds() + # Check the withdrawal worked + avail_out = only_one(funds['outputs']) + assert avail_out['value'] < 10000000 and avail_out['value'] > 9000000 + assert avail_out['status'] == 'confirmed' + assert len(funds['reserved_outputs']) == 0 + for c in funds['channels']: + if c['peer_id'] == l3.info['id']: + c['state'] == 'CHANNELD_NORMAL' + c['channel_sat'] == small_amount + else: + c['state'] == 'CHANNELD_BORKED' + c['channel_sat'] == amount + + assert only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['state'] == 'CHANNELD_BORKED' + + # Roll forward to where the cleanup logic gets played + l2.bitcoin.generate_block(5) + sync_blockheight(bitcoind, [l1, l2, l3]) + + wait_for(lambda: len(l1.rpc.listpeers()['peers']) == 0) + + # why did l2 not forget l1? + assert only_one(l2.rpc.listfunds()['channels'])['state'] == 'CHANNELD_NORMAL' + + # l1's state is kind of fucked up because it's really not supposed to not + # publish the funding tx + len(l1.rpc.listfunds()['outputs']) == 0 + len(l1.rpc.listfunds()['reserved_outputs']) == 1 + # Clean up prepped tx, otherwise we leak on quit + l1.rpc.txdiscard(txid) + len(l1.rpc.listfunds()['outputs']) == 1 + len(l1.rpc.listfunds()['reserved_outputs']) == 0 @unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") @@ -170,8 +304,10 @@ def test_double_spends(node_factory, bitcoind): reserved_out = only_one(funds['reserved_outputs']) reserved_out['reserved_at_height'] > originally_reserved_at for c in funds['channels']: - utxo_rez = only_one(c['utxo_reservations']) + assert len(c['utxo_reservations']) == 1 + utxo_rez = c['utxo_reservations'][0] assert utxo_rez['txid'] == reserved_out['txid'] and utxo_rez['output'] == reserved_out['output'] + # the reserved output's txid + outpoint should be in each of the pending channels peers = l2.rpc.listpeers()['peers'] assert len(peers) == 2 @@ -180,19 +316,102 @@ def test_double_spends(node_factory, bitcoind): # Go ahead and sink the funding tx for l2<->l3 l1.bitcoin.generate_block(1) - sync_blockheight(bitcoind, [l2]) + sync_blockheight(bitcoind, [l1, l2, l3]) peers = l2.rpc.listpeers()['peers'] - assert len(peers) == 1 + assert len(peers) == 2 for p in peers: - only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + if p['id'] == l3.info['id']: + only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + else: + only_one(p['channels'])['state'] == 'CHANNELD_BORKED' # Check that the reserved funds have gone away! funds = l2.rpc.listfunds() assert len(funds['reserved_outputs']) == 0 - only_one(funds['channels'])['channel_sat'] == amount - only_one(funds['channels'])['channel_total_sat'] == amount * 2 - assert 'utxo_reservations' not in only_one(funds['channels']) + for c in funds['channels']: + assert c['channel_sat'] == amount + assert c['channel_total_sat'] == amount * 2 + assert 'utxo_reservations' not in c + + assert only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['state'] == 'CHANNELD_BORKED' + + # Attempt to close borked channel, shouldn't work (not active) + with pytest.raises(RpcError, match=r'Peer has no active channel'): + l1.rpc.close(l2.info['id']) + + # Clean up prepped tx, otherwise we leak on quit + l1.rpc.txdiscard(txid) + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +def test_cancel_with_withdraw(node_factory, bitcoind): + # We re-use inputs if the tx hasn't been broadcast within a few hours/blocks + # Let's make sure we clean up the channel correctly if we withdraw + # the funds after the reservation window has expired. + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node() + l2 = node_factory.get_node(options={'plugin': plugin_path}) + + l1.fundwallet(200000000) + l2.fundwallet(200000000) + + amount = 200000 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] + + # One output will be correct. + if decode['vout'][0]['value'] == Decimal('0.00200000'): + txout = 0 + elif decode['vout'][1]['value'] == Decimal('0.00200000'): + txout = 1 + else: + assert False + + txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + assert only_one(l1.rpc.listpeers()['peers'])['channels'] is not None + + # Funds should be committed to this channel open + chan = only_one(only_one(l2.rpc.listpeers()['peers'])['channels']) + assert chan['msatoshi_to_us'] == amount * 1000 + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 0 + assert not only_one(funds['reserved_outputs'])['reservation_expired'] + + # withdraw should fail here, since we don't have funds available + with pytest.raises(RpcError, match=r'Cannot afford transaction'): + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all') + + # l1 doesn't broadcast, let's advance 18 blocks (UTXO_RESERVATION_BLOCKS) + l1.bitcoin.generate_block(18) + sync_blockheight(bitcoind, [l2]) + + # now we can withdraw the funds, no problem + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all') + + # before the block is confirmed, we should still have the channel available + # and awaiting lock-in + funds = l2.rpc.listfunds() + assert len(funds['outputs']) == 1 + # there's a little bit of weirdness here, in that the reserved output + # goes away, but we still show the utxos' for it in the awaiting channel; + # it will get cleaned up as soon as the tx is mined and at depth 6 + assert len(funds['reserved_outputs']) == 0 + assert only_one(funds['channels'])['state'] == 'CHANNELD_AWAITING_LOCKIN' + + # Go ahead and sink the withdrawal + l1.bitcoin.generate_block(1) + sync_blockheight(bitcoind, [l1, l2]) + + # Check that the channel has been marked as borked, on both sides + for node in [l1, l2]: + chan_funds = node.rpc.listfunds()['channels'] + assert only_one(chan_funds)['state'] == 'CHANNELD_BORKED' # Clean up prepped tx, otherwise we leak on quit l1.rpc.txdiscard(txid) @@ -279,20 +498,120 @@ def test_original_publishes(node_factory, bitcoind): sync_blockheight(bitcoind, [l2, l3]) peers = l2.rpc.listpeers()['peers'] - assert len(peers) == 1 + assert len(peers) == 2 + # The status for l1<->l2 is ok, l2<->l3 is borked for p in peers: - only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + if p['id'] == l1.info['id']: + only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + else: + only_one(p['channels'])['state'] == 'CHANNELD_BORKED' # Check that the reserved funds have gone away! funds = l2.rpc.listfunds() assert len(funds['reserved_outputs']) == 0 - only_one(funds['channels'])['channel_sat'] == amount - only_one(funds['channels'])['channel_total_sat'] == amount * 2 - assert 'utxo_reservations' not in only_one(funds['channels']) + + # There's still two channel entries; one's normal the other's borked + assert len(funds['channels']) == 2 + for c in funds['channels']: + c['channel_sat'] == amount + c['channel_total_sat'] == amount * 2 + assert 'utxo_reservations' not in c + + assert only_one(only_one(l3.rpc.listpeers()['peers'])['channels'])['state'] == 'CHANNELD_BORKED' # What happens if l3 tries to broadcast? with pytest.raises(RpcError, match=r'Missing inputs. Unsent tx discarded'): l3.rpc.txsend(l3_txid) - # FIXME: l3 should not be in AWAITING_UNILATERAL state - print(l3.rpc.listpeers()) + assert only_one(only_one(l3.rpc.listpeers()['peers'])['channels'])['state'] == 'CHANNELD_BORKED' + + # Now sink the 'borking' transaction so that the borked channel gets cleaned up + l1.bitcoin.generate_block(5) + sync_blockheight(bitcoind, [l2, l3]) + + # Check that l2 has canceled / thrown away l3 + assert len(l2.rpc.listpeers()['peers']) == 1 + # Check that l3 has canceled / thrown away l2 + assert len(l3.rpc.listpeers()['peers']) == 0 + + +# This assumes that EXPERIMENTAL_FEATURES implies DEVELOPER +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "needs EXPERIMENTAL_FEATURES=1") +def test_borked_tx_reorg(node_factory, bitcoind): + """ We should be able to bork a transaction, then reorg and confirm it. + We should also be able to confirm a tx, reorg and then bork it.""" + # Rescan to detect reorg at restart and may_reconnect so channeld + # will restart. Reorg can cause bad gossip msg. + opts = {'funding-confirms': 6, 'rescan': 10} + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node(options=opts) + l3 = node_factory.get_node(options=opts) + + # Add the plugin path, so that l2 does the double funding thing + opts['plugin'] = plugin_path + l2 = node_factory.get_node(options=opts) + + l1.fundwallet(10000000) # height 101 + l2.fundwallet(10000000) # height 102 + l2.fundwallet(10000000) # height 103 + l3.fundwallet(10000000) # height 104 + + funding_amount = 1000000 + gen_funding_tx(bitcoind, l1, l2, funding_amount) + bitcoind.generate_block(1) # height 105 + + l3l2_funding_txid = gen_funding_tx(bitcoind, l3, l2, funding_amount) + + # Generate 18 more so that l2 can withdraw at least one of the txs + bitcoind.generate_block(17) # heights 106-122 + sync_blockheight(bitcoind, [l2]) + + # Go ahead and withdraw some money for l2. Because of the 1 + # block difference, only the l1l2 funding_tx should be available + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], funding_amount) + + # Ship the other funding_tx + l3.rpc.txsend(l3l2_funding_txid) + + bitcoind.generate_block(3) # heights 123-125 + sync_blockheight(bitcoind, [l1, l2, l3]) + + # Ok, one channel should be borked, the other channel should + # be awaiting lockin, with a scid + assert only_one(l1.rpc.listpeers()['peers'])['channels'][0]['state'] == 'CHANNELD_BORKED' + l3_channel = only_one(l3.rpc.listpeers()['peers'])['channels'][0] + assert l3_channel['state'] == 'CHANNELD_AWAITING_LOCKIN' + assert 'short_channel_id' not in l3_channel + + # Stop l1 before the reorg + l1.stop() + bitcoind.simple_reorg(122) # height 122 + sync_blockheight(bitcoind, [l2, l3]) + + # Check that they got rolled back to 'awaiting lockin' + # QUES: why does mining a single block move this channel to NORMAL? + # it should be in 'AWAITING_LOCKIN', no? + for node in [l3]: + l3_channel = only_one(node.rpc.listpeers()['peers'])['channels'][0] + assert l3_channel['state'] == 'CHANNELD_NORMAL' + assert 'short_channel_id' in l3_channel + + # ideally we'd evict them both from the pool and re-do things (i.e. swap + # who's borked and who isn't) but i'm not sure how to do that, so for now + # we'll just assume a roll forward again is a similar enough, tho weaker, check + bitcoind.generate_block(6) # heights 123-125 + l1.start() + sync_blockheight(bitcoind, [l1, l2, l3]) + + # run the same state check! + assert not l1.rpc.listpeers()['peers'] + l3_channel = only_one(l3.rpc.listpeers()['peers'])['channels'][0] + assert l3_channel['state'] == 'CHANNELD_NORMAL' + assert 'short_channel_id' in l3_channel + + +# Test closing a channel that's not on-chain yet (but going to be borked?) +# Test fundchannel_cancel'ing a channel that's not on-chain yet (but will be borked?) +# - we shouldn't be able to cancel these, but we can 'bork' them by spending their input +# - an enterprising human can do this pretty straightforwardly. hmmmmmm diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 2e718ca66a32..ff6be1903c62 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -562,6 +562,9 @@ struct route_step *process_onionpacket( bool has_realm ) { fprintf(stderr, "process_onionpacket called!\n"); abort(); } +/* Generated stub for reinstate_channel_watches */ +void reinstate_channel_watches(struct wallet *w UNNEEDED, struct channel *c UNNEEDED) +{ fprintf(stderr, "reinstate_channel_watches called!\n"); abort(); } /* Generated stub for serialize_onionpacket */ u8 *serialize_onionpacket( const tal_t *ctx UNNEEDED, @@ -768,6 +771,7 @@ struct channel *del_txwatch(struct chain_topology *topo UNNEEDED, u64 chan_dbid UNNEEDED) { struct channel *channel = tal(tmpctx, struct channel); + channel->txowatches = tal(channel, u8); /* Add deleted txid watch to the set, for verification later */ tal_arr_expand(&deleted_txid_watches, @@ -1058,161 +1062,6 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) return true; } -static bool test_input_tx_assoc(struct lightningd *ld, const tal_t *ctx) -{ - struct wallet *w = create_test_wallet(ld, ctx); - struct utxo u1, u2, u3, u4; - struct bitcoin_txid txidA, txidB, txidC, txidD, txidE, txidF, txid, utxid; - struct pubkey pk; - struct node_id id; - u64 channel_dbid, peer_dbid; - u32 outpoint; - struct channel *channel; - struct db_stmt *stmt; - size_t count; - - /* Initialize the set of deleted tx watches */ - deleted_txid_watches = tal_arr(ctx, struct bitcoin_txid *, 0); - /* Initialize set of forgotten channels */ - forgotten_channel_ids = tal_arr(ctx, u64, 0); - - - CHECK(w); - channel = tal(ctx, struct channel); - - /* Set up utxos */ - memset(&u1, 1, sizeof(u1)); - u1.amount = AMOUNT_SAT(1); - u1.outnum = 1; - memset(&u2, 2, sizeof(u2)); - u2.amount = AMOUNT_SAT(2); - u2.outnum = 2; - memset(&u3, 3, sizeof(u3)); - u3.amount = AMOUNT_SAT(3); - u3.outnum = 3; - memset(&u4, 4, sizeof(u4)); - u4.amount = AMOUNT_SAT(4); - u4.outnum = 4; - - /* Set up bitcoin txids */ - memset(&txidA, 0, sizeof(txidA)); - memset(&txidB, 1, sizeof(txidB)); - memset(&txidC, 2, sizeof(txidC)); - memset(&txidD, 3, sizeof(txidD)); - memset(&txidE, 4, sizeof(txidE)); - memset(&txidE, 5, sizeof(txidF)); - - db_begin_transaction(w->db); - - /* Insert channel + peers into the database */ - pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); - node_id_from_pubkey(&id, &pk); - - stmt = db_prepare_v2(w->db, SQL("INSERT INTO peers (node_id) VALUES (?);")); - db_bind_node_id(stmt, 0, &id); - db_exec_prepared_v2(stmt); - peer_dbid = db_last_insert_id_v2(take(stmt)); - - for (size_t i = 0; i < 5; i++) { - stmt = db_prepare_v2(w->db, SQL("INSERT INTO channels " - "(peer_id, id) VALUES (?, ?);")); - db_bind_u64(stmt, 0, peer_dbid); - db_bind_int(stmt, 1, i); - db_exec_prepared_v2(take(stmt)); - } - - /* utxo set (1,2) for channel 0 open AB, txid_A */ - channel->dbid = 0; - CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidA)); - CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidA)); - - /* utxo set (1,2) for channel 1 open AC, &txid_A (same &txid, diff channel) */ - channel->dbid = 1; - CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidA)); - CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidA)); - - /* utxo set (1,3) for channel 2 open AD, &txid_B (diff &txid, diff channel) */ - channel->dbid = 2; - CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidB)); - CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidB)); - - /* utxo set (1,2,3) for channel 2 open AD, &txid_F (diff &txid, diff channel, but RBF - * of previous, txidB) */ - channel->dbid = 2; - CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidF)); - CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidF)); - CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidF)); - - /* utxo set (1,4) for channel 0 open AB, &txid_C (diff &txid, same channel) */ - channel->dbid = 0; - CHECK(wallet_add_input_tx_tracking(w, &u1, channel, &txidC)); - CHECK(wallet_add_input_tx_tracking(w, &u4, channel, &txidC)); - - /* utxo set (2,3) for channel 2 open AD, &txid_D (diff &txid, diff channel - * , diff input overlap) */ - channel->dbid = 4; - CHECK(wallet_add_input_tx_tracking(w, &u2, channel, &txidD)); - CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidD)); - - /* utxo set (3,4) for channel 3 open AE, &txid_E (no correlation, untouched) */ - channel->dbid = 3; - CHECK(wallet_add_input_tx_tracking(w, &u3, channel, &txidE)); - CHECK(wallet_add_input_tx_tracking(w, &u4, channel, &txidE)); - - CHECK_MSG(wallet_find_check_input_tx(w, ld->topology, &txidA), - "Error clearing out related inputs"); - CHECK_MSG(!wallet_err, wallet_err); - - /* check that txid_E, (3,4) are the only things still in table */ - stmt = db_prepare_v2(w->db, SQL("SELECT prev_out_tx, prev_out_index, txid, channel_id" - " FROM output_tracking")); - db_query_prepared(stmt); - - CHECK(!stmt->error); - count = 0; - while (db_step(stmt)) { - db_column_txid(stmt, 0, &utxid); - outpoint = db_column_int(stmt, 1); - db_column_txid(stmt, 2, &txid); - channel_dbid = db_column_int(stmt, 3); - - CHECK_MSG(bitcoin_txid_eq(&txid, &txidE), - tal_fmt(ctx, "expected txidE, got %s channel id %"PRIu64" utxo %s", - type_to_string(ctx, struct bitcoin_txid, &txid), - channel_dbid, - type_to_string(ctx, struct bitcoin_txid, &utxid))); - CHECK_MSG(channel_dbid == 3, - tal_fmt(ctx, "channel_dbid is %"PRIu64", expecting 3", channel_dbid)); - if (bitcoin_txid_eq(&utxid, &u3.txid)) { - CHECK(outpoint == 3); - } else if (bitcoin_txid_eq(&utxid, &u4.txid)) { - CHECK(outpoint == 4); - } else { - CHECK_MSG(false, "utxo incorrect"); - } - count++; - } - - /* Check that watches for txids are deleted. Checks order as well */ - CHECK_MSG(tal_count(deleted_txid_watches) == 4, "Expected three deleted txid watches"); - CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[0], &txidB), "looking for txidB"); - CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[1], &txidC), "looking for txidC"); - CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[2], &txidF), "looking for txidF"); - CHECK_MSG(bitcoin_txid_eq(deleted_txid_watches[3], &txidD), "looking for txidD"); - - /* Because of how the mocks for this work, we'll get channel id '2' back twice */ - CHECK_MSG(tal_count(forgotten_channel_ids) == 3, - tal_fmt(ctx, "expected 3 forgotten channel calls got %zu", - tal_count(forgotten_channel_ids))); - CHECK(forgotten_channel_ids[0] == 2); - CHECK(forgotten_channel_ids[1] == 2); - CHECK(forgotten_channel_ids[2] == 4); - - tal_free(stmt); - - db_commit_transaction(w->db); - return count > 0; -} static bool test_shachain_crud(struct lightningd *ld, const tal_t *ctx) { @@ -1714,7 +1563,6 @@ int main(void) htlc_out_map_init(&ld->htlcs_out); ok &= test_wallet_outputs(ld, tmpctx); - ok &= test_input_tx_assoc(ld, tmpctx); ok &= test_shachain_crud(ld, tmpctx); ok &= test_channel_crud(ld, tmpctx); ok &= test_channel_config_crud(ld, tmpctx); diff --git a/wallet/wallet.c b/wallet/wallet.c index 000ce655643a..0592086226dc 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -152,8 +152,9 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, return true; } -bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, - struct channel *channel, struct bitcoin_txid *txid) +bool wallet_add_input_tx_tracking(struct wallet *w, const struct bitcoin_txid *input_txid, + u32 input_outnum, struct channel *channel, + struct bitcoin_txid *txid) { struct db_stmt *stmt; size_t changes; @@ -166,8 +167,8 @@ bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, ", channel_id" ") VALUES (?, ?, ?, ?);")); - db_bind_txid(stmt, 0, &utxo->txid); - db_bind_int(stmt, 1, utxo->outnum); + db_bind_txid(stmt, 0, input_txid); + db_bind_int(stmt, 1, input_outnum); db_bind_txid(stmt, 2, txid); db_bind_int(stmt, 3, channel->dbid); @@ -177,90 +178,48 @@ bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, return changes > 0; } -bool wallet_find_check_input_tx(struct wallet *w, struct chain_topology *topo, - struct bitcoin_txid *txid) +bool wallet_input_tx_exists(struct wallet *w, struct bitcoin_txid *txid, + u64 channel_dbid) { - struct db_stmt *utxo_stmt, *stmt, *del_stmt; - struct bitcoin_txid utxo_txid, f_txid; - struct channel *chan; - u32 outpoint; - u64 blessed_chan_dbid, chan_dbid; - char *close_error = "input UTXO spent elsewhere"; - - utxo_stmt = db_prepare_v2(w->db, - SQL("SELECT prev_out_tx, prev_out_index" - ", channel_id FROM output_tracking" - " WHERE txid = ?;")); - db_bind_txid(utxo_stmt, 0, txid); - db_query_prepared(utxo_stmt); - - if (utxo_stmt->error) - fatal("%s", utxo_stmt->error); + struct db_stmt *stmt; + bool match; + stmt = db_prepare_v2(w->db, + SQL("SELECT COUNT(1)" + " FROM output_tracking" + " WHERE txid = ?" + " AND channel_id = ?;")); + db_bind_txid(stmt, 0, txid); + db_bind_int(stmt, 1, channel_dbid); + db_query_prepared(stmt); - /* Iterate through all of the inputs we cared about for this txid. - * Look up any other tracking records for that input */ - while (db_step(utxo_stmt)) { - /* Pull out the current utxo info */ - db_column_txid(utxo_stmt, 0, &utxo_txid); - outpoint = db_column_int(utxo_stmt, 1); - blessed_chan_dbid = db_column_int(utxo_stmt, 2); + if (db_step(stmt)) { + match = db_column_u64(stmt, 0) > 0; + } else + match = false; - stmt = db_prepare_v2(w->db, - SQL("SELECT txid, channel_id FROM output_tracking" - " WHERE prev_out_tx = ? AND prev_out_index = ?" - " AND txid != ?;")); - db_bind_txid(stmt, 0, &utxo_txid); - db_bind_int(stmt, 1, outpoint); - db_bind_txid(stmt, 2, txid); + tal_free(stmt); + return match; +} - db_query_prepared(stmt); - if (stmt->error) - fatal("%s", stmt->error); - - while (db_step(stmt)) { - /* Pull out subquery's info */ - db_column_txid(stmt, 0, &f_txid); - chan_dbid = db_column_int(stmt, 1); - - /* Remove the tx_filter for this txid (this isn't ever coming) - * and return the channel object */ - chan = del_txwatch(topo, &f_txid, chan_dbid); - - /* This is a channel cancel; otherwise it's an RBF'd tx. - * Defunct RBFs don't need cleanup as the correction - * to the 'good' txid is taken care of elsewhere - * - * `forget_channel` immediately marks the chan with an error, - * so we check that to see if we're already canceling it (since - * in some paths we require notifying the peer first, which - * is not synchronous. Ultimately, this frees the channel, - * so subsequent lookups of the channel in txwatch should return NULL - * */ - // FIXME: this can/might free channel.. what to do about - // other, possibly existing txwatches? - if (chan && chan_dbid != blessed_chan_dbid && !chan->error) - forget_channel(chan, false, close_error); - - /* We want to delete all tracking for the - * other outputs associated with this txid; it isn't - * ever coming through. */ - del_stmt = db_prepare_v2(w->db, SQL("DELETE FROM output_tracking" - " WHERE txid = ?;")); - db_bind_txid(del_stmt, 0, &f_txid); - db_exec_prepared_v2(take(del_stmt)); - } - tal_free(stmt); - } +void wallet_output_tracking_delete(struct wallet *w, u64 channel_dbid) +{ + struct db_stmt *stmt; + /* delete any references to this txid */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM output_tracking" + " WHERE channel_id = ?;")); + db_bind_int(stmt, 0, channel_dbid); + db_exec_prepared_v2(take(stmt)); +} - /* Finally, clean up the existing txid's records */ - del_stmt = db_prepare_v2(w->db, SQL("DELETE FROM output_tracking" - " WHERE txid = ?;")); - db_bind_txid(del_stmt, 0, txid); - db_exec_prepared_v2(take(del_stmt)); +void wallet_transaction_delete(struct wallet *w, const struct bitcoin_txid *txid) +{ + struct db_stmt *stmt; - tal_free(utxo_stmt); - return true; + stmt = db_prepare_v2(w->db, SQL("DELETE FROM transactions" + " WHERE id = ?;")); + db_bind_txid(stmt, 0, txid); + db_exec_prepared_v2(take(stmt)); } /** @@ -338,18 +297,20 @@ static bool reservation_expired(struct wallet *w, const struct utxo *utxo) return *utxo->reserved_at + *utxo->reserved_for <= w->ld->topology->tip->height; } -static bool wallet_clear_reservation(struct wallet *w, struct utxo *utxo) +static bool wallet_clear_reservation(struct wallet *w, const struct utxo *utxo) { return wallet_output_reservation_update(w, utxo, 0, 0); } -struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, - struct wallet *w, - struct channel *c) +struct utxo_reservation **wallet_channel_reservations_fetch_all(const tal_t *ctx, + struct wallet *w, + struct channel *c) { struct db_stmt *stmt; struct utxo_reservation **results; + /* We save both ours and theirs inputs to output_tracking, so filter + * to just inputs that we own here */ stmt = db_prepare_v2(w->db, SQL("SELECT prev_out_tx" ", prev_out_index" ", txid" @@ -379,6 +340,47 @@ struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, return tal_count(results) ? results : tal_free(results); } +struct utxo_reservation **wallet_channel_reservations_fetch(const tal_t *ctx, + struct wallet *w, + struct channel *c) +{ + struct db_stmt *stmt; + struct utxo_reservation **results; + + /* We save both ours and theirs inputs to output_tracking, so filter + * to just inputs that we own here */ + stmt = db_prepare_v2(w->db, SQL("SELECT o.prev_out_tx" + ", o.prev_out_index" + ", ot.txid" + ", ot.channel_id" + " FROM outputs o" + " LEFT OUTER JOIN output_tracking ot" + " ON o.prev_out_index = ot.prev_out_index" + " AND o.prev_out_tx = ot.prev_out_tx" + " WHERE ot.channel_id = ?;")); + + db_bind_int(stmt, 0, c->dbid); + db_query_prepared(stmt); + if (stmt->error) + fatal("Error fetching channel utxo reservations: %s", stmt->error); + + results = tal_arr(ctx, struct utxo_reservation *, 0); + while (db_step(stmt)) { + struct utxo_reservation *ur = tal(results, struct utxo_reservation); + db_column_txid(stmt, 0, &ur->prev_txid); + ur->prev_outnum = db_column_int(stmt, 1); + db_column_txid(stmt, 2, &ur->funding_txid); + ur->channel_dbid = db_column_int(stmt, 3); + + tal_arr_expand(&results, ur); + } + + tal_free(stmt); + + /* We return NULL if no results found */ + return tal_count(results) ? results : tal_free(results); +} + bool wallet_update_output_status(struct wallet *w, const struct bitcoin_txid *txid, const u32 outnum, enum output_status oldstatus, @@ -451,7 +453,7 @@ static bool wallet_reserve_output(struct wallet *w, struct utxo *u) } bool wallet_output_reservation_update(struct wallet *w, - struct utxo *utxo, + const struct utxo *utxo, const u32 current_height, const u32 reserve_for) { @@ -3806,6 +3808,28 @@ struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx, return txids; } +struct bitcoin_tx *wallet_channel_find_funding_tx(const tal_t *ctx, + struct wallet *w, + struct channel *channel) +{ + struct db_stmt *stmt; + struct bitcoin_tx *funding_tx; + + stmt = db_prepare_v2(w->db, SQL("SELECT rawtx" + " FROM transactions" + " WHERE id = ?;")); + db_bind_txid(stmt, 0, &channel->funding_txid); + db_query_prepared(stmt); + + if (db_step(stmt)) + funding_tx = db_column_tx(ctx, stmt, 0); + else + funding_tx = NULL; + + tal_free(stmt); + return funding_tx; +} + void wallet_channeltxs_add(struct wallet *w, struct channel *chan, const int type, const struct bitcoin_txid *txid, const u32 input_num, const u32 blockheight) diff --git a/wallet/wallet.h b/wallet/wallet.h index 701f2fb4bd1d..47de5f182ac0 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -355,15 +355,27 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, * us to 1) clean up channels that aren't opened because of a spend elsewhere * and 2) track RBFs for channel opens. */ -bool wallet_add_input_tx_tracking(struct wallet *w, struct utxo *utxo, - struct channel *chnanel, struct bitcoin_txid *txid); +bool wallet_add_input_tx_tracking(struct wallet *w, const struct bitcoin_txid *input_txid, + u32 input_outnum, struct channel *channel, + struct bitcoin_txid *txid); -/* wallet_find_check_input_tx - Find and clean up any associated funding tx's - * that are no longer valid/spendable because of the inclusion of this - * txid in a block. Cleans up any associated channels and tx-watches as well. +/* wallet_input_tx_exists - Confirm that the txid matches for this channel. + * + * Returns true if this is a valid txid for the channel open. + */ +bool wallet_input_tx_exists(struct wallet *w, struct bitcoin_txid *txid, + u64 channel_dbid); + +/* wallet_output_tracking_delete - remove all output tracking for a channel */ +void wallet_output_tracking_delete(struct wallet *w, u64 channel_dbid); + +/* wallet_transaction_delete - Delete a transaction record from the database + * + * Used for transactions that bork channels, that aren't our wallet's, after + * the transaction has reached sufficient depth to be considered permanent. */ -bool wallet_find_check_input_tx(struct wallet *w, struct chain_topology *topo, - struct bitcoin_txid *txid); +void wallet_transaction_delete(struct wallet *w, const struct bitcoin_txid *txid); + /** * wallet_confirm_tx - Confirm a tx which contains a UTXO. */ @@ -386,12 +398,19 @@ bool wallet_update_output_status(struct wallet *w, const u32 outnum, enum output_status oldstatus, enum output_status newstatus); +/* wallet_channel_reservations_fetch_all - Finds all utxo inputs for this + * channel, including peer's inputs. + */ +struct utxo_reservation **wallet_channel_reservations_fetch_all(const tal_t *ctx, + struct wallet *w, + struct channel *c); /** - * wallet_fetch_channel_reservations - Find all current reservations for this channel + * wallet_channel_reservations_fetch - Find all current reservations for this channel, + * filtered to just utxos that we own. * * Returns NULL if none found. */ -struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, +struct utxo_reservation **wallet_channel_reservations_fetch(const tal_t *ctx, struct wallet *w, struct channel *c); /** @@ -407,7 +426,7 @@ struct utxo_reservation **wallet_fetch_channel_reservations(const tal_t *ctx, * @current_height - current blockeheight * @reserve_for - number of blocks to hold reservation */ bool wallet_output_reservation_update(struct wallet *w, - struct utxo *utxo, + const struct utxo *utxo, const u32 current_height, const u32 reserved_for); /** @@ -1222,6 +1241,12 @@ struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx, struct wallet *w, const u32 blockheight); +/* Given a channel, find the funding tx from the transactions table. + * + * Returns NULL if not found */ +struct bitcoin_tx *wallet_channel_find_funding_tx(const tal_t *ctx, + struct wallet *w, + struct channel *channel); /** * Store transactions of interest in the database to replay on restart */ diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 0b730affac8a..17906d31b941 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -898,7 +898,7 @@ static void add_utxo_info(struct command *cmd, struct utxo_reservation **rezzies; size_t i; - rezzies = wallet_fetch_channel_reservations(cmd, cmd->ld->wallet, c); + rezzies = wallet_channel_reservations_fetch(cmd, cmd->ld->wallet, c); json_array_start(stream, "utxo_reservations"); for (i = 0; i < tal_count(rezzies); i++) { json_object_start(stream, NULL); From 0d255c855881cadc4144696c2837b331cc449c58 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:19:17 -0600 Subject: [PATCH 086/131] channel: helpers for declaring a channel borked/active --- lightningd/channel.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lightningd/channel.h b/lightningd/channel.h index c33f1f5aa2ce..8823b2cca0ac 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -256,6 +256,17 @@ static inline bool channel_on_chain(const struct channel *channel) return channel_state_on_chain(channel->state); } +static inline bool channel_is_borked(const struct channel *channel) +{ + return channel->state == CHANNELD_BORKED; +} + +static inline bool channel_not_locked(const struct channel *channel) +{ + return channel_is_borked(channel) + || channel->state == CHANNELD_AWAITING_LOCKIN; +} + static inline bool channel_active(const struct channel *channel) { return channel->state != FUNDING_SPEND_SEEN From 384ec94da07a4a152c13f43a16192cb4b2a45895 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:19:40 -0600 Subject: [PATCH 087/131] channel: on a permanent failure, only drop to chain if not borked Borked channels are 'borked' because they haven't (and won't) make it to chain; we can't drop to chain for borked channels. --- lightningd/channel.c | 8 ++++++-- lightningd/peer_control.c | 8 ++++---- lightningd/peer_control.h | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 3b31035a8b4f..c5b2b6dc2307 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -415,8 +415,12 @@ void channel_fail_permanent(struct channel *channel, const char *fmt, ...) } channel_set_owner(channel, NULL); - /* Drop non-cooperatively (unilateral) to chain. */ - drop_to_chain(ld, channel, false); + + if (channel_is_borked(channel)) + resolve_close_command(ld, channel, false); + else + /* Drop non-cooperatively (unilateral) to chain. */ + drop_to_chain(ld, channel, false); if (channel_active(channel)) channel_set_state(channel, channel->state, AWAITING_UNILATERAL); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index befefef8a5d0..7cb04139484b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -233,10 +233,10 @@ resolve_one_close_command(struct close_command *cc, bool cooperative) was_pending(command_success(cc->cmd, result)); } -/* Resolve a close command for a channel that will be closed soon. */ -static void -resolve_close_command(struct lightningd *ld, struct channel *channel, - bool cooperative) +/* Resolve a close command for a channel that will be closed soon, or + * that is borked (never will be on chain) */ +void resolve_close_command(struct lightningd *ld, struct channel *channel, + bool cooperative) { struct close_command *cc; struct close_command *n; diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 58261f16fb2e..3220e52283bc 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -85,6 +85,9 @@ void activate_peers(struct lightningd *ld); void drop_to_chain(struct lightningd *ld, struct channel *channel, bool cooperative); +void resolve_close_command(struct lightningd *ld, struct channel *channel, + bool cooperative); + void channel_watch_funding(struct lightningd *ld, struct channel *channel); /* Pull peers, channels and HTLCs from db, and wire them up. From c186c0a54922642c960e518fa2a8e8b18b8bb235 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:20:33 -0600 Subject: [PATCH 088/131] channel: update 'active' to exclude any borked channels These channels won't ever make it to chain, and thus aren't anywhere near active. --- lightningd/channel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lightningd/channel.h b/lightningd/channel.h index 8823b2cca0ac..2844a856a9ad 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -271,7 +271,8 @@ static inline bool channel_active(const struct channel *channel) { return channel->state != FUNDING_SPEND_SEEN && channel->state != CLOSINGD_COMPLETE - && !channel_on_chain(channel); + && !channel_on_chain(channel) + && !channel_is_borked(channel); } void get_channel_basepoints(struct lightningd *ld, From 65ed74d0a11f96f6f4db22d541911138f69ff383 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:21:12 -0600 Subject: [PATCH 089/131] close: borked channels can't be closed --- lightningd/peer_control.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 7cb04139484b..a1bbd64c6a95 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -221,6 +221,13 @@ resolve_one_close_command(struct close_command *cc, bool cooperative) struct json_stream *result = json_stream_success(cc->cmd); struct bitcoin_txid txid; + /* Borked channels don't have onchain txids or tx info */ + if (channel_is_borked(cc->channel)) { + json_add_string(result, "type", "borked"); + was_pending(command_success(cc->cmd, result)); + return; + } + bitcoin_txid(cc->channel->last_tx, &txid); json_add_tx(result, "tx", cc->channel->last_tx); From 5793d836fbc29c7afb6dce384f1f08d6f8c9612e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:30:40 -0600 Subject: [PATCH 090/131] channel: check if we have funds in channel before forgetting don't forget a channel that we've contributed funds to --- lightningd/peer_control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index a1bbd64c6a95..680bc50cb226 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -430,8 +430,10 @@ void channel_errmsg(struct channel *channel, */ /* We should immediately forget the channel if we receive error during - * CHANNELD_AWAITING_LOCKIN if we are fundee. */ + * CHANNELD_AWAITING_LOCKIN if we are fundee and have no funds + * in the channel open */ if (!err_for_them && channel->opener == REMOTE + && amount_sat_eq(channel->our_funds, AMOUNT_SAT(0)) && channel->state == CHANNELD_AWAITING_LOCKIN) channel_fail_forget(channel, "%s: %s ERROR %s", channel->owner->name, From b0e4a5cb4d691ffcee32bb19a0b97968f5f5f75c Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 14:31:29 -0600 Subject: [PATCH 091/131] wallet outputs: move output state to spent when spent_height updated A transaction should be moved into 'spent' when the spent_height is populated. --- wallet/wallet.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/wallet/wallet.c b/wallet/wallet.c index 0592086226dc..828f8747339f 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -3399,21 +3399,23 @@ wallet_outpoint_spend(struct wallet *w, const tal_t *ctx, const u32 blockheight, int changes; if (outpointfilter_matches(w->owned_outpoints, txid, outnum)) { stmt = db_prepare_v2(w->db, SQL("UPDATE outputs " - "SET spend_height = ? " - "WHERE prev_out_tx = ?" + "SET spend_height = ?" + ", status = ?" + " WHERE prev_out_tx = ?" " AND prev_out_index = ?")); db_bind_int(stmt, 0, blockheight); - db_bind_sha256d(stmt, 1, &txid->shad); - db_bind_int(stmt, 2, outnum); + db_bind_int(stmt, 1, output_status_in_db(output_state_spent)); + db_bind_sha256d(stmt, 2, &txid->shad); + db_bind_int(stmt, 3, outnum); db_exec_prepared_v2(take(stmt)); } if (outpointfilter_matches(w->utxoset_outpoints, txid, outnum)) { stmt = db_prepare_v2(w->db, SQL("UPDATE utxoset " - "SET spendheight = ? " - "WHERE txid = ?" + "SET spendheight = ?" + " WHERE txid = ?" " AND outnum = ?")); db_bind_int(stmt, 0, blockheight); From 29fa621515fb78c2504baaa1a936eaa766a47def Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 16:30:33 -0600 Subject: [PATCH 092/131] borked: re-instate info about borked transactions at start/restart On restart, we need to re-load all of the 'borked' channel information, so that we can accurately move the channel into the correct state as they move forward. Note that this assumes that the rescan done at start is >=6 from the tip. If a rescan is done of less than 6 then borked transactions will not be properly watched and borked channels will not get cleaned up. --- lightningd/channel_control.c | 5 ++- lightningd/opening_control.c | 2 +- lightningd/peer_control.c | 9 ++++ lightningd/test/run-invoice-select-inchan.c | 6 +++ tests/test_opening.py | 47 +++++++++++++++++++++ wallet/wallet.c | 2 +- 6 files changed, 68 insertions(+), 3 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index d7b12f29a5cc..334471c2ba26 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -292,7 +292,10 @@ bool maybe_bork_channel(struct channel *channel, struct bitcoin_txid *txid, /* Returns true if borked */ // TODO: only update to borked if there's no other eligible 'rbf' // txids outstanding - channel_set_state(channel, CHANNELD_AWAITING_LOCKIN, CHANNELD_BORKED); + + /* The channel may already be in a borked state, if this is a replay from start */ + if (!channel_is_borked(channel)) + channel_set_state(channel, CHANNELD_AWAITING_LOCKIN, CHANNELD_BORKED); return true; } diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 010f0a9086f9..638e9b0acf02 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -417,7 +417,7 @@ void reinstate_channel_watches(struct wallet *w, struct channel *c) wallet_channel_reservations_fetch_all(c->txowatches, w, c); - log_debug(c->log, "Reinstating %zu channel watches.", + log_debug(c->log, "Reinstating %zu watches for channel.", tal_count(utxo_rs)); for (i = 0; i < tal_count(utxo_rs); i++) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 680bc50cb226..49f5fbf421bb 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1492,6 +1492,15 @@ static void activate_peer(struct peer *peer, u32 delay) list_for_each(&peer->channels, channel, list) { /* Watching lockin may be unnecessary, but it's harmless. */ channel_watch_funding(ld, channel); + + /* If the channel's not locked in, we should watch for all of + * the utxos; the replay will/should clean these up and add the + * requisite txwatch for a 'borking tx' (if needed) */ + if (channel_not_locked(channel)) { + db_begin_transaction(ld->wallet->db); + reinstate_channel_watches(ld->wallet, channel); + db_commit_transaction(ld->wallet->db); + } } } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index de0f67bdbba8..bc4203b474d8 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -77,6 +77,12 @@ struct command_result *command_success(struct command *cmd UNNEEDED, /* Generated stub for connect_succeeded */ void connect_succeeded(struct lightningd *ld UNNEEDED, const struct peer *peer UNNEEDED) { fprintf(stderr, "connect_succeeded called!\n"); abort(); } +/* Generated stub for db_begin_transaction_ */ +void db_begin_transaction_(struct db *db UNNEEDED, const char *location UNNEEDED) +{ fprintf(stderr, "db_begin_transaction_ called!\n"); abort(); } +/* Generated stub for db_commit_transaction */ +void db_commit_transaction(struct db *db UNNEEDED) +{ fprintf(stderr, "db_commit_transaction called!\n"); abort(); } /* Generated stub for delay_then_reconnect */ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED, const struct wireaddr_internal *addrhint TAKES UNNEEDED) diff --git a/tests/test_opening.py b/tests/test_opening.py index 40fd89588c26..07b937e31f07 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -611,6 +611,53 @@ def test_borked_tx_reorg(node_factory, bitcoind): assert 'short_channel_id' in l3_channel +# This assumes that EXPERIMENTAL_FEATURES implies DEVELOPER +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "needs EXPERIMENTAL_FEATURES=1") +def test_borked_tx_restart(node_factory, bitcoind): + # Test that restarting a node while a transaction is borked/getting borked/ + # buried works as expected + opts = {'funding-confirms': 6, 'rescan': 10} + plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') + + l1 = node_factory.get_node(options=opts) + opts['plugin'] = plugin_path + l2 = node_factory.get_node(options={'plugin': plugin_path}) + + l1.fundwallet(10000000) + l2.fundwallet(10000000) + + funding_amount = 1000000 + gen_funding_tx(bitcoind, l1, l2, funding_amount) + + l1.stop() + + # Have l2 spend their funds elsewhere, and mine it + bitcoind.generate_block(18) + sync_blockheight(bitcoind, [l2]) + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], funding_amount) + bitcoind.generate_block(1) + + l1.start() + sync_blockheight(bitcoind, [l1]) + + assert only_one(l1.rpc.listfunds()['channels'])['state'] == 'CHANNELD_BORKED' + + l1.restart() + # Wait for the sync to finish + sync_blockheight(bitcoind, [l1]) + + # Still in BORKED state + assert len(l1.rpc.listfunds()['channels']) == 1 + assert only_one(l1.rpc.listfunds()['channels'])['state'] == 'CHANNELD_BORKED' + + l1.stop() + bitcoind.generate_block(5) # Push the borking tx down to 6 + l1.start() + sync_blockheight(bitcoind, [l1]) + assert len(l1.rpc.listpeers()['peers']) == 0 + assert len(l1.rpc.listfunds()['channels']) == 0 + + # Test closing a channel that's not on-chain yet (but going to be borked?) # Test fundchannel_cancel'ing a channel that's not on-chain yet (but will be borked?) # - we shouldn't be able to cancel these, but we can 'bork' them by spending their input diff --git a/wallet/wallet.c b/wallet/wallet.c index 828f8747339f..1ce12e5a240e 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1610,7 +1610,7 @@ static bool wallet_channels_load_active(struct wallet *w) ", remote_upfront_shutdown_script" ", option_static_remotekey" ", shutdown_scriptpubkey_local" - " FROM channels WHERE state < ?;")); + " FROM channels WHERE state != ?;")); db_bind_int(stmt, 0, CLOSED); db_query_prepared(stmt); From d6367eef3e676b77159c0fe74fabb634caa627ed Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 16:33:47 -0600 Subject: [PATCH 093/131] test: add BORKED channel state to invoice channel selection test --- lightningd/test/run-invoice-select-inchan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index bc4203b474d8..75fcc750ddbf 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -676,6 +676,11 @@ int main(void) assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL); assert(any_offline == false); + /* 3a. inchan but its peer is borked -> NULL result */ + add_peer(ld, 0, CHANNELD_BORKED, true); + assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL); + assert(any_offline == false); + /* 4. connected peer but no corresponding inchan -> NULL result. */ add_peer(ld, 1, CHANNELD_NORMAL, true); assert(select_inchan(tmpctx, ld, AMOUNT_MSAT(0), inchans, deadends, &any_offline) == NULL); From 72c41631546c077493136631aae52017590c6c74 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 18:04:16 -0600 Subject: [PATCH 094/131] cancel: don't allow fundchannel_cancel for borked channels it's as good as canceled anyway --- lightningd/channel_control.c | 7 +++++++ tests/test_opening.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 334471c2ba26..13d21cf58989 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -781,6 +781,13 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, "Cannot cancel channel that was " "initiated by peer"); + if (channel_is_borked(cancel_channel)) + return command_fail(cmd, LIGHTNINGD, + "Channel is considered 'borked' and is uncloseable. " + "A 'borked' channel is one where a funding_tx input" + " has been spent in a different transaction, making" + " it unlikely that this channel will open."); + /* Check if we broadcast the transaction. (We store the transaction type into DB * before broadcast). */ enum wallet_tx_type type; diff --git a/tests/test_opening.py b/tests/test_opening.py index 07b937e31f07..e94cbd2122e9 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -326,6 +326,10 @@ def test_double_spends(node_factory, bitcoind): else: only_one(p['channels'])['state'] == 'CHANNELD_BORKED' + # Try to 'cancel' a BORKED channel + with pytest.raises(RpcError, match=r'Channel is considered \'borked\' and is uncloseable'): + l1.rpc.fundchannel_cancel(l2.info['id']) + # Check that the reserved funds have gone away! funds = l2.rpc.listfunds() assert len(funds['reserved_outputs']) == 0 From da1f20a0bd87f2484b104143a8be73d9d5fd27c3 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 13 Jan 2020 18:05:02 -0600 Subject: [PATCH 095/131] borked: add small check that borked channels are counted correctly Add an assertion around how borked channels are counted in totals for getinfo, so that we'll know if this changes. --- tests/test_opening.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_opening.py b/tests/test_opening.py index e94cbd2122e9..24b9e846e1f6 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -584,9 +584,12 @@ def test_borked_tx_reorg(node_factory, bitcoind): # Ok, one channel should be borked, the other channel should # be awaiting lockin, with a scid assert only_one(l1.rpc.listpeers()['peers'])['channels'][0]['state'] == 'CHANNELD_BORKED' + assert l1.rpc.getinfo()['num_inactive_channels'] == 1 + l3_channel = only_one(l3.rpc.listpeers()['peers'])['channels'][0] assert l3_channel['state'] == 'CHANNELD_AWAITING_LOCKIN' assert 'short_channel_id' not in l3_channel + assert l3.rpc.getinfo()['num_pending_channels'] == 1 # Stop l1 before the reorg l1.stop() From 52bf052ec637adcd959f17ffe8fc5cdf93103d6d Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 14 Jan 2020 15:31:26 -0600 Subject: [PATCH 096/131] borked: clean up active_channel lookups to account for borking Resolves some weirdness with connecting/disconnecting/closing or attempting to open a new channel with a peer that has a channel in 'borked' state. For now, we disallow opening a new channel while there's a channel hanging around as 'borked'. Borks get cleaned up after they've been buried 6 blocks, at which point a reopen is allowed. This prevents us from ending up in a state where there's somehow two channels between two peers. --- lightningd/channel.c | 12 ++++++++++++ lightningd/channel.h | 4 ++++ lightningd/connect_control.c | 3 ++- lightningd/opening_control.c | 21 +++++++++++---------- lightningd/peer_control.c | 26 ++++++++++++++++---------- tests/test_opening.py | 13 ++++++++----- tests/test_pay.py | 2 +- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index c5b2b6dc2307..b5fe812dd036 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -297,6 +297,18 @@ const char *channel_state_str(enum channel_state state) return "unknown"; } +struct channel *peer_active_or_borked_channel(struct peer *peer) +{ + struct channel *channel; + + list_for_each(&peer->channels, channel, list) { + if (channel_active(channel) + || channel_is_borked(channel)) + return channel; + } + return NULL; +} + struct channel *peer_active_channel(struct peer *peer) { struct channel *channel; diff --git a/lightningd/channel.h b/lightningd/channel.h index 2844a856a9ad..54deb1f9ddf1 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -217,6 +217,10 @@ void channel_set_state(struct channel *channel, /* Find a channel which is not onchain, if any */ struct channel *peer_active_channel(struct peer *peer); +/* Find a channel which is not onchain (or never will be on chain), + * if any */ +struct channel *peer_active_or_borked_channel(struct peer *peer); + /* Find a channel which is in state CHANNELD_NORMAL, if any */ struct channel *peer_normal_channel(struct peer *peer); diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 3229e3d29cc2..5451c2e5e48f 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -136,7 +136,8 @@ static struct command_result *json_connect(struct command *cmd, /* If we know about peer, see if it's already connected. */ peer = peer_by_id(cmd->ld, &id); if (peer) { - struct channel *channel = peer_active_channel(peer); + struct channel *channel = + peer_active_or_borked_channel(peer); if (peer->uncommitted_channel || (channel && channel->connected)) { diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 638e9b0acf02..a271045d670c 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -741,9 +741,10 @@ static void opening_opener_sigs_received(struct subd *openingd, const u8 *resp, per_peer_state_set_fds_arr(pps, fds); /* openingd should never accept their funding channel in this case. */ - if (peer_active_channel(uc->peer)) { + if (peer_active_or_borked_channel(uc->peer)) { log_broken(uc->log, "openingd accepted peer funding channel"); - uncommitted_channel_disconnect(uc, LOG_BROKEN, "already have active channel"); + uncommitted_channel_disconnect(uc, LOG_BROKEN, + "already have active or borked channel"); goto cleanup; } @@ -1042,10 +1043,10 @@ static void opening_fundee_finished(struct subd *openingd, per_peer_state_set_fds_arr(pps, fds); /* openingd should never accept them funding channel in this case. */ - if (peer_active_channel(uc->peer)) { - uncommitted_channel_disconnect(uc, - LOG_BROKEN, - "already have active channel"); + if (peer_active_or_borked_channel(uc->peer)) { + log_broken(uc->log, "openingd accepted peer funding channel"); + uncommitted_channel_disconnect(uc, LOG_BROKEN, + "already have active or borked channel"); goto failed; } @@ -1535,10 +1536,10 @@ static void opening_got_offer(struct subd *openingd, struct openchannel_hook_payload *payload; /* Tell them they can't open, if we already have open channel. */ - if (peer_active_channel(uc->peer)) { + if (peer_active_or_borked_channel(uc->peer)) { subd_send_msg(openingd, take(towire_opening_got_offer_reply(NULL, - "Already have active channel", NULL))); + "Already have active or borked channel", NULL))); return; } @@ -1780,7 +1781,7 @@ static struct command_result *json_fund_channel_complete(struct command *cmd, return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer"); } - channel = peer_active_channel(peer); + channel = peer_active_or_borked_channel(peer); if (channel) return command_fail(cmd, LIGHTNINGD, "Peer already %s", channel_state_name(channel)); @@ -1934,7 +1935,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer"); } - channel = peer_active_channel(peer); + channel = peer_active_or_borked_channel(peer); if (channel) { return command_fail(cmd, LIGHTNINGD, "Peer already %s", channel_state_name(channel)); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 49f5fbf421bb..b5cc6fd61db9 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1013,7 +1013,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, /* Can't be opening, since we wouldn't have sent peer_disconnected. */ assert(!peer->uncommitted_channel); - hook_payload->channel = peer_active_channel(peer); + hook_payload->channel = peer_active_or_borked_channel(peer); plugin_hook_call_peer_connected(ld, hook_payload); } @@ -1173,7 +1173,7 @@ static void json_add_peer(struct lightningd *ld, if (p->uncommitted_channel) connected = true; else { - channel = peer_active_channel(p); + channel = peer_active_or_borked_channel(p); connected = channel && channel->connected; } json_add_bool(response, "connected", connected); @@ -1255,7 +1255,7 @@ command_find_channel(struct command *cmd, if (json_tok_channel_id(buffer, tok, &cid)) { list_for_each(&ld->peers, peer, list) { - *channel = peer_active_channel(peer); + *channel = peer_active_or_borked_channel(peer); if (!*channel) continue; derive_channel_id(&channel_cid, @@ -1316,7 +1316,7 @@ static struct command_result *json_close(struct command *cmd, peer = peer_from_json(cmd->ld, buffer, idtok); if (peer) - channel = peer_active_channel(peer); + channel = peer_active_or_borked_channel(peer); else { struct command_result *res; res = command_find_channel(cmd, buffer, idtok, &channel); @@ -1336,6 +1336,10 @@ static struct command_result *json_close(struct command *cmd, "Peer has no active channel"); } + if (channel_is_borked(channel)) + return command_fail(cmd, LIGHTNINGD, + "Channel is BORKED, cannot be closed"); + /* If we've set a local shutdown script for this peer, and it's not the * default upfront script, try to close to a different channel. @@ -1583,11 +1587,12 @@ static struct command_result *json_disconnect(struct command *cmd, if (!peer) { return command_fail(cmd, LIGHTNINGD, "Peer not connected"); } - channel = peer_active_channel(peer); + channel = peer_active_or_borked_channel(peer); if (channel) { - if (*force) { + if (*force || channel_is_borked(channel)) { channel_fail_reconnect(channel, - "disconnect command force=true"); + "disconnect command %s", + force ? "force=true" : ""); return command_success(cmd, json_stream_success(cmd)); } return command_fail(cmd, LIGHTNINGD, "Peer is in state %s", @@ -1813,10 +1818,11 @@ static struct command_result *param_channel_or_all(struct command *cmd, /* Find channel by peer_id */ peer = peer_from_json(cmd->ld, buffer, tok); if (peer) { - *channel = peer_active_channel(peer); + *channel = peer_active_or_borked_channel(peer); if (!*channel) return command_fail(cmd, LIGHTNINGD, - "Could not find active channel of peer with that id"); + "Could not find active or borked " + "channel of peer with that id"); return NULL; /* Find channel by id or scid */ @@ -2020,7 +2026,7 @@ static struct command_result *json_dev_fail(struct command *cmd, "Could not find peer with that id"); } - channel = peer_active_channel(peer); + channel = peer_active_or_borked_channel(peer); if (!channel) { return command_fail(cmd, LIGHTNINGD, "Could not find active channel with peer"); diff --git a/tests/test_opening.py b/tests/test_opening.py index 24b9e846e1f6..58ce413da98a 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -251,8 +251,8 @@ def test_double_spends(node_factory, bitcoind): # channels associated with the double-spent utxo plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') - l1 = node_factory.get_node() - l2 = node_factory.get_node(options={'plugin': plugin_path}) + l1 = node_factory.get_node(may_reconnect=True) + l2 = node_factory.get_node(may_reconnect=True, options={'plugin': plugin_path}) l3 = node_factory.get_node() l1.fundwallet(200000000) @@ -330,6 +330,11 @@ def test_double_spends(node_factory, bitcoind): with pytest.raises(RpcError, match=r'Channel is considered \'borked\' and is uncloseable'): l1.rpc.fundchannel_cancel(l2.info['id']) + # Try disconnecting and then reconnecting the borked peers (l1 <-> l2) + l2.rpc.disconnect(l1.info['id']) + assert not only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'] + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + # Check that the reserved funds have gone away! funds = l2.rpc.listfunds() assert len(funds['reserved_outputs']) == 0 @@ -341,7 +346,7 @@ def test_double_spends(node_factory, bitcoind): assert only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['state'] == 'CHANNELD_BORKED' # Attempt to close borked channel, shouldn't work (not active) - with pytest.raises(RpcError, match=r'Peer has no active channel'): + with pytest.raises(RpcError, match=r'Channel is BORKED, cannot be closed'): l1.rpc.close(l2.info['id']) # Clean up prepped tx, otherwise we leak on quit @@ -544,8 +549,6 @@ def test_original_publishes(node_factory, bitcoind): def test_borked_tx_reorg(node_factory, bitcoind): """ We should be able to bork a transaction, then reorg and confirm it. We should also be able to confirm a tx, reorg and then bork it.""" - # Rescan to detect reorg at restart and may_reconnect so channeld - # will restart. Reorg can cause bad gossip msg. opts = {'funding-confirms': 6, 'rescan': 10} plugin_path = os.path.join(os.getcwd(), 'tests/plugins/funder.py') diff --git a/tests/test_pay.py b/tests/test_pay.py index fad831c1d8f0..47dff4bcba30 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -1940,7 +1940,7 @@ def channel_get_fees(scid): assert(db_fees[0]['feerate_ppm'] == 43) # check if invalid scid raises proper error - with pytest.raises(RpcError, match=r'-1.*Could not find active channel of peer with that id'): + with pytest.raises(RpcError, match=r'-1.*Could not find active or borked channel of peer with that id'): result = l1.rpc.setchannelfee(l3.info['id'], 42, 43) with pytest.raises(RpcError, match=r'-32602.*Given id is not a channel ID or short channel ID'): result = l1.rpc.setchannelfee('f42' + scid[3:], 42, 43) From 4c69ed76f02957dbe88f36fd4d1ed45518be7dd6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 14 Jan 2020 16:17:13 -0600 Subject: [PATCH 097/131] borked: update billboard to reflect the fact that channel is borked We were leaving the status in "AWAITING_LOCKIN" state; we should update the billboard so that we've got the right thing showing in the status when the channel is borked. --- lightningd/opening_control.c | 8 ++++++++ tests/test_opening.py | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a271045d670c..03018d74e95f 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -513,6 +513,14 @@ enum watch_result txo_spent(struct chain_topology *topo, /* Reset the txowatch object counter */ channel->txowatches = tal(channel, u8); + channel_set_billboard(channel, false, + tal_fmt(tmpctx, "Input %s:%u double spent in tx %s", + type_to_string(tmpctx, struct bitcoin_txid, + &input_txid), + input_outnum, + type_to_string(tmpctx, struct bitcoin_txid, + &txid))); + return WATCH_DELETED; } diff --git a/tests/test_opening.py b/tests/test_opening.py index 58ce413da98a..4ec0022ade33 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -6,6 +6,7 @@ import os import pytest +import re import unittest @@ -322,9 +323,12 @@ def test_double_spends(node_factory, bitcoind): assert len(peers) == 2 for p in peers: if p['id'] == l3.info['id']: - only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + assert only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' else: - only_one(p['channels'])['state'] == 'CHANNELD_BORKED' + c = only_one(p['channels']) + assert c['state'] == 'CHANNELD_BORKED' + r = re.compile('Input .*:.* double spent in tx .*') + assert any(r.search(line) for line in c['status']) # Try to 'cancel' a BORKED channel with pytest.raises(RpcError, match=r'Channel is considered \'borked\' and is uncloseable'): From 59cc57d6393684aa5d4257c1e0c081889c0b8f78 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 15 Jan 2020 19:40:56 -0600 Subject: [PATCH 098/131] tests: update upfront close to use the dual-funded pathway Not sure what the best way to gate/split tests is. --- tests/plugins/accepter_close_to.py | 30 +++++++++++++----- tests/plugins/funder.py | 6 ++-- tests/test_connection.py | 50 +++++++++++++----------------- 3 files changed, 48 insertions(+), 38 deletions(-) diff --git a/tests/plugins/accepter_close_to.py b/tests/plugins/accepter_close_to.py index 3711154d84f8..cd6266c8e029 100755 --- a/tests/plugins/accepter_close_to.py +++ b/tests/plugins/accepter_close_to.py @@ -14,22 +14,38 @@ plugin = Plugin() +def extract_opening_amount(openchannel): + key = 'opener_satoshis' if 'version' in openchannel and openchannel['version'] == 2 else 'funding_satoshis' + return Millisatoshi(openchannel[key]) + + @plugin.hook('openchannel') def on_openchannel(openchannel, plugin, **kwargs): + ret = {'result': 'continue'} + amt_msat = extract_opening_amount(openchannel) + amt = amt_msat.to_satoshi() + + if openchannel['version'] == 2: + # We match their funds. Always. + ret['funding_sats'] = amt_msat.to_satoshi_str() + # - a multiple of 11: we send back a valid address (regtest) - if Millisatoshi(openchannel['funding_satoshis']).to_satoshi() % 11 == 0: - return {'result': 'continue', 'close_to': 'bcrt1q7gtnxmlaly9vklvmfj06amfdef3rtnrdazdsvw'} + if amt % 11 == 0: + ret['close_to'] = 'bcrt1q7gtnxmlaly9vklvmfj06amfdef3rtnrdazdsvw' + return ret # - a multiple of 7: we send back an empty address - if Millisatoshi(openchannel['funding_satoshis']).to_satoshi() % 7 == 0: - return {'result': 'continue', 'close_to': ''} + if amt % 7 == 0: + ret['close_to'] = '' + return ret # - a multiple of 5: we send back an address for the wrong chain (mainnet) - if Millisatoshi(openchannel['funding_satoshis']).to_satoshi() % 5 == 0: - return {'result': 'continue', 'close_to': 'bc1qlq8srqnz64wgklmqvurv7qnr4rvtq2u96hhfg2'} + if amt % 5 == 0: + ret['close_to'] = 'bc1qlq8srqnz64wgklmqvurv7qnr4rvtq2u96hhfg2' + return ret # - otherwise: we don't include the close_to - return {'result': 'continue'} + return ret plugin.run() diff --git a/tests/plugins/funder.py b/tests/plugins/funder.py index 9aa54b88ae97..a86de5b6ef8f 100755 --- a/tests/plugins/funder.py +++ b/tests/plugins/funder.py @@ -15,16 +15,16 @@ @plugin.hook("openchannel") def on_openchannel(openchannel, plugin, **kwargs): - if openchannel['version'] == "1": + if openchannel['version'] == 1: raise ValueError("Not to be used with v1") their_funds = Millisatoshi(openchannel['opener_satoshis']) # We send back our maximum available funds if their_funds.to_satoshi() % 2 == 1: our_funds = Millisatoshi(openchannel['available_funds']) - return {'result': 'continue', 'funding_sats': our_funds} + return {'result': 'continue', 'funding_sats': our_funds.to_satoshi_str()} else: - return {'result': 'continue', 'funding_sats': their_funds} + return {'result': 'continue', 'funding_sats': their_funds.to_satoshi_str()} plugin.run() diff --git a/tests/test_connection.py b/tests/test_connection.py index 0c06a85b695e..cb05e9564365 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -6,7 +6,8 @@ from pyln.client import RpcError, Millisatoshi from utils import ( DEVELOPER, only_one, wait_for, sync_blockheight, VALGRIND, TIMEOUT, - SLOW_MACHINE, expected_peer_features, expected_node_features + SLOW_MACHINE, expected_peer_features, expected_node_features, + EXPERIMENTAL_FEATURES ) from bitcoin.core import CMutableTransaction, CMutableTxOut @@ -1043,12 +1044,16 @@ def test_funding_cancel_race(node_factory, bitcoind, executor): @unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.") +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Dual funding needs experimental") def test_funding_close_upfront(node_factory, bitcoind): l1 = node_factory.get_node() opts = {'plugin': os.path.join(os.getcwd(), 'tests/plugins/accepter_close_to.py')} l2 = node_factory.get_node(options=opts) + l1.fundwallet(100000000) + l2.fundwallet(100000000) + # The 'accepter_close_to' plugin uses the channel funding amount to determine # whether or not to include a 'close_to' address amt_normal = 100007 # continues without returning a close_to @@ -1061,44 +1066,31 @@ def _fundchannel(l1, l2, amount, close_to): assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id']) resp = l1.rpc.fundchannel_start(l2.info['id'], amount, close_to=close_to) - address = resp['funding_address'] + funding_addr = resp['funding_address'] if close_to: assert resp['close_to'] else: assert 'close_to' not in resp - peer = l1.rpc.listpeers()['peers'][0] - # Peer should still be connected and in state waiting for funding_txid - assert peer['id'] == l2.info['id'] - r = re.compile('Funding channel start: awaiting funding_txid with output to .*') - assert any(r.match(line) for line in peer['channels'][0]['status']) - assert 'OPENINGD' in peer['channels'][0]['state'] - - # 'Externally' fund the address from fundchannel_start - addr_scriptpubkey = bitcoind.rpc.getaddressinfo(address)['scriptPubKey'] - txout = CMutableTxOut(amount, bytearray.fromhex(addr_scriptpubkey)) - unfunded_tx = CMutableTransaction([], [txout]) - hextx = binascii.hexlify(unfunded_tx.serialize()).decode('utf8') - - funded_tx_obj = bitcoind.rpc.fundrawtransaction(hextx) - raw_funded_tx = funded_tx_obj['hex'] - txid = bitcoind.rpc.decoderawtransaction(raw_funded_tx)['txid'] - txout = 1 if funded_tx_obj['changepos'] == 0 else 0 + prep = l1.rpc.txprepare([{funding_addr: amount}], zero_out_change=True) + decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx']) + assert decode['txid'] == prep['txid'] - assert l1.rpc.fundchannel_complete(l2.info['id'], txid, txout)['commitments_secured'] - - # Broadcast the transaction manually and confirm that channel locks in - signed_tx = bitcoind.rpc.signrawtransactionwithwallet(raw_funded_tx)['hex'] - assert txid == bitcoind.rpc.decoderawtransaction(signed_tx)['txid'] + # One output will be correct. + if decode['vout'][0]['value'] == Decimal(str(amount / 10 ** 8)): + txout = 0 + elif decode['vout'][1]['value'] == Decimal(str(amount / 10 ** 8)): + txout = 1 + else: + assert False - bitcoind.rpc.sendrawtransaction(signed_tx) + txid = l1.rpc.fundchannel_complete(l2.info['id'], prep['txid'], txout)['txid'] + l1.rpc.txsend(txid) bitcoind.generate_block(1) for node in [l1, l2]: node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL') - channel = node.rpc.listpeers()['peers'][0]['channels'][-1] - assert amount * 1000 == channel['msatoshi_total'] # check that normal peer close works _fundchannel(l1, l2, amt_normal, None) @@ -1117,9 +1109,11 @@ def _fundchannel(l1, l2, amount, close_to): addr = bitcoind.rpc.getnewaddress() _fundchannel(l1, l2, amt_normal, addr) assert addr == only_one(l1.rpc.listpeers()['peers'])['channels'][2]['close_to_addr'] + l2_close_to_addr = l2.rpc.listpeers()['peers'][0]['channels'][-1]['close_to_addr'] resp = l1.rpc.close(l2.info['id'], destination=addr) assert resp['type'] == 'mutual' - assert only_one(only_one(bitcoind.rpc.decoderawtransaction(resp['tx'])['vout'])['scriptPubKey']['addresses']) == addr + for vout in bitcoind.rpc.decoderawtransaction(resp['tx'])['vout']: + assert only_one(vout['scriptPubKey']['addresses']) in [addr, l2_close_to_addr] # check that remote peer closing works as expected (and that remote's close_to works) _fundchannel(l1, l2, amt_addr, addr) From 536755af377bfd23f28631f3b3f2192f3c7dc74f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 24 Jan 2020 12:01:05 -0600 Subject: [PATCH 099/131] fixup funder test: use new namespace --- tests/plugins/funder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugins/funder.py b/tests/plugins/funder.py index a86de5b6ef8f..883cbc188034 100755 --- a/tests/plugins/funder.py +++ b/tests/plugins/funder.py @@ -8,7 +8,7 @@ they've requested. """ -from lightning import Plugin, Millisatoshi +from pyln.client import Plugin, Millisatoshi plugin = Plugin() From 9d059aa3432a76532b5495a5e2a551593a1f8922 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 3 Feb 2020 21:31:47 -0600 Subject: [PATCH 100/131] test-util: add EXPERIMENTAL_FEATURES variable No idea why this isn't included yet? --- contrib/pyln-testing/pyln/testing/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 92bde08c069b..47cf1f263a0f 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -70,6 +70,7 @@ def env(name, default=None): SLOW_MACHINE = env("SLOW_MACHINE", "0") == "1" DEPRECATED_APIS = env("DEPRECATED_APIS", "0") == "1" TIMEOUT = int(env("TIMEOUT", 180 if SLOW_MACHINE else 60)) +EXPERIMENTAL_FEATURES = env("EXPERIMENTAL_FEATURES") == "1" def wait_for(success, timeout=TIMEOUT): From b97ceca34695b63d6a50c4f1e630a52addfd1976 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 4 Feb 2020 15:42:22 -0600 Subject: [PATCH 101/131] fixup: wallet-df: save our_funds amount to channel record missed one, probably due to rebase --- lightningd/channel_control.c | 2 +- openingd/opening_wire.csv | 4 ++-- wallet/wallet.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 13d21cf58989..f57f302e1183 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -175,7 +175,7 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) if (!is_p2pkh(scriptpubkey, NULL) && !is_p2sh(scriptpubkey, NULL) && !is_p2wpkh(scriptpubkey, NULL) && !is_p2wsh(scriptpubkey, NULL)) { channel_fail_permanent(channel, "Bad shutdown scriptpubkey %s", - tal_hex(channel, scriptpubkey)); + tal_hex(tmpctx, scriptpubkey)); return; } diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index c378ded2c4a4..7e24856a01a9 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -49,7 +49,7 @@ msgdata,opening_got_offer,shutdown_scriptpubkey,u8,shutdown_len msgtype,opening_got_offer_reply,6105 msgdata,opening_got_offer_reply,rejection,?wirestring, msgdata,opening_got_offer_reply,shutdown_len,u16, -msgdata,opening_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len +msgdata,opening_got_offer_reply,our_shutdown_scriptpubkey,u8,shutdown_len # master->openingd: we'd like to fund this too, maybe msgtype,opening_got_offer_reply_fund,6107 @@ -59,7 +59,7 @@ msgdata,opening_got_offer_reply_fund,utxos,utxo,num_inputs msgdata,opening_got_offer_reply_fund,num_outputs,u16, msgdata,opening_got_offer_reply_fund,outputs,bitcoin_tx_output,num_outputs msgdata,opening_got_offer_reply_fund,shutdown_len,u16, -msgdata,opening_got_offer_reply_fund,our_shutdown_scriptpubkey,?u8,shutdown_len +msgdata,opening_got_offer_reply_fund,our_shutdown_scriptpubkey,u8,shutdown_len # Openingd->master: we've successfully offered channel. # This gives their sig, means we can broadcast tx: we're done. diff --git a/wallet/wallet.c b/wallet/wallet.c index 1ce12e5a240e..ad0648a3467a 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1415,7 +1415,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm ok &= wallet_shachain_load(w, db_column_u64(stmt, 28), &wshachain); remote_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 29, u8); - local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 46, u8); + local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 47, u8); /* Do we have a last_sent_commit, if yes, populate */ if (!db_column_is_null(stmt, 42)) { From 904c0d2ea4f6f9a6f4984506b242530597b11da5 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 4 Feb 2020 17:06:32 -0600 Subject: [PATCH 102/131] tests: fixup disconnects failure reusing the commitment_signed message in channel open threw off the disconnects pattern expected in the htlc failure test --- tests/test_closing.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_closing.py b/tests/test_closing.py index 5557b42e41fe..52778518c7c5 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -504,10 +504,12 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): """Test penalty transaction with an incoming HTLC""" # We suppress each one after first commit; HTLC gets added not fulfilled. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], - may_fail=True, feerates=(7500, 7500, 7500, 7500), + disconnects = ['=WIRE_COMMITMENT_SIGNED', '=WIRE_COMMITMENT_SIGNED-nocommit'] + l1 = node_factory.get_node(disconnect=disconnects, + may_fail=True, + feerates=(7500, 7500, 7500, 7500), allow_broken_log=True) - l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit']) + l2 = node_factory.get_node(disconnect=disconnects) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fund_channel(l2, 10**6) From b7941135f4cbff19408e2f8894f942bc5099ec9e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 4 Feb 2020 21:45:26 -0600 Subject: [PATCH 103/131] tests: update openchannel hook test to be aware of v2 format the v2 of the openchannel hook callback has a different format than the v1; this patch updates the test to check for either format, plus adjusts the plugin to use the appropriate key, depending on version --- tests/plugins/reject_odd_funding_amounts.py | 7 ++++++- tests/test_plugin.py | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/plugins/reject_odd_funding_amounts.py b/tests/plugins/reject_odd_funding_amounts.py index eb3460f91ec2..721bcce0bc60 100755 --- a/tests/plugins/reject_odd_funding_amounts.py +++ b/tests/plugins/reject_odd_funding_amounts.py @@ -15,7 +15,12 @@ def on_openchannel(openchannel, plugin, **kwargs): for k in sorted(openchannel.keys()): print("{}={}".format(k, openchannel[k])) - if Millisatoshi(openchannel['funding_satoshis']).to_satoshi() % 2 == 1: + if 'version' in openchannel and openchannel['version'] == 2: + key = 'opener_satoshis' + else: + key = 'funding_satoshis' + + if Millisatoshi(openchannel[key]).to_satoshi() % 2 == 1: return {'result': 'reject', 'error_message': "I don't like odd amounts"} return {'result': 'continue'} diff --git a/tests/test_plugin.py b/tests/test_plugin.py index cbf324cac448..0160fba86933 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -496,12 +496,9 @@ def test_openchannel_hook(node_factory, bitcoind): l1.rpc.fundchannel(l2.info['id'], 100000) # Make sure plugin got all the vars we expect - l2.daemon.wait_for_log('reject_odd_funding_amounts.py: 11 VARS') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: channel_flags=1') - l2.daemon.wait_for_log('reject_odd_funding_amounts.py: channel_reserve_satoshis=1000000msat') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: dust_limit_satoshis=546000msat') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: feerate_per_kw=7500') - l2.daemon.wait_for_log('reject_odd_funding_amounts.py: funding_satoshis=100000000msat') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: htlc_minimum_msat=0msat') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: id={}'.format(l1.info['id'])) l2.daemon.wait_for_log('reject_odd_funding_amounts.py: max_accepted_htlcs=483') @@ -509,6 +506,20 @@ def test_openchannel_hook(node_factory, bitcoind): l2.daemon.wait_for_log('reject_odd_funding_amounts.py: push_msat=0msat') l2.daemon.wait_for_log('reject_odd_funding_amounts.py: to_self_delay=5') + if l2.daemon.is_in_log('reject_odd_funding_amounts.py: 12 VARS'): + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: channel_reserve_satoshis=1000000msat') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: funding_satoshis=100000000msat') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: version=1') + # For V2 !! + elif l2.daemon.is_in_log('reject_odd_funding_amounts.py: 14 VARS'): + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: available_funds=0msat') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: channel_reserve_satoshis=0msat') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: feerate_per_kw_funding=7500') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: opener_satoshis=100000000msat') + assert l2.daemon.is_in_log('reject_odd_funding_amounts.py: version=2') + else: + raise Exception("VAR count incorrect/not found") + # Close it. txid = l1.rpc.close(l2.info['id'])['txid'] bitcoind.generate_block(1, txid) From d3351ab1016db2b8680caaeef9da8a6aa313dc14 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 14:03:15 -0600 Subject: [PATCH 104/131] tests: more dev_disconnect updates WIRE_COMMITMENT_SIGNED reuse --- tests/test_connection.py | 14 ++++++++------ tests/test_misc.py | 2 +- tests/test_pay.py | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_connection.py b/tests/test_connection.py index cb05e9564365..7a8f49424dbc 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -518,7 +518,8 @@ def test_reconnect_sender_add1(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_reconnect_sender_add(node_factory): - disconnects = ['-WIRE_COMMITMENT_SIGNED', + disconnects = ['=WIRE_COMMITMENT_SIGNED', + '-WIRE_COMMITMENT_SIGNED', '@WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK', @@ -542,13 +543,14 @@ def test_reconnect_sender_add(node_factory): # This will send commit, so will reconnect as required. l1.rpc.sendpay(route, rhash) # Should have printed this for every reconnect. - for i in range(0, len(disconnects)): + for i in range(0, len(disconnects) - 1): l1.daemon.wait_for_log('Already have funding locked in') @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_reconnect_receiver_add(node_factory): - disconnects = ['-WIRE_COMMITMENT_SIGNED', + disconnects = ['=WIRE_COMMITMENT_SIGNED', + '-WIRE_COMMITMENT_SIGNED', '@WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK', @@ -568,7 +570,7 @@ def test_reconnect_receiver_add(node_factory): route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1x1x1'}] l1.rpc.sendpay(route, rhash) - for i in range(len(disconnects)): + for i in range(len(disconnects) - 1): l1.daemon.wait_for_log('Already have funding locked in') assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid' @@ -1451,7 +1453,7 @@ def test_fee_limits(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_update_fee_reconnect(node_factory, bitcoind): # Disconnect after commitsig for fee update. - disconnects = ['+WIRE_COMMITMENT_SIGNED*3'] + disconnects = ['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED*2'] # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True, feerates=(15000, 15000, 15000, 3750)) @@ -1760,7 +1762,7 @@ def test_no_fee_estimate(node_factory, bitcoind, executor): @unittest.skipIf(not DEVELOPER, "needs --dev-disconnect") def test_funder_feerate_reconnect(node_factory, bitcoind): # l1 updates fees, then reconnect so l2 retransmits commitment_signed. - disconnects = ['-WIRE_COMMITMENT_SIGNED*3'] + disconnects = ['=WIRE_COMMITMENT_SIGNED', '-WIRE_COMMITMENT_SIGNED*3'] l1 = node_factory.get_node(may_reconnect=True, feerates=(7500, 7500, 7500, 7500)) l2 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) diff --git a/tests/test_misc.py b/tests/test_misc.py index a07ae5c21b3b..ee2a2d5ad2fa 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -279,7 +279,7 @@ def test_htlc_sig_persistence(node_factory, bitcoind, executor): # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(options={'dev-no-reconnect': None}, feerates=(7500, 7500, 7500, 7500)) - l2 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED']) + l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED']) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fund_channel(l2, 10**6) diff --git a/tests/test_pay.py b/tests/test_pay.py index 47dff4bcba30..87d15165d343 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -331,7 +331,7 @@ def test_pay_optional_args(node_factory): def test_payment_success_persistence(node_factory, bitcoind, executor): # Start two nodes and open a channel.. die during payment. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED'], + l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED'], options={'dev-no-reconnect': None}, may_reconnect=True, feerates=(7500, 7500, 7500, 7500)) @@ -376,7 +376,7 @@ def test_payment_success_persistence(node_factory, bitcoind, executor): def test_payment_failed_persistence(node_factory, executor): # Start two nodes and open a channel.. die during payment. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED'], + l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED'], options={'dev-no-reconnect': None}, may_reconnect=True, feerates=(7500, 7500, 7500, 7500)) From fa2e6c47b135201f0e9a2de6e7cc89f9c5b1738f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 14:10:06 -0600 Subject: [PATCH 105/131] fixup tests: update version to include dual-funding number dual funding is currently 19 --- tests/utils.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index 814f05ded8d0..d3bba7d2fb31 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,17 +4,26 @@ EXPERIMENTAL_FEATURES = env("EXPERIMENTAL_FEATURES", "0") == "1" COMPAT = env("COMPAT", "1") == "1" +# features 1, 3, 7, 9, 11, 13, 15 and 17 (0x02aaa2). +BASE_FEATURES = "02aaa2" +# dual funding is currently 19; will update in the future +# features 1, 3, 7, 9, 11, 13, 15, 17, 19 (0x0aaaa2). +BASE_PLUS_DF = "0aaaa2" def expected_peer_features(): """Return the expected peer features hexstring for this configuration""" - # features 1, 3, 7, 9, 11, 13, 15 and 17 (0x02aaa2). - return "02aaa2" + if not EXPERIMENTAL_FEATURES: + return BASE_FEATURES + + return BASE_PLUS_DF # With the addition of the keysend plugin, we now send a different set of # features for the 'node' and the 'peer' feature sets def expected_node_features(): """Return the expected node features hexstring for this configuration""" - # features 1, 3, 7, 9, 11, 13, 15, 17 and 55 (0x8000000002aaa2). - return "8000000002aaa2" + if not EXPERIMENTAL_FEATURES: + return "80000000" + BASE_FEATURES + + return "80000000" + BASE_PLUS_DF From 03cd27f22eadb0c502a2dd02f69e9d01dc32a089 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 14:30:26 -0600 Subject: [PATCH 106/131] tests: switch out disconnect message depending on version? --- tests/test_connection.py | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/tests/test_connection.py b/tests/test_connection.py index 7a8f49424dbc..968346739a94 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -249,12 +249,21 @@ def test_disconnect(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_disconnect_funder(node_factory): - # Now error on funder side duringchannel open. - disconnects = ['-WIRE_OPEN_CHANNEL', - '@WIRE_OPEN_CHANNEL', - '+WIRE_OPEN_CHANNEL', - '-WIRE_FUNDING_CREATED', - '@WIRE_FUNDING_CREATED'] + if EXPERIMENTAL_FEATURES: + openchannel_key = 'WIRE_OPEN_CHANNEL2' + # for v2, we replace 'funding created' with + # 'commitment signed' + funding_created = 'WIRE_COMMITMENT_SIGNED' + else: + openchannel_key = 'WIRE_OPEN_CHANNEL' + funding_created = 'WIRE_FUNDING_CREATED' + + # Now error on funder side during channel open. + disconnects = ['-' + openchannel_key, + '@' + openchannel_key, + '+' + openchannel_key, + '-' + funding_created, + '@' + funding_created] l1 = node_factory.get_node(disconnect=disconnects) l2 = node_factory.get_node() @@ -277,10 +286,15 @@ def test_disconnect_funder(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_disconnect_fundee(node_factory): + if EXPERIMENTAL_FEATURES: + acceptchannel_key = 'WIRE_ACCEPT_CHANNEL2' + else: + acceptchannel_key = 'WIRE_ACCEPT_CHANNEL' + # Now error on fundee side during channel open. - disconnects = ['-WIRE_ACCEPT_CHANNEL', - '@WIRE_ACCEPT_CHANNEL', - '+WIRE_ACCEPT_CHANNEL'] + disconnects = ['-' + acceptchannel_key, + '@' + acceptchannel_key, + '+' + acceptchannel_key] l1 = node_factory.get_node() l2 = node_factory.get_node(disconnect=disconnects) @@ -305,7 +319,12 @@ def test_disconnect_fundee(node_factory): def test_disconnect_half_signed(node_factory): # Now, these are the corner cases. Fundee sends funding_signed, # but funder doesn't receive it. - disconnects = ['@WIRE_FUNDING_SIGNED'] + if EXPERIMENTAL_FEATURES: + funding_signedkey = 'WIRE_FUNDING_SIGNED2' + else: + funding_signedkey = 'WIRE_FUNDING_SIGNED' + + disconnects = ['@' + funding_signedkey] l1 = node_factory.get_node() l2 = node_factory.get_node(disconnect=disconnects) @@ -322,8 +341,13 @@ def test_disconnect_half_signed(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_reconnect_signed(node_factory): + if EXPERIMENTAL_FEATURES: + funding_signedkey = 'WIRE_FUNDING_SIGNED2' + else: + funding_signedkey = 'WIRE_FUNDING_SIGNED' + # This will fail *after* both sides consider channel opening. - disconnects = ['+WIRE_FUNDING_SIGNED'] + disconnects = ['+' + funding_signedkey] l1 = node_factory.get_node(may_reconnect=True) l2 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) @@ -349,8 +373,13 @@ def test_reconnect_signed(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_reconnect_openingd(node_factory): + if EXPERIMENTAL_FEATURES: + acceptchannel_key = 'WIRE_ACCEPT_CHANNEL2' + else: + acceptchannel_key = 'WIRE_ACCEPT_CHANNEL' + # Openingd thinks we're still opening; funder reconnects.. - disconnects = ['0WIRE_ACCEPT_CHANNEL'] + disconnects = ['0' + acceptchannel_key] l1 = node_factory.get_node(may_reconnect=True) l2 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) @@ -2053,8 +2082,13 @@ def test_restart_many_payments(node_factory, bitcoind): def test_fail_unconfirmed(node_factory, bitcoind, executor): """Test that if we crash with an unconfirmed connection to a known peer, we don't have a dangling peer in db""" + if EXPERIMENTAL_FEATURES: + openchannel_key = 'WIRE_OPEN_CHANNEL2' + else: + openchannel_key = 'WIRE_OPEN_CHANNEL' + # = is a NOOP disconnect, but sets up file. - l1 = node_factory.get_node(disconnect=['=WIRE_OPEN_CHANNEL']) + l1 = node_factory.get_node(disconnect=['=' + openchannel_key]) l2 = node_factory.get_node() # First one, we close by mutual agreement. @@ -2070,7 +2104,7 @@ def test_fail_unconfirmed(node_factory, bitcoind, executor): l1.stop() # Mangle disconnect file so this time it blackholes.... with open(l1.daemon.disconnect_file, "w") as f: - f.write("0WIRE_OPEN_CHANNEL\n") + f.write('0' + openchannel_key + '\n') l1.start() # Now we establish a new channel, which gets stuck. From 4849fcd50177ce0f2274e31b84f28d1815d4a90f Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 15:16:53 -0600 Subject: [PATCH 107/131] test: connect before funding in fundchannel --- contrib/pyln-testing/pyln/testing/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 47cf1f263a0f..e62e5d4b611c 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -714,6 +714,8 @@ def fund_channel(self, l2, amount, wait_for_active=True, announce_channel=True): # Now go ahead and open a channel num_tx = len(self.bitcoin.rpc.getrawmempool()) + + self.rpc.connect(l2.info['id'], 'localhost', l2.port) tx = self.rpc.fundchannel(l2.info['id'], amount, announce=announce_channel)['tx'] wait_for(lambda: len(self.bitcoin.rpc.getrawmempool()) == num_tx + 1) From be9a3ae800c3252cbe13ad2f58f7ff93d11aceb6 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 15:39:55 -0600 Subject: [PATCH 108/131] tests: abort fundchannel_start tests if v2 is being used v2 opens don't currently support external funding --- tests/test_connection.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/test_connection.py b/tests/test_connection.py index 968346739a94..9cac2d3f7fff 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -939,7 +939,12 @@ def test_funding_external_wallet_corners(node_factory, bitcoind): with pytest.raises(RpcError, match=r'Amount exceeded 16777215'): l1.rpc.fundchannel_start(l2.info['id'], amount + 1) - l1.rpc.fundchannel_start(l2.info['id'], amount) + resp = l1.rpc.fundchannel_start(l2.info['id'], amount) + + # FIXME: allow for v2 channel opens to support externally funded + if int(resp['open_channel_version']) == 2: + return + with pytest.raises(RpcError, match=r'Already funding channel'): l1.rpc.fundchannel(l2.info['id'], amount) @@ -1097,6 +1102,11 @@ def _fundchannel(l1, l2, amount, close_to): assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id']) resp = l1.rpc.fundchannel_start(l2.info['id'], amount, close_to=close_to) + + # FIXME: external wallet opens currently disabled for v2 + if resp['open_channel_version'] == 2: + return False + funding_addr = resp['funding_address'] if close_to: @@ -1122,9 +1132,13 @@ def _fundchannel(l1, l2, amount, close_to): for node in [l1, l2]: node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL') + return True + + # FIXME: allow for externally funded channels on v2 of the protocol + if not _fundchannel(l1, l2, amt_normal, None): + return # check that normal peer close works - _fundchannel(l1, l2, amt_normal, None) assert l1.rpc.close(l2.info['id'])['type'] == 'mutual' # check that you can provide a closing address upfront @@ -1176,7 +1190,13 @@ def test_funding_external_wallet(node_factory, bitcoind): assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id']) amount = 2**24 - 1 - address = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address'] + started = l1.rpc.fundchannel_start(l2.info['id'], amount) + + # FIXME: external wallet opens currently disabled for v2 + if started['open_channel_version'] == 2: + return + + address = started['funding_address'] assert len(address) > 0 peer = l1.rpc.listpeers()['peers'][0] From 6b929b807bf6d828c7196553a19e452a7e6783ba Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 16:58:06 -0600 Subject: [PATCH 109/131] openingd: negotiation_failed should return/abort A slight misunderstanding in how negotiation_failed handles control flow; now we return from failures, and clean up state before we go in the funder case. --- openingd/openingd.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 6c4210b8b7cb..b7e41aa354a4 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1408,7 +1408,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, return NULL; input_count = tal_count(local_ins) + tal_count(remote_ins); - const void *map[input_count]; + void **map = tal_arr(state, void *, input_count); for (i = 0; i < input_count; i++) map[i] = int2ptr(i); @@ -1473,9 +1473,11 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->first_per_commitment_point[REMOTE], REMOTE, &err_reason); - if (!remote_commit) + if (!remote_commit) { negotiation_failed(state, true, "Could not meet fees and reserve: %s", err_reason); + goto fail_1; + } msg = towire_hsm_sign_remote_commitment_tx(NULL, remote_commit, @@ -1532,9 +1534,12 @@ static u8 *funder_finalize_channel_setup2(struct state *state, local_commit = initial_channel_tx(state, &wscript, state->channel, &state->first_per_commitment_point[LOCAL], LOCAL, &err_reason); - if (!local_commit) + if (!local_commit) { negotiation_failed(state, false, "Did not meet fees and reserve: %s", err_reason); + goto fail_2; + } + /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 @@ -1564,6 +1569,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, else input_amts[i] = AMOUNT_SAT(0); } + map = tal_free(map); /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 @@ -1622,9 +1628,21 @@ static u8 *funder_finalize_channel_setup2(struct state *state, state->feerate_per_kw_funding, state->localconf.channel_reserve, state->upfront_shutdown_script[REMOTE]); -#else - return NULL; + + +fail_2: + tal_free(remote_commit); +fail_1: + tal_free(funding_tx); + tal_free(wscript); + tal_free(map); + tal_free(local_ins); + tal_free(local_outs); + tal_free(remote_ins); + tal_free(remote_outs); #endif /* EXPERIMENTAL_FEATURES */ + + return NULL; } static bool funder_finalize_channel_setup(struct state *state, @@ -2289,6 +2307,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) if (!remote_commit) { negotiation_failed(state, true, "Could not meet their fees and reserve: %s", err_reason); + return NULL; } msg = towire_hsm_sign_remote_commitment_tx(NULL, From 92b8faef6d6c4dc959ec8746c5af8c5a85d9ee95 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 17:14:35 -0600 Subject: [PATCH 110/131] tests: mark cancel race test as skipped if using v2 Needs to be updated/re-enabled when we support external wallet funding for v2 opens --- tests/test_connection.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index 9cac2d3f7fff..e9dbfe0840ea 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1029,6 +1029,15 @@ def test_funding_cancel_race(node_factory, bitcoind, executor): num_complete = 0 num_cancel = 0 + # This test doesn't work for v2, so make sure we're not on v2 + l1.rpc.connect(nodes[0].info['id'], 'localhost', nodes[0].port) + result = l1.rpc.fundchannel_start(nodes[0].info['id'], "100000sat") + if result['open_channel_version'] == 2: + # FIXME: let v2 of fundchannel_start handle external wallet funds + pytest.skip('running as v2, external wallet funding not permitted') + else: + l1.rpc.fundchannel_cancel(nodes[0].info['id']) + for count, n in enumerate(nodes): l1.rpc.connect(n.info['id'], 'localhost', n.port) l1.rpc.fundchannel_start(n.info['id'], "100000sat") From af7d91881fc5f72dc0b64a7b0624777b5861f73e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 5 Feb 2020 17:15:29 -0600 Subject: [PATCH 111/131] tests: move all v2 'disabled' tests due to no extrnal v2 to 'skipped' Previously we had effectively skipped tests without marking them as such; now we mark them as such to make it more obvious what's going on --- tests/test_connection.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_connection.py b/tests/test_connection.py index e9dbfe0840ea..f4e552a1823f 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -943,7 +943,7 @@ def test_funding_external_wallet_corners(node_factory, bitcoind): # FIXME: allow for v2 channel opens to support externally funded if int(resp['open_channel_version']) == 2: - return + pytest.skip('running as v2, external wallet funding not permitted') with pytest.raises(RpcError, match=r'Already funding channel'): l1.rpc.fundchannel(l2.info['id'], amount) @@ -1114,7 +1114,7 @@ def _fundchannel(l1, l2, amount, close_to): # FIXME: external wallet opens currently disabled for v2 if resp['open_channel_version'] == 2: - return False + pytest.skip('running as v2, external wallet funding not permitted') funding_addr = resp['funding_address'] @@ -1141,13 +1141,9 @@ def _fundchannel(l1, l2, amount, close_to): for node in [l1, l2]: node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL') - return True - - # FIXME: allow for externally funded channels on v2 of the protocol - if not _fundchannel(l1, l2, amt_normal, None): - return # check that normal peer close works + _fundchannel(l1, l2, amt_normal, None) assert l1.rpc.close(l2.info['id'])['type'] == 'mutual' # check that you can provide a closing address upfront From fefd295dae57ff42f6918fd0bd115183483aed57 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Tue, 11 Feb 2020 17:55:55 -0600 Subject: [PATCH 112/131] fixup: utxo initiation missing new fields --- common/test/run-funding_tx.c | 6 ++++++ common/test/run-funding_tx_dual.c | 6 ++++++ common/utxo.c | 18 ++++++++++++++++++ lightningd/onchain_control.c | 7 ++++++- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 247ddffbec31..4c131cd5aaba 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -46,6 +46,9 @@ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u64 */ u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8 */ +u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } @@ -73,6 +76,9 @@ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) /* Generated stub for towire_u64 */ void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) { fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } /* Generated stub for towire_u8_array */ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "towire_u8_array called!\n"); abort(); } diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index cdb35fc65742..22b67df77460 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -46,6 +46,9 @@ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u64 */ u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8 */ +u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } @@ -73,6 +76,9 @@ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) /* Generated stub for towire_u64 */ void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) { fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } /* Generated stub for towire_u8_array */ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "towire_u8_array called!\n"); abort(); } diff --git a/common/utxo.c b/common/utxo.c index dd3b4b4a539a..ae61f8e254f9 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -10,6 +10,8 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) /* Is this a unilateral close output and needs the * close_info? */ bool is_unilateral_close = utxo->close_info != NULL; + bool is_reserved = utxo->reserved_at != NULL; + towire_bitcoin_txid(pptr, &utxo->txid); towire_u32(pptr, utxo->outnum); towire_amount_sat(pptr, utxo->amount); @@ -29,6 +31,13 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) if (utxo->close_info->commitment_point) towire_pubkey(pptr, utxo->close_info->commitment_point); } + + towire_bool(pptr, is_reserved); + if (is_reserved) { + towire_u32(pptr, *utxo->reserved_at); + towire_u32(pptr, *utxo->reserved_for); + } + towire_u8(pptr, utxo->spend_priority); } struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) @@ -66,6 +75,15 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) utxo->close_info = NULL; } + if (fromwire_bool(ptr, max)) { + const u32 reserved_at = fromwire_u32(ptr, max), + reserved_for = fromwire_u32(ptr, max); + + utxo->reserved_at = &reserved_at; + utxo->reserved_for = &reserved_for; + } + utxo->spend_priority = fromwire_u8(ptr, max); + return utxo; } diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index 84115df98425..f38756c9b25c 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -296,13 +296,18 @@ static void onchain_add_utxo(struct channel *channel, const u8 *msg) u->close_info->channel_id = channel->dbid; u->close_info->peer_id = channel->peer->id; u->spendheight = NULL; + u->reserved_at = NULL; + u->reserved_for = NULL; + u->scriptPubkey = NULL; + u->scriptSig = NULL; + u->spend_priority = spend_normal; if (!fromwire_onchain_add_utxo( u, msg, &u->txid, &u->outnum, &u->close_info->commitment_point, &u->amount, &blockheight, &u->scriptPubkey)) { fatal("onchaind gave invalid add_utxo message: %s", tal_hex(msg, msg)); } - u->blockheight = blockheight>0?&blockheight:NULL; + u->blockheight = blockheight > 0 ? &blockheight : NULL; outpointfilter_add(channel->peer->ld->wallet->owned_outpoints, &u->txid, u->outnum); wallet_add_utxo(channel->peer->ld->wallet, u, p2wpkh); From 565e7d6c4f5b30f566a83eaa6f56d384fd95df00 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 12 Feb 2020 13:33:47 -0600 Subject: [PATCH 113/131] test-patch: switch on disconnects depending on EXP_FEATURES We don't have a way to introspect if a node will be using v2 before the node has been created, so for now we use the 'crude' "are EXPERIMENTAL_FEATURES turned on" switch to decide what messages to add to the disconnects. --- tests/test_closing.py | 5 +++-- tests/test_connection.py | 7 +++++-- tests/test_pay.py | 7 ++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/test_closing.py b/tests/test_closing.py index 52778518c7c5..3e2b56f34bfd 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -3,7 +3,7 @@ from pyln.client import RpcError from utils import ( only_one, sync_blockheight, wait_for, DEVELOPER, TIMEOUT, VALGRIND, - SLOW_MACHINE + SLOW_MACHINE, EXPERIMENTAL_FEATURES ) import os @@ -504,7 +504,8 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): """Test penalty transaction with an incoming HTLC""" # We suppress each one after first commit; HTLC gets added not fulfilled. # Feerates identical so we don't get gratuitous commit to update them - disconnects = ['=WIRE_COMMITMENT_SIGNED', '=WIRE_COMMITMENT_SIGNED-nocommit'] + disconnects = ['=WIRE_COMMITMENT_SIGNED-nocommit'] + l1 = node_factory.get_node(disconnect=disconnects, may_fail=True, feerates=(7500, 7500, 7500, 7500), diff --git a/tests/test_connection.py b/tests/test_connection.py index f4e552a1823f..68ac78a35130 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1506,8 +1506,11 @@ def test_fee_limits(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_update_fee_reconnect(node_factory, bitcoind): - # Disconnect after commitsig for fee update. - disconnects = ['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED*2'] + # Disconnect after first commitsig. + # FIXME: use something else to switch on for v2 enabled + disconnects = ['+WIRE_COMMITMENT_SIGNED*3'] + if EXPERIMENTAL_FEATURES: + disconnects = ['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED*2'] # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True, feerates=(15000, 15000, 15000, 3750)) diff --git a/tests/test_pay.py b/tests/test_pay.py index 87d15165d343..91fcf625fb92 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -376,7 +376,12 @@ def test_payment_success_persistence(node_factory, bitcoind, executor): def test_payment_failed_persistence(node_factory, executor): # Start two nodes and open a channel.. die during payment. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED'], + + # FIXME: use something else to switch on v2 enablement + disconnects = ['+WIRE_COMMITMENT_SIGNED'] + if EXPERIMENTAL_FEATURES: + disconnects = ['=WIRE_COMMITMENT_SIGNED'] + disconnects + l1 = node_factory.get_node(disconnect=disconnects, options={'dev-no-reconnect': None}, may_reconnect=True, feerates=(7500, 7500, 7500, 7500)) From 0a791a85c07de29805f91fa214ca2d9973bc6351 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Thu, 20 Feb 2020 18:28:29 -0600 Subject: [PATCH 114/131] df: update to 'interactive tx construction' draft protocols Change up how the 'inputs/outputs' are exchanged, removes ack_rbf and adds a new gossip message `blacklist_podle` for gossiping podle commitments. Using sha 3f9f65d3ad5a21835994f9d9226ed9e0e4066662, but this will likely change, not be stable in the final --- channeld/Makefile | 1 + channeld/channeld.c | 14 +- closingd/Makefile | 1 + common/funding_tx.c | 50 ++ common/funding_tx.h | 21 + connectd/Makefile | 2 + gossipd/Makefile | 2 + gossipd/gossipd.c | 16 +- hsmd/hsm_wire.csv | 2 +- hsmd/hsmd.c | 4 - lightningd/opening_control.c | 10 +- onchaind/Makefile | 1 + openingd/opening_wire.csv | 1 + openingd/openingd.c | 283 +++++---- tools/generate-wire.py | 1 + ...l_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 | 99 --- wire/peer_wire.c | 26 +- wire/test/run-peer-wire.c | 595 ++++++++++-------- 18 files changed, 629 insertions(+), 500 deletions(-) delete mode 100644 wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 diff --git a/channeld/Makefile b/channeld/Makefile index 2db94cd1cd53..fd2d1e0a6ed1 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -49,6 +49,7 @@ CHANNELD_COMMON_OBJS := \ common/ecdh_hsmd.o \ common/features.o \ common/fee_states.o \ + common/funding_tx.o \ common/gen_status_wire.o \ common/gen_peer_status_wire.o \ common/gossip_rcvd_filter.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index 7142ee839a3b..9d2e69e2d977 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1968,14 +1968,15 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_CHANNEL_REESTABLISH: case WIRE_CLOSING_SIGNED: #if EXPERIMENTAL_FEATURES + case WIRE_TX_ADD_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_ADD_INPUT: - case WIRE_FUNDING_ADD_OUTPUT: - case WIRE_FUNDING_ADD_COMPLETE: - case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: - case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ break; @@ -1991,6 +1992,9 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_PING: case WIRE_PONG: case WIRE_ERROR: +#if EXPERIMENTAL_FEATURES + case WIRE_BLACKLIST_PODLE: +#endif /* EXPERIMENTAL_FEATURES */ abort(); } diff --git a/closingd/Makefile b/closingd/Makefile index 7b3877c7f620..b401d7bfb43a 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -54,6 +54,7 @@ CLOSINGD_COMMON_OBJS := \ common/daemon_conn.o \ common/dev_disconnect.o \ common/derive_basepoints.o \ + common/funding_tx.o \ common/gen_peer_status_wire.o \ common/gen_status_wire.o \ common/gossip_rcvd_filter.o \ diff --git a/common/funding_tx.c b/common/funding_tx.c index 0e37c0154305..219beb6733dc 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -416,3 +416,53 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, return tx; } #endif /* EXPERIMENTAL_FEATURES */ + +void towire_input_info(u8 **pptr, const struct input_info *input_info) +{ + towire_u16(pptr, input_info->serial_id); + towire_amount_sat(pptr, input_info->sats); + towire_bitcoin_txid(pptr, &input_info->prevtx_txid); + towire_u32(pptr, input_info->prevtx_vout); + towire_u16(pptr, tal_count(input_info->prevtx_scriptpubkey)); + towire_u8_array(pptr, input_info->prevtx_scriptpubkey, + tal_count(input_info->prevtx_scriptpubkey)); + towire_u16(pptr, input_info->max_witness_len); + towire_u16(pptr, tal_count(input_info->script)); + towire_u8_array(pptr, input_info->script, tal_count(input_info->script)); +} +struct input_info *fromwire_input_info(const tal_t *ctx, const u8 **ptr, size_t *max) +{ + struct input_info *input = tal(ctx, struct input_info); + u16 prevtx_scriptlen; + u16 script_len; + + input->serial_id = fromwire_u16(ptr, max); + input->sats = fromwire_amount_sat(ptr, max); + fromwire_bitcoin_txid(ptr, max, &input->prevtx_txid); + input->prevtx_vout = fromwire_u32(ptr, max); + prevtx_scriptlen = fromwire_u16(ptr, max); + fromwire_u8_array(ptr, max, input->prevtx_scriptpubkey, prevtx_scriptlen); + input->max_witness_len = fromwire_u16(ptr, max); + script_len = fromwire_u16(ptr, max); + fromwire_u8_array(ptr, max, input->script, script_len); + + return input; +} +void towire_output_info(u8 **pptr, const struct output_info *output_info) +{ + towire_u16(pptr, output_info->serial_id); + towire_amount_sat(pptr, output_info->sats); + towire_u16(pptr, tal_count(output_info->script)); + towire_u8_array(pptr, output_info->script, tal_count(output_info->script)); +} +struct output_info *fromwire_output_info(const tal_t *ctx, const u8 **ptr, size_t *max) +{ + struct output_info *output = tal(ctx, struct output_info); + u16 script_len; + + output->serial_id = fromwire_u16(ptr, max); + output->sats = fromwire_amount_sat(ptr, max); + script_len = fromwire_u16(ptr, max); + fromwire_u8_array(ptr, max, output->script, script_len); + return output; +} diff --git a/common/funding_tx.h b/common/funding_tx.h index 28ef4d4a954f..3d0dd71c29b5 100644 --- a/common/funding_tx.h +++ b/common/funding_tx.h @@ -13,6 +13,27 @@ struct privkey; struct pubkey; struct utxo; +struct input_info { + u16 serial_id; + struct amount_sat sats; + struct bitcoin_txid prevtx_txid; + u32 prevtx_vout; + u8 *prevtx_scriptpubkey; + u16 max_witness_len; + u8 *script; +}; + +struct output_info { + u16 serial_id; + struct amount_sat sats; + u8 *script; +}; + +void towire_input_info(u8 **pptr, const struct input_info *input_info); +struct input_info *fromwire_input_info(const tal_t *ctx, const u8 **ptr, size_t *max); +void towire_output_info(u8 **pptr, const struct output_info *output_info); +struct output_info *fromwire_output_info(const tal_t *ctx, const u8 **ptr, size_t *max); + /** * funding_tx: create a P2WSH funding transaction for a channel. * @ctx: context to tal from. diff --git a/connectd/Makefile b/connectd/Makefile index 1d7fdeaa675a..619aa4446e9e 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -52,6 +52,7 @@ CONNECTD_COMMON_OBJS := \ common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ + common/funding_tx.o \ common/gen_status_wire.o \ common/gossip_rcvd_filter.o \ common/htlc_wire.o \ @@ -61,6 +62,7 @@ CONNECTD_COMMON_OBJS := \ common/node_id.o \ common/onionreply.o \ common/per_peer_state.o \ + common/permute_tx.o \ common/pseudorand.o \ common/status.o \ common/status_wire.o \ diff --git a/gossipd/Makefile b/gossipd/Makefile index 0bd9b98aab90..f7dcf8ca929f 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -54,6 +54,7 @@ GOSSIPD_COMMON_OBJS := \ common/derive_basepoints.o \ common/dev_disconnect.o \ common/features.o \ + common/funding_tx.o \ common/gen_status_wire.o \ common/gossip_rcvd_filter.o \ common/htlc_wire.o \ @@ -63,6 +64,7 @@ GOSSIPD_COMMON_OBJS := \ common/node_id.o \ common/onionreply.o \ common/per_peer_state.o \ + common/permute_tx.o \ common/ping.o \ common/pseudorand.o \ common/status.o \ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 5db3bbe4d95d..d08e2949e541 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -467,6 +467,11 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_PONG: err = handle_pong(peer, msg); goto handled_relay; +#if EXPERIMENTAL_FEATURES + case WIRE_BLACKLIST_PODLE: + /* FIXME: handle blacklisted PoDLE */ + goto handled_relay; +#endif /* EXPERIMENTAL_FEATURES */ /* These are non-gossip messages (!is_msg_for_gossipd()) */ case WIRE_INIT: @@ -490,14 +495,15 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: + case WIRE_TX_ADD_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_ADD_INPUT: - case WIRE_FUNDING_ADD_OUTPUT: - case WIRE_FUNDING_ADD_COMPLETE: - case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: - case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ status_broken("peer %s: relayed unexpected msg of type %s", type_to_string(tmpctx, struct node_id, &peer->id), diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index 5946f35eec3b..442d8e9b43f3 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -63,7 +63,7 @@ msgtype,hsm_dual_funding_sigs,40 #include #include #include -#include +#include msgdata,hsm_dual_funding_sigs,num_utxos,u16, msgdata,hsm_dual_funding_sigs,our_utxos,utxo,num_utxos msgdata,hsm_dual_funding_sigs,feerate_kw_funding,u32, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index f3ebd662588e..37ad858ef0c4 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1722,10 +1722,6 @@ static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, status_failed(STATUS_FAIL_INTERNAL_ERROR, "Unable to find index for input"); - /* Copy over info for which input this belongs to */ - memcpy(&stack->prevtx_txid, &our_utxos[i]->txid, sizeof(struct bitcoin_txid)); - stack->prevtx_vout = our_utxos[i]->outnum; - sign_input(tx, our_utxos[i], &inkey, &sig, input_index); witnesses = bitcoin_witness_p2wpkh(tmpctx, &sig, &inkey); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 03018d74e95f..35b0d40675fb 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -594,14 +594,8 @@ static bool add_remote_witnesses(struct unreleased_tx *utx, 0); } - /* Find the corresponding input in the transaction */ - for (j = 0; j < tal_count(utx->inputs); j++) { - if (bitcoin_txid_eq(&utx->inputs[j]->txid, &witness->prevtx_txid) && - utx->inputs[j]->index == witness->prevtx_vout) { - utx->inputs[j]->witness = tal_steal(utx->inputs[j], witnesses_arr); - break; - } - } + /* FIXME: make sure inputs are ordered corrrectly (by serial_id) */ + utx->inputs[i]->witness = tal_steal(utx->inputs[i], witnesses_arr); } return true; diff --git a/onchaind/Makefile b/onchaind/Makefile index 09f5feb62e89..96b882dda2e1 100644 --- a/onchaind/Makefile +++ b/onchaind/Makefile @@ -54,6 +54,7 @@ ONCHAIND_COMMON_OBJS := \ common/daemon_conn.o \ common/derive_basepoints.o \ common/dev_disconnect.o \ + common/funding_tx.o \ common/gen_status_wire.o \ common/htlc_tx.o \ common/htlc_wire.o \ diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 7e24856a01a9..13489edd6e65 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -182,6 +182,7 @@ msgdata,opening_dual_funding_signed,shutdown_scriptpubkey,u8,shutdown_len # openingd -> master: are these inputs valid? msgtype,opening_check_inputs,6312 #if EXPERIMENTAL_FEATURES +#include msgdata,opening_check_inputs,num_inputs,u32, msgdata,opening_check_inputs,inputs,input_info,num_inputs diff --git a/openingd/openingd.c b/openingd/openingd.c index b7e41aa354a4..1847ab1397f2 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -630,14 +630,15 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) state->feerate_per_kw_funding = state->feerate_per_kw; msg = towire_open_channel2(NULL, &chainparams->genesis_blockhash, - &state->channel_id, + 0, /* FIXME: use real locktime */ + NULL, /* FIXME: use real podleh2 */ + state->feerate_per_kw_funding, state->opener_funding, state->push_msat, state->localconf.dust_limit, state->localconf.max_htlc_value_in_flight, state->localconf.htlc_minimum, state->feerate_per_kw, - state->feerate_per_kw_funding, state->localconf.to_self_delay, state->localconf.max_accepted_htlcs, &state->our_funding_pubkey, @@ -1135,6 +1136,40 @@ static bool check_remote_input_outputs(struct state *state, return true; } +static u16 next_serial(enum role role) +{ + /* todo: pick a random number, and check parity. must be unique? */ + if (role == ACCEPTER) + return 1; + return 0; +} + +static bool remove_output(struct output_info **outs, u16 serial_id) +{ + size_t i; + for (i = 0; i < tal_count(outs); i++) { + if (outs[i]->serial_id == serial_id) { + // how to remove ?? + return true; + } + } + + return false; +} + +static bool remove_input(struct input_info **ins, u16 serial_id) +{ + size_t i; + for (i = 0; i < tal_count(ins); i++) { + if (ins[i]->serial_id == serial_id) { + // how to remove ?? + return true; + } + } + + return false; +} + static bool send_receive_funding_tx_info(struct state *state, enum role role, struct input_info ***local_inputs, @@ -1144,6 +1179,8 @@ static bool send_receive_funding_tx_info(struct state *state, { struct channel_id id_in; + struct input_info *input; + struct output_info *output; bool complete; size_t i, queue_count; u8 *msg; @@ -1157,15 +1194,26 @@ static bool send_receive_funding_tx_info(struct state *state, * - if is the `accepter`: * - MAY omit this message */ - if (tal_count(*local_inputs) > 0) { - msg = towire_funding_add_input(tmpctx, &state->channel_id, - cast_const2(const struct input_info **, - *local_inputs)); + for (i = 0; i < tal_count(local_inputs); i++) { + input = *local_inputs[i]; + msg = towire_tx_add_input(tmpctx, &state->channel_id, + next_serial(role), + input->sats, + &input->prevtx_txid, + input->prevtx_vout, + input->prevtx_scriptpubkey, + input->max_witness_len, + input->script, + NULL); // FIXME: podle! + sync_crypto_write(state->pps, take(msg)); - peer_billboard(false, "Opening channel: funding_add_input sent"); - } else + } + + if (tal_count(local_inputs) == 0) assert(role == ACCEPTER); + else + peer_billboard(false, "Opening channel: tx_add_inputs sent"); /* @@ -1174,36 +1222,23 @@ static bool send_receive_funding_tx_info(struct state *state, * Either node: * - MAY omit this message */ - if (tal_count(*local_outputs) > 0) { - msg = towire_funding_add_output(tmpctx, &state->channel_id, - cast_const2(const struct output_info **, - *local_outputs)); + for (i = 0; i < tal_count(local_outputs); i++) { + output = *local_outputs[i]; + msg = towire_tx_add_output(tmpctx, &state->channel_id, + next_serial(role), + output->sats, + output->script); sync_crypto_write(state->pps, take(msg)); - peer_billboard(false, "Opening channel: funding_add_output sent"); } + if (tal_count(local_outputs) > 0) + peer_billboard(false, "Opening channel: tx_add_outputs sent"); - /* - * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 - * - * Both nodes: - * - MUST send this message after `accept_channel2` has been sent/received. - * - * The sending node: - * - MUST ensure that the `num_inputs` corresponds to the total sum of all `num_inputs` - * sent in all `funding_add_input` messages that originated from them - * - MUST ensure that the `num_outputs` corresponds to the total sum of all `num_outputs` - * sent in all `funding_add_output` messages that originated from them - */ - /* FIXME: allow for more interactive input/output composition */ - msg = towire_funding_add_complete(tmpctx, &state->channel_id, - tal_count(*local_inputs), - tal_count(*local_outputs)); + /* FIXME: allow for more interactive input/output composition */ + msg = towire_tx_complete(tmpctx, &state->channel_id); sync_crypto_write(state->pps, take(msg)); - peer_billboard(false, "Opening channel: funding_add_complete sent"); - /* We expect the peer to send us their inputs/outputs. Read * until we get funding_add_complete */ complete = false; @@ -1212,9 +1247,7 @@ static bool send_receive_funding_tx_info(struct state *state, queue_count = 0; while (!complete) { - struct input_info **inputs; - struct output_info **outputs; - u16 num_ins, num_outs; + u16 serial_id; int type; /* First we get messages off the queue, if any */ @@ -1230,73 +1263,98 @@ static bool send_receive_funding_tx_info(struct state *state, type = fromwire_peektype(msg); switch (type) { - case WIRE_FUNDING_ADD_INPUT: - if (!fromwire_funding_add_input(state, msg, &id_in, &inputs)) + case WIRE_TX_ADD_INPUT: + input = tal(remote_inputs, struct input_info); + struct tlv_tx_add_input_tlvs *tlv = + tlv_tx_add_input_tlvs_new(input); + + if (!fromwire_tx_add_input(input, msg, &id_in, + &input->serial_id, + &input->sats, + &input->prevtx_txid, + &input->prevtx_vout, + &input->prevtx_scriptpubkey, + &input->max_witness_len, + &input->script, + tlv)) peer_failed(state->pps, &state->channel_id, - "Parsing received funding_add_input %s", + "Parsing received tx_add_input %s", tal_hex(msg, msg)); check_channel_id(state, &id_in, &state->channel_id); - // FIXME: is there a more succinct way to do this? - for (i = 0; i < tal_count(inputs); i++) - tal_arr_expand(remote_inputs, inputs[i]); + // FIXME: verify podle? + tal_arr_expand(remote_inputs, input); + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); break; - case WIRE_FUNDING_ADD_OUTPUT: - if (!fromwire_funding_add_output(state, msg, &id_in, &outputs)) + case WIRE_TX_ADD_OUTPUT: + output = tal(remote_outputs, struct output_info); + if (!fromwire_tx_add_output(output, msg, &id_in, + &output->serial_id, + &output->sats, + &output->script)) peer_failed(state->pps, &state->channel_id, - "Parsing received funding_add_output %s", + "Parsing received tx_add_output %s", tal_hex(msg, msg)); check_channel_id(state, &id_in, &state->channel_id); - // FIXME: is there a more succinct way to do this? - for (i = 0; i < tal_count(outputs); i++) - tal_arr_expand(remote_outputs, outputs[i]); + tal_arr_expand(remote_outputs, output); + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); break; - case WIRE_FUNDING_ADD_COMPLETE: - if (!fromwire_funding_add_complete(msg, &id_in, - &num_ins, &num_outs)) + case WIRE_TX_REMOVE_INPUT: + if (!fromwire_tx_remove_input(msg, &id_in, &serial_id)) peer_failed(state->pps, &state->channel_id, - "Parsing received funding_add_complete %s", + "Parsing received tx_remove_input %s", tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); - /* - * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 - * - * The receiving node: - * - MUST fail the channel if: - * - the `num_inputs` does not correspond to the total - * sum of all `num_inputs` received in all - * `funding_add_input` messages - * - the `num_outputs` does not correspond to the total - * sum of all `num_outputs` received in all - * `funding_add_output` messages - */ - if (tal_count(*remote_inputs) != num_ins) + if (!remove_input(*remote_inputs, serial_id)) + peer_failed(state->pps, &state->channel_id, + "Attempted to remove unknown input %u", + serial_id); + + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); + break; + case WIRE_TX_REMOVE_OUTPUT: + if (!fromwire_tx_remove_output(msg, &id_in, &serial_id)) peer_failed(state->pps, &state->channel_id, - "Expected %u inputs, received %zu :%s", - num_ins, tal_count(*remote_inputs), + "Parsing received tx_remove_output %s", tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + if (!remove_output(*remote_outputs, serial_id)) + peer_failed(state->pps, &state->channel_id, + "Attempted to remove unknown output %u", + serial_id); + + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); + break; + case WIRE_TX_COMPLETE: + if (!fromwire_tx_complete(msg, &id_in)) + peer_failed(state->pps, &state->channel_id, + "Parsing received tx_complete %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); /** * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - if is the `opener`: * - MUST send at least one `funding_add_input` message */ - if (num_ins == 0 && role != OPENER) + if (tal_count(*remote_inputs) == 0) peer_failed(state->pps, &state->channel_id, "Opener must send at lease one input"); - if (tal_count(*remote_outputs) != num_outs) - peer_failed(state->pps, &state->channel_id, - "Expected %u outputs, received %zu :%s", - num_outs, tal_count(*remote_outputs), - tal_hex(msg, msg)); + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); complete = true; break; default: peer_failed(state->pps, &state->channel_id, - "Expected a funding_add_ message, got %s", + "Expected a tx_ message, got %s", tal_hex(msg, msg)); } @@ -1308,18 +1366,13 @@ static bool send_receive_funding_tx_info(struct state *state, return true; } -static bool input_outpoint_eq(struct witness_stack *witness, - struct input_info *input) -{ - return bitcoin_txid_eq(&witness->prevtx_txid, &input->prevtx_txid) && - witness->prevtx_vout == input->prevtx_vout; -} - static u32 sum_witness_len(struct witness_stack *witness) { u32 len = 0; for (size_t i = 0; i < tal_count(witness->witness_element); i++) - len += tal_count(witness->witness_element[i]->witness); + /* We add one for each element -- the size counter */ + /* FIXME: use varsize of len to get size */ + len += tal_count(witness->witness_element[i]->witness) + 1; return len; } @@ -1327,7 +1380,7 @@ static u32 sum_witness_len(struct witness_stack *witness) static char *check_remote_witnesses(struct witness_stack **witnesses, struct input_info **inputs) { - size_t i, j; + size_t i; u16 witness_len; if (tal_count(witnesses) != tal_count(inputs)) @@ -1335,35 +1388,24 @@ static char *check_remote_witnesses(struct witness_stack **witnesses, tal_count(witnesses), tal_count(inputs)); + //TODO: sort input_info by serial_id + /* * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 * - if the `witness_stack` length exceeds `max_witness_len`: * - MUST error. */ for (i = 0; i < tal_count(witnesses); i++) { - bool found = false; - for (j = 0; j < tal_count(inputs); j++) { - if (input_outpoint_eq(witnesses[i], inputs[j])) { - found = true; - witness_len = sum_witness_len(witnesses[i]); - if (witness_len > inputs[j]->max_witness_len) { - return tal_fmt(tmpctx, "Witness %s:%d len %u " - "larger than specified max %u", - type_to_string(tmpctx, - struct bitcoin_txid, - &witnesses[i]->prevtx_txid), - witnesses[i]->prevtx_vout, - witness_len, inputs[j]->max_witness_len); - } - break; - } - } - if (!found) - return tal_fmt(tmpctx, "No matching input found for witness %s:%u", + witness_len = sum_witness_len(witnesses[i]); + if (witness_len > inputs[i]->max_witness_len) { + return tal_fmt(tmpctx, "Witness for %s:%d len %u " + "larger than specified max %u", type_to_string(tmpctx, struct bitcoin_txid, - &witnesses[i]->prevtx_txid), - witnesses[i]->prevtx_vout); + &inputs[i]->prevtx_txid), + inputs[i]->prevtx_vout, + witness_len, inputs[i]->max_witness_len); + } } return NULL; @@ -1389,6 +1431,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, size_t i, input_count; struct bitcoin_tx *funding_tx, *remote_commit, *local_commit; + struct bitcoin_txid remote_txid; struct witness_stack **remote_witnesses; @@ -1582,11 +1625,21 @@ static u8 *funder_finalize_channel_setup2(struct state *state, if (!msg) return NULL; - if (!fromwire_funding_signed2(state, msg, - &id_in, &remote_witnesses)) + if (!fromwire_tx_signatures(state, msg, &id_in, + &remote_txid, + &remote_witnesses)) peer_failed(state->pps, &state->channel_id, - "Bad funding_signed2 in %s", tal_hex(msg, msg)); + "Bad tx_signatures in %s", tal_hex(msg, msg)); + + check_channel_id(state, &id_in, &state->channel_id); + if (!bitcoin_txid_eq(&state->funding_txid, &remote_txid)) + peer_failed(state->pps, &state->channel_id, + "Wrong txid for funding_signatures. " + "Expected %s, got %s", + type_to_string(tmpctx, struct bitcoin_txid, &state->funding_txid), + type_to_string(tmpctx, struct bitcoin_txid, &remote_txid)); + /* Check remote witness info */ err_reason = check_remote_witnesses(remote_witnesses, remote_ins); @@ -2056,18 +2109,21 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) const u8 *wscript; u8 channel_flags; u8 *msg; + u32 locktime; + struct sha256 podle_h2; struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); if (!fromwire_open_channel2(open_channel2_msg, &chain_hash, - &state->channel_id, + &locktime, + &podle_h2, + &state->feerate_per_kw_funding, &state->opener_funding, &state->push_msat, &state->remoteconf.dust_limit, &state->remoteconf.max_htlc_value_in_flight, &state->remoteconf.htlc_minimum, &state->feerate_per_kw, - &state->feerate_per_kw_funding, &state->remoteconf.to_self_delay, &state->remoteconf.max_accepted_htlcs, &state->their_funding_pubkey, @@ -2366,8 +2422,9 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) msg = towire_commitment_signed(state, &state->channel_id, &our_sig.s, NULL); sync_crypto_write(state->pps, take(msg)); - /* We send funding_signed2 after we've committed this to disk */ - msg = towire_funding_signed2(state, &state->channel_id, + /* We send tx signatures after we've committed this to disk */ + msg = towire_tx_signatures(state, &state->channel_id, + &state->funding_txid, cast_const2(const struct witness_stack **, our_stack)); /* We convert their inputs to a different format to get around @@ -2766,9 +2823,11 @@ static u8 *handle_peer_in(struct state *state) state->use_v2 = true; return fundee_channel2(state, msg); } - if (t == WIRE_FUNDING_ADD_INPUT - || t == WIRE_FUNDING_ADD_OUTPUT - || t == WIRE_FUNDING_ADD_COMPLETE) { + if (t == WIRE_TX_ADD_INPUT + || t == WIRE_TX_ADD_OUTPUT + || t == WIRE_TX_REMOVE_INPUT + || t == WIRE_TX_REMOVE_OUTPUT + || t == WIRE_TX_COMPLETE) { /* add to queue for this state/peer because * it's possible we're off getting ready for multi-fund whatever.*/ queue_msg(state, msg); diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 37937e4f966a..df554d651347 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -243,6 +243,7 @@ class Type(FieldSet): ('msat', 'u64'): ('amount_msat', False), ('satoshis', 'u64'): ('amount_sat', False), ('sats', 'u64'): ('amount_sat', False), + ('node_id', 'pubkey', 'blacklist_podle'): ('node_id', False), ('node_id', 'pubkey', 'channel_announcement'): ('node_id', False), ('node_id', 'pubkey', 'node_announcement'): ('node_id', False), ('temporary_channel_id', 'u8'): ('channel_id', True), diff --git a/wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 b/wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 deleted file mode 100644 index f1c50080fb7d..000000000000 --- a/wire/extracted_peer_experimental_3f9f65d3ad5a21835994f9d9226ed9e0e4066662 +++ /dev/null @@ -1,99 +0,0 @@ ---- wire/extracted_peer_wire_csv 2019-11-21 16:04:36.972045004 -0600 -+++ - 2019-11-21 16:20:28.611476176 -0600 -@@ -77,6 +77,96 @@ - msgtype,funding_locked,36 - msgdata,funding_locked,channel_id,channel_id, - msgdata,funding_locked,next_per_commitment_point,point, -+msgtype,open_channel2,64 -+msgdata,open_channel2,chain_hash,chain_hash, -+msgdata,open_channel2,temporary_channel_id,byte,32 -+msgdata,open_channel2,funding_satoshis,u64, -+msgdata,open_channel2,push_msat,u64, -+msgdata,open_channel2,dust_limit_satoshis,u64, -+msgdata,open_channel2,max_htlc_value_in_flight_msat,u64, -+msgdata,open_channel2,htlc_minimum_msat,u64, -+msgdata,open_channel2,feerate_per_kw,u32, -+msgdata,open_channel2,feerate_per_kw_funding,u32, -+msgdata,open_channel2,to_self_delay,u16, -+msgdata,open_channel2,max_accepted_htlcs,u16, -+msgdata,open_channel2,funding_pubkey,point, -+msgdata,open_channel2,revocation_basepoint,point, -+msgdata,open_channel2,payment_basepoint,point, -+msgdata,open_channel2,delayed_payment_basepoint,point, -+msgdata,open_channel2,htlc_basepoint,point, -+msgdata,open_channel2,first_per_commitment_point,point, -+msgdata,open_channel2,channel_flags,byte, -+msgdata,open_channel2,opening_tlv,opening_tlvs, -+tlvtype,opening_tlvs,option_upfront_shutdown_script,1 -+tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, -+tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len -+msgtype,accept_channel2,65 -+msgdata,accept_channel2,temporary_channel_id,byte,32 -+msgdata,accept_channel2,funding_satoshis,u64, -+msgdata,accept_channel2,dust_limit_satoshis,u64, -+msgdata,accept_channel2,max_htlc_value_in_flight_msat,u64, -+msgdata,accept_channel2,htlc_minimum_msat,u64, -+msgdata,accept_channel2,minimum_depth,u32, -+msgdata,accept_channel2,to_self_delay,u16, -+msgdata,accept_channel2,max_accepted_htlcs,u16, -+msgdata,accept_channel2,funding_pubkey,point, -+msgdata,accept_channel2,revocation_basepoint,point, -+msgdata,accept_channel2,payment_basepoint,point, -+msgdata,accept_channel2,delayed_payment_basepoint,point, -+msgdata,accept_channel2,htlc_basepoint,point, -+msgdata,accept_channel2,first_per_commitment_point,point, -+msgdata,accept_channel2,accept_tlv,accept_tlvs, -+tlvtype,accept_tlvs,option_upfront_shutdown_script,1 -+tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, -+tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len -+msgtype,funding_add_input,66 -+msgdata,funding_add_input,temporary_channel_id,byte,32 -+msgdata,funding_add_input,num_inputs,u16, -+msgdata,funding_add_input,input_info,input_info,num_inputs -+subtype,input_info -+subtypedata,input_info,sats,u64, -+subtypedata,input_info,prevtx_txid,sha256, -+subtypedata,input_info,prevtx_vout,u32, -+subtypedata,input_info,prevtx_scriptpubkey_len,u16, -+subtypedata,input_info,prevtx_scriptpubkey,byte,prevtx_scriptpubkey_len -+subtypedata,input_info,max_witness_len,u16, -+subtypedata,input_info,scriptlen,u16, -+subtypedata,input_info,script,byte,scriptlen -+msgtype,funding_add_output,67 -+msgdata,funding_add_output,temporary_channel_id,byte,32 -+msgdata,funding_add_output,num_outputs,u16, -+msgdata,funding_add_output,output_info,output_info,num_outputs -+subtype,output_info -+subtypedata,output_info,sats,u64, -+subtypedata,output_info,scriptlen,u16, -+subtypedata,output_info,script,byte,scriptlen -+msgtype,funding_add_complete,68 -+msgdata,funding_add_complete,temporary_channel_id,byte,32 -+msgdata,funding_add_complete,num_inputs,u16, -+msgdata,funding_add_complete,num_outputs,u16, -+msgtype,funding_signed2,69 -+msgdata,funding_signed2,channel_id,channel_id, -+msgdata,funding_signed2,num_witnesses,u16, -+msgdata,funding_signed2,witness_stack,witness_stack,num_witnesses -+subtype,witness_stack -+subtypedata,witness_stack,prevtx_txid,sha256, -+subtypedata,witness_stack,prevtx_vout,u32, -+subtypedata,witness_stack,num_input_witness,u16, -+subtypedata,witness_stack,witness_element,witness_element,num_input_witness -+subtype,witness_element -+subtypedata,witness_element,len,u16, -+subtypedata,witness_element,witness,byte,len -+msgtype,init_rbf,70 -+msgdata,init_rbf,channel_id,channel_id, -+msgdata,init_rbf,funding_satoshis,u64, -+msgdata,init_rbf,feerate_per_kw,u32, -+msgdata,init_rbf,feerate_per_kw_funding,u32, -+msgdata,init_rbf,num_additional_inputs,u16, -+msgdata,init_rbf,input_info,input_info,num_additional_inputs -+msgdata,init_rbf,num_outputs,u16, -+msgdata,init_rbf,output_info,output_info,num_outputs -+msgtype,ack_rbf,71 -+msgdata,ack_rbf,channel_id,channel_id, - msgtype,shutdown,38 - msgdata,shutdown,channel_id,channel_id, - msgdata,shutdown,len,u16, diff --git a/wire/peer_wire.c b/wire/peer_wire.c index bf78e5254448..7e314e6d1177 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -33,14 +33,16 @@ static bool unknown_type(enum wire_type t) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: + case WIRE_TX_ADD_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_ADD_INPUT: - case WIRE_FUNDING_ADD_OUTPUT: - case WIRE_FUNDING_ADD_COMPLETE: - case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: - case WIRE_ACK_RBF: + case WIRE_BLACKLIST_PODLE: #endif /* EXPERIMENTAL_FEATURES */ return false; } @@ -59,6 +61,9 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_REPLY_CHANNEL_RANGE: case WIRE_PING: case WIRE_PONG: +#if EXPERIMENTAL_FEATURES + case WIRE_BLACKLIST_PODLE: +#endif /* EXPERIMENTAL_FEATURES */ return true; case WIRE_INIT: case WIRE_ERROR: @@ -81,14 +86,15 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: + case WIRE_TX_ADD_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_FUNDING_ADD_INPUT: - case WIRE_FUNDING_ADD_OUTPUT: - case WIRE_FUNDING_ADD_COMPLETE: - case WIRE_FUNDING_SIGNED2: case WIRE_INIT_RBF: - case WIRE_ACK_RBF: #endif /* EXPERIMENTAL_FEATURES */ break; } diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index ca9945956ef6..ff5a109feac0 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -81,20 +81,22 @@ static void set_node_id(struct node_id *id) (tal_count((p1)->field) == tal_count((p2)->field) \ && (tal_count((p1)->field) == 0 || memcmp((p1)->field, (p2)->field, tal_bytelen((p1)->field)) == 0)) -#define eq_struct_set(p1, p2, field, type) \ - do { \ - ok &= (!(p1) && !(p2)) || ((p1) && (p2)); \ - ok &= (!(p1)->field && !(p2)->field) || ((p1)->field && (p2)->field); \ - if (ok && (p1) && (p1)->field) \ - for (size_t i = 0; i < tal_count((p1)->field); i++) { \ - struct type *_a, *_b; \ - _a = a->field[i]; \ - _b = b->field[i]; \ - ok &= (_a && _b) || (!_a && !_b); \ - if (ok && _a) \ - ok &= (type##_eq(_a, _b)); \ - } \ - } while (0) \ +/* Check a set of structs */ +#define eq_struct_set(p1, p2, field, type) \ + do { \ + ok &= (!(p1) && !(p2)) || ((p1) && (p2)); \ + ok &= (!(p1)->field && !(p2)->field) || ((p1)->field && (p2)->field); \ + if (ok && (p1) && (p1)->field) \ + for (size_t i = 0; i < tal_count((p1)->field); i++) { \ + struct type *_a, *_b; \ + _a = a->field[i]; \ + _b = b->field[i]; \ + ok &= (_a && _b) || (!_a && !_b); \ + if (ok && _a) \ + ok &= (type##_eq(_a, _b)); \ + } \ + } while (0) \ + /* Convenience structs for everyone! */ struct msg_error { @@ -195,6 +197,12 @@ struct msg_node_announcement { u8 *features; u8 *addresses; }; +struct msg_blacklist_podle { + secp256k1_ecdsa_signature signature; + u32 timestamp; + struct node_id node_id; + struct sha256 podle_h2; +}; struct msg_open_channel { struct bitcoin_blkid chain_hash; struct channel_id temporary_channel_id; @@ -254,14 +262,15 @@ struct msg_update_fee { /* Open Channel 2 */ struct msg_open_channel2 { struct bitcoin_blkid chain_hash; - struct channel_id temporary_channel_id; + u32 locktime; + struct sha256 podle_h2; + u32 feerate_per_kw_funding; struct amount_sat funding_satoshis; struct amount_msat push_msat; struct amount_sat dust_limit_satoshis; struct amount_msat max_htlc_value_in_flight_msat; struct amount_msat htlc_minimum_msat; u32 feerate_per_kw; - u32 feerate_per_kw_funding; u16 to_self_delay; u16 max_accepted_htlcs; struct pubkey funding_pubkey; @@ -274,7 +283,7 @@ struct msg_open_channel2 { struct tlv_opening_tlvs *tlv; }; struct msg_accept_channel2 { - struct channel_id temporary_channel_id; + struct channel_id channel_id; struct amount_sat funding_satoshis; struct amount_sat dust_limit_satoshis; struct amount_msat max_htlc_value_in_flight_msat; @@ -290,33 +299,45 @@ struct msg_accept_channel2 { struct pubkey first_per_commitment_point; struct tlv_accept_tlvs *tlv; }; -struct msg_funding_add_input { - struct channel_id temporary_channel_id; - struct input_info **input_infos; +struct msg_tx_add_input { + u32 prevtx_vout; + u16 max_witness_len; + u16 serial_id; + struct amount_sat sats; + struct bitcoin_txid prevtx_txid; + struct channel_id channel_id; + u8 *prevtx_scriptpubkey; + u8 *script; + struct tlv_tx_add_input_tlvs *tlv; }; -struct msg_funding_add_output { - struct channel_id temporary_channel_id; - struct output_info **output_infos; +struct msg_tx_add_output { + struct amount_sat sats; + struct channel_id channel_id; + u16 serial_id; + u8 *script; }; -struct msg_funding_add_complete { - struct channel_id temporary_channel_id; - u16 num_inputs; - u16 num_outputs; +struct msg_tx_remove_input { + struct channel_id channel_id; + u16 serial_id; +}; +struct msg_tx_remove_output { + struct channel_id channel_id; + u16 serial_id; +}; +struct msg_tx_complete { + struct channel_id channel_id; }; -struct msg_funding_signed2 { +struct msg_tx_signatures { struct channel_id channel_id; + struct bitcoin_txid txid; struct witness_stack **witness_stacks; }; struct msg_init_rbf { struct channel_id channel_id; struct amount_sat funding_satoshis; + u32 locktime; u32 feerate_per_kw; - u32 feerate_per_kw_funding; - struct input_info **input_infos; - struct output_info **output_infos; -}; -struct msg_ack_rbf { - struct channel_id channel_id; + u8 fee_step; }; static void *towire_struct_channel_announcement(const tal_t *ctx, @@ -857,19 +878,47 @@ static struct msg_init *fromwire_struct_init(const tal_t *ctx, const void *p) } #if EXPERIMENTAL_FEATURES +static void set_sha256(struct sha256 *sha) +{ + memset(sha->u.u8, 2, sizeof(sha->u.u8)); +} + +static void *towire_struct_blacklist_podle(const tal_t *ctx, + const struct msg_blacklist_podle *s) +{ + return towire_blacklist_podle(ctx, + &s->signature, + &s->node_id, + &s->podle_h2, + s->timestamp); +} +static struct msg_blacklist_podle *fromwire_struct_blacklist_podle(const tal_t *ctx, + const void *p) +{ + struct msg_blacklist_podle *s = tal(ctx, struct msg_blacklist_podle); + if (!fromwire_blacklist_podle(p, + &s->signature, + &s->node_id, + &s->podle_h2, + &s->timestamp)) + return tal_free(s); + return s; +} + static void *towire_struct_open_channel2(const tal_t *ctx, - const struct msg_open_channel2 *s) + const struct msg_open_channel2 *s) { return towire_open_channel2(ctx, &s->chain_hash, - &s->temporary_channel_id, + s->locktime, + &s->podle_h2, + s->feerate_per_kw_funding, s->funding_satoshis, s->push_msat, s->dust_limit_satoshis, s->max_htlc_value_in_flight_msat, s->htlc_minimum_msat, s->feerate_per_kw, - s->feerate_per_kw_funding, s->to_self_delay, s->max_accepted_htlcs, &s->funding_pubkey, @@ -888,24 +937,25 @@ static struct msg_open_channel2 *fromwire_struct_open_channel2(const tal_t *ctx, s->tlv = tlv_opening_tlvs_new(ctx); if (fromwire_open_channel2(p, &s->chain_hash, - &s->temporary_channel_id, - &s->funding_satoshis, - &s->push_msat, - &s->dust_limit_satoshis, - &s->max_htlc_value_in_flight_msat, - &s->htlc_minimum_msat, - &s->feerate_per_kw, - &s->feerate_per_kw_funding, - &s->to_self_delay, - &s->max_accepted_htlcs, - &s->funding_pubkey, - &s->revocation_basepoint, - &s->payment_basepoint, - &s->delayed_payment_basepoint, - &s->htlc_basepoint, - &s->first_per_commitment_point, - &s->channel_flags, - s->tlv)) + &s->locktime, + &s->podle_h2, + &s->feerate_per_kw_funding, + &s->funding_satoshis, + &s->push_msat, + &s->dust_limit_satoshis, + &s->max_htlc_value_in_flight_msat, + &s->htlc_minimum_msat, + &s->feerate_per_kw, + &s->to_self_delay, + &s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->delayed_payment_basepoint, + &s->htlc_basepoint, + &s->first_per_commitment_point, + &s->channel_flags, + s->tlv)) return s; return tal_free(s); } @@ -913,21 +963,21 @@ static void *towire_struct_accept_channel2(const tal_t *ctx, const struct msg_accept_channel2 *s) { return towire_accept_channel2(ctx, - &s->temporary_channel_id, - s->funding_satoshis, - s->dust_limit_satoshis, - s->max_htlc_value_in_flight_msat, - s->htlc_minimum_msat, - s->minimum_depth, - s->to_self_delay, - s->max_accepted_htlcs, - &s->funding_pubkey, - &s->revocation_basepoint, - &s->payment_basepoint, - &s->htlc_basepoint, - &s->delayed_payment_basepoint, - &s->first_per_commitment_point, - s->tlv); + &s->channel_id, + s->funding_satoshis, + s->dust_limit_satoshis, + s->max_htlc_value_in_flight_msat, + s->htlc_minimum_msat, + s->minimum_depth, + s->to_self_delay, + s->max_accepted_htlcs, + &s->funding_pubkey, + &s->revocation_basepoint, + &s->payment_basepoint, + &s->htlc_basepoint, + &s->delayed_payment_basepoint, + &s->first_per_commitment_point, + s->tlv); } static struct msg_accept_channel2 *fromwire_struct_accept_channel2(const tal_t *ctx, const void *p) @@ -935,7 +985,7 @@ static struct msg_accept_channel2 *fromwire_struct_accept_channel2(const tal_t * struct msg_accept_channel2 *s = tal(ctx, struct msg_accept_channel2); s->tlv = tlv_accept_tlvs_new(ctx); - if (fromwire_accept_channel2(p, &s->temporary_channel_id, + if (fromwire_accept_channel2(p, &s->channel_id, &s->funding_satoshis, &s->dust_limit_satoshis, &s->max_htlc_value_in_flight_msat, @@ -953,111 +1003,136 @@ static struct msg_accept_channel2 *fromwire_struct_accept_channel2(const tal_t * return s; return tal_free(s); } -static void *towire_struct_funding_add_input(const tal_t *ctx, - struct msg_funding_add_input *s) -{ - return towire_funding_add_input(ctx, - &s->temporary_channel_id, - (const struct input_info **)s->input_infos); +static void *towire_struct_tx_add_input(const tal_t *ctx, + struct msg_tx_add_input *s) +{ + return towire_tx_add_input(ctx, &s->channel_id, + s->serial_id, + s->sats, + &s->prevtx_txid, + s->prevtx_vout, + s->prevtx_scriptpubkey, + s->max_witness_len, + s->script, + s->tlv); } -static struct msg_funding_add_input *fromwire_struct_funding_add_input(const tal_t *ctx, const void *p) +static struct msg_tx_add_input *fromwire_struct_tx_add_input(const tal_t *ctx, const void *p) { - struct msg_funding_add_input *s = tal(ctx, struct msg_funding_add_input); + struct msg_tx_add_input *s = tal(ctx, struct msg_tx_add_input); + s->tlv = tlv_tx_add_input_tlvs_new(s); - if (fromwire_funding_add_input(ctx, p, - &s->temporary_channel_id, - &s->input_infos)) + if (fromwire_tx_add_input(ctx, p, + &s->channel_id, + &s->serial_id, + &s->sats, + &s->prevtx_txid, + &s->prevtx_vout, + &s->prevtx_scriptpubkey, + &s->max_witness_len, + &s->script, + s->tlv)) return s; return tal_free(s); } -static void *towire_struct_funding_add_output(const tal_t *ctx, - struct msg_funding_add_output *s) +static void *towire_struct_tx_add_output(const tal_t *ctx, struct msg_tx_add_output *s) { - return towire_funding_add_output(ctx, - &s->temporary_channel_id, - (const struct output_info **)s->output_infos); + return towire_tx_add_output(ctx, + &s->channel_id, + s->serial_id, + s->sats, + s->script); } -static struct msg_funding_add_output *fromwire_struct_funding_add_output(const tal_t *ctx, const void *p) +static struct msg_tx_add_output *fromwire_struct_tx_add_output(const tal_t *ctx, const void *p) { - struct msg_funding_add_output *s = tal(ctx, struct msg_funding_add_output); + struct msg_tx_add_output *s = tal(ctx, struct msg_tx_add_output); - if (fromwire_funding_add_output(ctx, p, - &s->temporary_channel_id, - &s->output_infos)) + if (fromwire_tx_add_output(ctx, p, + &s->channel_id, + &s->serial_id, + &s->sats, + &s->script)) return s; return tal_free(s); } -static void *towire_struct_funding_add_complete(const tal_t *ctx, - struct msg_funding_add_complete *s) +static void *towire_struct_tx_remove_input(const tal_t *ctx, struct msg_tx_remove_input *s) { - return towire_funding_add_complete(ctx, &s->temporary_channel_id, - s->num_inputs, - s->num_outputs); + return towire_tx_remove_input(ctx, &s->channel_id, + s->serial_id); } -static struct msg_funding_add_complete *fromwire_struct_funding_add_complete(const tal_t *ctx, const void *p) +static struct msg_tx_remove_input *fromwire_struct_tx_remove_input(const tal_t *ctx, const void *p) { - struct msg_funding_add_complete *s = tal(ctx, struct msg_funding_add_complete); + struct msg_tx_remove_input *s = tal(ctx, struct msg_tx_remove_input); - if (fromwire_funding_add_complete(p, &s->temporary_channel_id, - &s->num_inputs, - &s->num_outputs)) + if (fromwire_tx_remove_input(p, &s->channel_id, + &s->serial_id)) return s; return tal_free(s); } -static void *towire_struct_funding_signed2(const tal_t *ctx, - struct msg_funding_signed2 *s) +static void *towire_struct_tx_remove_output(const tal_t *ctx, struct msg_tx_remove_output *s) { - return towire_funding_signed2(ctx, - &s->channel_id, - (const struct witness_stack **)s->witness_stacks); + return towire_tx_remove_output(ctx, &s->channel_id, + s->serial_id); } -static struct msg_funding_signed2 *fromwire_struct_funding_signed2(const tal_t *ctx, const void *p) +static struct msg_tx_remove_output *fromwire_struct_tx_remove_output(const tal_t *ctx, const void *p) { - struct msg_funding_signed2 *s = tal(ctx, struct msg_funding_signed2); + struct msg_tx_remove_output *s = tal(ctx, struct msg_tx_remove_output); - if (fromwire_funding_signed2(ctx, p, - &s->channel_id, - &s->witness_stacks)) { + if (fromwire_tx_remove_output(p, &s->channel_id, + &s->serial_id)) return s; - } return tal_free(s); } +static void *towire_struct_tx_complete(const tal_t *ctx, struct msg_tx_complete *s) +{ + return towire_tx_complete(ctx, &s->channel_id); +} +static struct msg_tx_complete *fromwire_struct_tx_complete(const tal_t *ctx, const void *p) +{ + struct msg_tx_complete *s = tal(ctx, struct msg_tx_complete); -static void *towire_struct_init_rbf(const tal_t *ctx, - struct msg_init_rbf *s) + if (fromwire_tx_complete(p, &s->channel_id)) + return s; + + return tal_free(s); +} +static void *towire_struct_tx_signatures(const tal_t *ctx, struct msg_tx_signatures *s) { - return towire_init_rbf(ctx, - &s->channel_id, - s->funding_satoshis, - s->feerate_per_kw, - s->feerate_per_kw_funding, - (const struct input_info **)s->input_infos, - (const struct output_info **)s->output_infos); + return towire_tx_signatures(ctx, &s->channel_id, + &s->txid, + (const struct witness_stack **)s->witness_stacks); } -static struct msg_init_rbf *fromwire_struct_init_rbf(const tal_t *ctx, const void *p) +static struct msg_tx_signatures *fromwire_struct_tx_signatures(const tal_t *ctx, const void *p) { - struct msg_init_rbf *s = tal(ctx, struct msg_init_rbf); + struct msg_tx_signatures *s = tal(ctx, struct msg_tx_signatures); - if (fromwire_init_rbf(ctx, p, - &s->channel_id, - &s->funding_satoshis, - &s->feerate_per_kw, - &s->feerate_per_kw_funding, - &s->input_infos, - &s->output_infos)) + if (fromwire_tx_signatures(ctx, p, + &s->channel_id, + &s->txid, + &s->witness_stacks)) { return s; + } return tal_free(s); } -static void *towire_struct_ack_rbf(const tal_t *ctx, const struct msg_ack_rbf *s) + +static void *towire_struct_init_rbf(const tal_t *ctx, + struct msg_init_rbf *s) { - return towire_ack_rbf(ctx, &s->channel_id); + return towire_init_rbf(ctx, &s->channel_id, + s->funding_satoshis, + s->locktime, + s->feerate_per_kw, + s->fee_step); } -static struct msg_ack_rbf *fromwire_struct_ack_rbf(const tal_t *ctx, const void *p) +static struct msg_init_rbf *fromwire_struct_init_rbf(const tal_t *ctx, const void *p) { - struct msg_ack_rbf *s = tal(ctx, struct msg_ack_rbf); + struct msg_init_rbf *s = tal(ctx, struct msg_init_rbf); - if (fromwire_ack_rbf(p, &s->channel_id)) + if (fromwire_init_rbf(p, &s->channel_id, + &s->funding_satoshis, + &s->locktime, + &s->feerate_per_kw, + &s->fee_step)) return s; return tal_free(s); } @@ -1076,20 +1151,11 @@ static bool accept_option_upfront_shutdown_script_eq(const struct tlv_accept_tlv || (a && b && eq_var(a, b, shutdown_scriptpubkey)); } -static bool input_info_eq(struct input_info *a, - struct input_info *b) -{ - return eq_with(a, b, prevtx_vout) - && eq_var(a, b, prevtx_scriptpubkey) - && eq_field(a, b, max_witness_len) - && eq_var(a, b, script); -} - -static bool output_info_eq(struct output_info *a, - struct output_info *b) +static bool podle_proof_eq(const struct tlv_tx_add_input_tlvs_podle_proof *a, + const struct tlv_tx_add_input_tlvs_podle_proof *b) { - return eq_with(a, b, sats) - && eq_var(a, b, script); + return (!a && !b) + || (a && b && eq_between(a, b, p, sig)); } static bool witness_element_eq(struct witness_element *a, @@ -1104,8 +1170,7 @@ static bool witness_stack_eq(struct witness_stack *a, { bool ok = true; eq_struct_set(a, b, witness_element, witness_element); - return ok && eq_field(a, b, prevtx_txid) - && eq_field(a, b, prevtx_vout); + return ok; } @@ -1127,6 +1192,14 @@ static bool accept_tlv_eq(const struct tlv_accept_tlvs *a, b->option_upfront_shutdown_script)); } +static bool tx_add_input_tlv_eq(const struct tlv_tx_add_input_tlvs *a, + const struct tlv_tx_add_input_tlvs *b) +{ + return (!a && !b) || + (a && b && + podle_proof_eq(a->podle_proof, b->podle_proof)); +} + static bool open_channel2_eq(const struct msg_open_channel2 *a, const struct msg_open_channel2 *b) { @@ -1143,29 +1216,44 @@ static bool accept_channel2_eq(const struct msg_accept_channel2 *a, && accept_tlv_eq(a->tlv, b->tlv); } -static bool funding_add_input_eq(const struct msg_funding_add_input *a, - const struct msg_funding_add_input *b) +static bool tx_add_input_eq(const struct msg_tx_add_input *a, + const struct msg_tx_add_input *b) { - bool ok = true; - eq_struct_set(a, b, input_infos, input_info); - return ok && eq_upto(a, b, input_infos); + return eq_with(a, b, channel_id) + && eq_var(a, b, prevtx_scriptpubkey) + && eq_var(a, b, script) + && tx_add_input_tlv_eq(a->tlv, b->tlv); } -static bool funding_add_output_eq(const struct msg_funding_add_output *a, - const struct msg_funding_add_output *b) +static bool tx_add_output_eq(const struct msg_tx_add_output *a, + const struct msg_tx_add_output *b) { - bool ok = true; - eq_struct_set(a, b, output_infos, output_info); - return ok && eq_upto(a, b, output_infos); + return eq_with(a, b, serial_id) + && eq_var(a, b, script); } -static bool funding_add_complete_eq(const struct msg_funding_add_complete *a, - const struct msg_funding_add_complete *b) +static bool tx_remove_input_eq(const struct msg_tx_remove_input *a, + const struct msg_tx_remove_input *b) { - return eq_with(a, b, num_outputs); + //return eq_with(a, b, serial_id); + return memcmp(a, b, sizeof(*a)) == 0; +} + +static bool tx_remove_output_eq(const struct msg_tx_remove_output *a, + const struct msg_tx_remove_output *b) +{ + //return eq_with(a, b, serial_id); + return memcmp(a, b, sizeof(*a)) == 0; } -static bool funding_signed2_eq(const struct msg_funding_signed2 *a, - const struct msg_funding_signed2 *b) + +static bool tx_complete_eq(const struct msg_tx_complete *a, + const struct msg_tx_complete *b) +{ + return memcmp(a, b, sizeof(*a)) == 0; +} + +static bool tx_signatures_eq(const struct msg_tx_signatures *a, + const struct msg_tx_signatures *b) { bool ok = true; eq_struct_set(a, b, witness_stacks, witness_stack); @@ -1175,17 +1263,16 @@ static bool funding_signed2_eq(const struct msg_funding_signed2 *a, static bool init_rbf_eq(const struct msg_init_rbf *a, const struct msg_init_rbf *b) { - bool ok = true; - eq_struct_set(a, b, input_infos, input_info); - eq_struct_set(a, b, output_infos, output_info); - return ok && eq_upto(a, b, input_infos); + return eq_with(a, b, fee_step); } -static bool ack_rbf_eq(const struct msg_ack_rbf *a, - const struct msg_ack_rbf *b) +static bool blacklist_podle_eq(const struct msg_blacklist_podle *a, + const struct msg_blacklist_podle *b) { - return memcmp(a, b, sizeof(*a)) == 0; + return eq_with(a, b, node_id) + && eq_field(a, b, podle_h2); } + #endif /* EXPERIMENTAL_FEATURES */ static bool channel_announcement_eq(const struct msg_channel_announcement *a, @@ -1358,7 +1445,7 @@ static bool node_announcement_eq(const struct msg_node_announcement *a, for (i = 0; i < tal_count(msg) * 8; i++) { \ msg[i / 8] ^= (1 << (i%8)); \ b = fromwire_struct_##type(ctx, msg); \ - assert(!b || !type##_eq(a, b)); \ + assert(!b || !type##_eq(a, b));; \ msg[i / 8] ^= (1 << (i%8)); \ } \ for (i = 0; i < tal_count(msg); i++) { \ @@ -1419,12 +1506,14 @@ int main(void) /* v2 channel establishment */ struct msg_open_channel2 ocv2, *ocv22; struct msg_accept_channel2 acv2, *acv22; - struct msg_funding_add_input fai, *fai2; - struct msg_funding_add_output fao, *fao2; - struct msg_funding_add_complete fac, *fac2; - struct msg_funding_signed2 fsv2, *fsv22; + struct msg_tx_add_input tai, *tai2; + struct msg_tx_add_output tao, *tao2; + struct msg_tx_remove_input tri, *tri2; + struct msg_tx_remove_output tro, *tro2; + struct msg_tx_complete tc, *tc2; + struct msg_tx_signatures ts, *ts2; struct msg_init_rbf irbf, *irbf2; - struct msg_ack_rbf arbf, *arbf2; + struct msg_blacklist_podle bp, *bp2; #endif /* EXPERIMENTAL_FEATURES */ void *ctx = tal(NULL, char); @@ -1628,7 +1717,7 @@ int main(void) set_pubkey(&ocv2.htlc_basepoint); set_pubkey(&ocv2.first_per_commitment_point); - ocv2.tlv = tal(ctx, struct tlv_opening_tlvs); + ocv2.tlv = tlv_opening_tlvs_new(ctx); ocv2.tlv->option_upfront_shutdown_script = tal(ctx, struct tlv_opening_tlvs_option_upfront_shutdown_script); ocv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = tal_arr(ctx, u8, 2); memset(ocv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey, 2, 2); @@ -1647,7 +1736,7 @@ int main(void) set_pubkey(&acv2.htlc_basepoint); set_pubkey(&acv2.first_per_commitment_point); - acv2.tlv = tal(ctx, struct tlv_accept_tlvs); + acv2.tlv = tlv_accept_tlvs_new(ctx); acv2.tlv->option_upfront_shutdown_script = tal(ctx, struct tlv_accept_tlvs_option_upfront_shutdown_script); acv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = tal_arr(ctx, u8, 2); memset(acv2.tlv->option_upfront_shutdown_script->shutdown_scriptpubkey, 2, 2); @@ -1657,95 +1746,89 @@ int main(void) assert(accept_channel2_eq(&acv2, acv22)); test_corruption_tlv(&acv2, acv22, accept_channel2); - memset(&fai, 2, sizeof(fai)); - fai.input_infos = tal_arr(ctx, struct input_info *, 2); - memset(fai.input_infos, 2, sizeof(struct input_info *) * 2); - for (i = 0; i < 2; i++) { - fai.input_infos[i] = tal(ctx, struct input_info); - memset(fai.input_infos[i], 2, sizeof(struct input_info)); - fai.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); - memset(fai.input_infos[i]->prevtx_scriptpubkey, 2, 2); - fai.input_infos[i]->script = tal_arr(ctx, u8, 2); - memset(fai.input_infos[i]->script, 2, 2); - } - msg = towire_struct_funding_add_input(ctx, &fai); - fai2 = fromwire_struct_funding_add_input(ctx, msg); - assert(funding_add_input_eq(&fai, fai2)); - test_corruption(&fai, fai2, funding_add_input); - - - memset(&fao, 2, sizeof(fao)); - fao.output_infos = tal_arr(ctx, struct output_info *, 2); - memset(fao.output_infos, 2, sizeof(struct output_info *)*2); - for (i = 0; i < 2; i++) { - fao.output_infos[i] = tal(ctx, struct output_info); - memset(fao.output_infos[i], 2, sizeof(struct output_info)); - fao.output_infos[i]->script = tal_arr(ctx, u8, 2); - memset(fao.output_infos[i]->script, 2, 2); - } - msg = towire_struct_funding_add_output(ctx, &fao); - fao2 = fromwire_struct_funding_add_output(ctx, msg); - assert(funding_add_output_eq(&fao, fao2)); - test_corruption(&fao, fao2, funding_add_output); - - memset(&fac, 2, sizeof(fac)); - msg = towire_struct_funding_add_complete(ctx, &fac); - fac2 = fromwire_struct_funding_add_complete(ctx, msg); - assert(funding_add_complete_eq(&fac, fac2)); - test_corruption(&fac, fac2, funding_add_complete); - - memset(&fsv2, 2, sizeof(fsv2)); - fsv2.witness_stacks = tal_arr(ctx, struct witness_stack *, 2); - memset(fsv2.witness_stacks, 2, sizeof(struct witness_stack *) * 2); + memset(&tai, 2, sizeof(tai)); + tai.tlv = tlv_tx_add_input_tlvs_new(ctx); + tai.tlv->podle_proof = tal(ctx, struct tlv_tx_add_input_tlvs_podle_proof); + set_sha256(&tai.tlv->podle_proof->e); + set_pubkey(&tai.tlv->podle_proof->p); + set_pubkey(&tai.tlv->podle_proof->p2); + memset(&tai.tlv->podle_proof->sig, 2, 32); + + tai.prevtx_scriptpubkey = tal_arr(ctx, u8, 2); + memset(tai.prevtx_scriptpubkey, 2, 2); + tai.script = tal_arr(ctx, u8, 2); + memset(tai.script, 2, 2); + msg = towire_struct_tx_add_input(ctx, &tai); + tai2 = fromwire_struct_tx_add_input(ctx, msg); + assert(tx_add_input_eq(&tai, tai2)); + + test_corruption_tlv(&tai, tai2, tx_add_input); + + memset(&tao, 2, sizeof(tao)); + tao.script = tal_arr(ctx, u8, 2); + memset(tao.script, 2, 2); + + msg = towire_struct_tx_add_output(ctx, &tao); + tao2 = fromwire_struct_tx_add_output(ctx, msg); + assert(tx_add_output_eq(&tao, tao2)); + test_corruption(&tao, tao2, tx_add_output); + + memset(&tri, 2, sizeof(tri)); + + msg = towire_struct_tx_remove_input(ctx, &tri); + tri2 = fromwire_struct_tx_remove_input(ctx, msg); + assert(tx_remove_input_eq(&tri, tri2)); + test_corruption(&tri, tri2, tx_remove_input); + + memset(&tro, 2, sizeof(tro)); + + msg = towire_struct_tx_remove_output(ctx, &tro); + tro2 = fromwire_struct_tx_remove_output(ctx, msg); + assert(tx_remove_output_eq(&tro, tro2)); + test_corruption(&tro, tro2, tx_remove_output); + + memset(&tc, 2, sizeof(tc)); + msg = towire_struct_tx_complete(ctx, &tc); + tc2 = fromwire_struct_tx_complete(ctx, msg); + assert(tx_complete_eq(&tc, tc2)); + test_corruption(&tc, tc2, tx_complete); + + memset(&ts, 2, sizeof(ts)); + ts.witness_stacks = tal_arr(ctx, struct witness_stack *, 2); + memset(ts.witness_stacks, 2, sizeof(struct witness_stack *) * 2); for (i = 0; i < 2; i++) { - fsv2.witness_stacks[i] = tal(ctx, struct witness_stack); - memset(fsv2.witness_stacks[i], 2, sizeof(struct witness_stack)); - fsv2.witness_stacks[i]->witness_element = tal_arr(ctx, struct witness_element *, 2); - memset(fsv2.witness_stacks[i]->witness_element, 2, sizeof(struct witness_element *) * 2); + ts.witness_stacks[i] = tal(ctx, struct witness_stack); + memset(ts.witness_stacks[i], 2, sizeof(struct witness_stack)); + ts.witness_stacks[i]->witness_element = tal_arr(ctx, struct witness_element *, 2); + memset(ts.witness_stacks[i]->witness_element, 2, sizeof(struct witness_element *) * 2); for (size_t j = 0; j < 2; j++) { - fsv2.witness_stacks[i]->witness_element[j] = tal(ctx, struct witness_element); - memset(fsv2.witness_stacks[i]->witness_element[j], 2, sizeof(struct witness_element)); - fsv2.witness_stacks[i]->witness_element[j]->witness = tal_arr(ctx, u8, 2); - memset(fsv2.witness_stacks[i]->witness_element[j]->witness, 2, 2); + ts.witness_stacks[i]->witness_element[j] = tal(ctx, struct witness_element); + memset(ts.witness_stacks[i]->witness_element[j], 2, sizeof(struct witness_element)); + ts.witness_stacks[i]->witness_element[j]->witness = tal_arr(ctx, u8, 2); + memset(ts.witness_stacks[i]->witness_element[j]->witness, 2, 2); } } - msg = towire_struct_funding_signed2(ctx, &fsv2); - fsv22 = fromwire_struct_funding_signed2(ctx, msg); - assert(funding_signed2_eq(&fsv2, fsv22)); - test_corruption(&fsv2, fsv22, funding_signed2); + msg = towire_struct_tx_signatures(ctx, &ts); + ts2 = fromwire_struct_tx_signatures(ctx, msg); + assert(tx_signatures_eq(&ts, ts2)); + test_corruption(&ts, ts2, tx_signatures); memset(&irbf, 2, sizeof(irbf)); - irbf.input_infos = tal_arr(ctx, struct input_info *, 2); - memset(irbf.input_infos, 2, sizeof(struct input_info *) * 2); - for (i = 0; i < 2; i++) { - irbf.input_infos[i] = tal(ctx, struct input_info); - memset(irbf.input_infos[i], 2, sizeof(struct input_info)); - irbf.input_infos[i]->prevtx_scriptpubkey = tal_arr(ctx, u8, 2); - memset(irbf.input_infos[i]->prevtx_scriptpubkey, 2, 2); - irbf.input_infos[i]->script = tal_arr(ctx, u8, 2); - memset(irbf.input_infos[i]->script, 2, 2); - } - irbf.output_infos = tal_arr(ctx, struct output_info *, 2); - memset(irbf.output_infos, 2, sizeof(struct output_info *)*2); - for (i = 0; i < 2; i++) { - irbf.output_infos[i] = tal(ctx, struct output_info); - memset(irbf.output_infos[i], 2, sizeof(struct output_info)); - irbf.output_infos[i]->script = tal_arr(ctx, u8, 2); - memset(irbf.output_infos[i]->script, 2, 2); - } msg = towire_struct_init_rbf(ctx, &irbf); irbf2 = fromwire_struct_init_rbf(ctx, msg); assert(init_rbf_eq(&irbf, irbf2)); test_corruption(&irbf, irbf2, init_rbf); - memset(&arbf, 2, sizeof(arbf)); + memset(&bp, 2, sizeof(bp)); + set_node_id(&bp.node_id); + set_sha256(&bp.podle_h2); - msg = towire_struct_ack_rbf(ctx, &arbf); - arbf2 = fromwire_struct_ack_rbf(ctx, msg); - assert(ack_rbf_eq(&arbf, arbf2)); - test_corruption(&arbf, arbf2, ack_rbf); + msg = towire_struct_blacklist_podle(ctx, &bp); + bp2 = fromwire_struct_blacklist_podle(ctx, msg); + assert(blacklist_podle_eq(&bp, bp2)); + test_corruption(&bp, bp2, blacklist_podle); #endif /* EXPERIMENTAL_FEATURES */ /* No memory leaks please */ From 335ec00ee76dff7d991ad4d28d8c4ec94111ebed Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Mon, 24 Feb 2020 20:34:03 -0600 Subject: [PATCH 115/131] df: update channel id to sha256 of revocation basepoints --- lightningd/opening_control.c | 2 + openingd/opening_wire.csv | 2 + openingd/openingd.c | 63 +++++++--- ...l_f6f06187472f7d8e5806b6d127e00f8fc297a4cb | 119 ++++++++++++++++++ wire/fromwire.c | 27 +++- wire/test/Makefile | 2 + wire/test/run-fromwire.c | 106 ++++++++++++++++ wire/wire.h | 5 + 8 files changed, 309 insertions(+), 17 deletions(-) create mode 100644 wire/extracted_peer_experimental_f6f06187472f7d8e5806b6d127e00f8fc297a4cb create mode 100644 wire/test/run-fromwire.c diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 35b0d40675fb..c7221a2b2146 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1730,6 +1730,8 @@ void peer_start_openingd(struct peer *peer, uc->minimum_depth = peer->ld->config.anchor_confirms; msg = towire_opening_init(NULL, + /* We need sorting order to derive channel_id2 */ + node_id_cmp(&peer->ld->id, &peer->id), chainparams, peer->ld->our_features, &uc->our_config, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 13489edd6e65..f611352df059 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -5,6 +5,8 @@ #include msgtype,opening_init,6000 +# We need the node ordering (us/peer) for deriving the channel_id (v2) +msgdata,opening_init,node_order,u8, # Which network are we configured for? msgdata,opening_init,chainparams,chainparams, msgdata,opening_init,our_features,feature_set, diff --git a/openingd/openingd.c b/openingd/openingd.c index 1847ab1397f2..76bf1bd62989 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -68,6 +68,10 @@ static struct channel_id *dev_force_tmp_channel_id; struct state { struct per_peer_state *pps; + /* We need the node ordering between us and our peer + * for v2 channel ids; is ordering given us/them */ + u8 node_order; + /* Features they offered */ u8 *their_features; @@ -553,20 +557,22 @@ static bool setup_channel_funder(struct state *state) * could do it for the we-are-funding case. */ state->accepter_funding = AMOUNT_SAT(0); set_reserve(state); + + /*~ Grab a random ID until the funding tx is created (we can't do that + * until we know their funding_pubkey) */ + /* Only applies to v1 opens; v2's use the basepoint to discern + * channel_id. */ + temporary_channel_id(&state->channel_id); +#if DEVELOPER + /* --dev-force-tmp-channel-id specified */ + if (dev_force_tmp_channel_id) + state->channel_id = *dev_force_tmp_channel_id; +#endif } /* Initialize the msg queue */ state->funding_msg_queue = tal_arr(state, u8 *, 0); - /*~ Grab a random ID until the funding tx is created (we can't do that - * until we know their funding_pubkey) */ - temporary_channel_id(&state->channel_id); - -#if DEVELOPER - /* --dev-force-tmp-channel-id specified */ - if (dev_force_tmp_channel_id) - state->channel_id = *dev_force_tmp_channel_id; -#endif /* BOLT #2: * * The sending node: @@ -741,7 +747,6 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) "experimental features. %s", tal_hex(msg, msg)); #endif - } else { /* BOLT #2: * @@ -791,6 +796,21 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) "Parsing accept_channel %s", tal_hex(msg, msg)); } + + /* + * BOLT-FIXME #2 + * + * For channels established using the v2 protocol, the `channel_id` is the + * SHA256(lesser-peers-revocation-basepoint || greater-peers-revocation-basepoint), + * where the lesser and greater peer is based off the order of their respective + * node id, using the compressed key notation. + */ + if (state->use_v2) + derive_channel_id2(&state->channel_id, + &state->our_points.revocation, + &state->their_points.revocation, + state->node_order); + /* BOLT #2: * * The `temporary_channel_id` MUST be the same as the @@ -799,7 +819,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) /* In this case we exit, since we don't know what's going on. */ peer_failed(state->pps, &state->channel_id, - "accept_channel ids don't match: sent %s got %s", + "accept_channel ids don't match: expected %s got %s", type_to_string(msg, struct channel_id, &id_in), type_to_string(msg, struct channel_id, &state->channel_id)); @@ -1507,10 +1527,6 @@ static u8 *funder_finalize_channel_setup2(struct state *state, &state->channel_id, "We could not create channel with given config"); - /* We switch over to using the funding_tx derived channel_id */ - derive_channel_id(&state->channel_id, - &state->funding_txid, state->funding_txout); - /* We need to send them the signatures for their commitment tx */ remote_commit = initial_channel_tx(state, &wscript, state->channel, &state->first_per_commitment_point[REMOTE], @@ -2208,6 +2224,19 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) state->upfront_shutdown_script[LOCAL]; } + /* + * BOLT-FIXME #2 + * + * For channels established using the v2 protocol, the `channel_id` is the + * SHA256(lesser-peers-revocation-basepoint || greater-peers-revocation-basepoint), + * where the lesser and greater peer is based off the order of their respective + * node id, using the compressed key notation. + */ + derive_channel_id2(&state->channel_id, + &state->our_points.revocation, + &state->their_points.revocation, + state->node_order); + msg = towire_accept_channel2(tmpctx, &state->channel_id, state->accepter_funding, state->localconf.dust_limit, @@ -2944,7 +2973,8 @@ static u8 *handle_master_in(struct state *state) switch (t) { case WIRE_OPENING_FUNDER_START: - if (!fromwire_opening_funder_start(tmpctx, msg, &state->opener_funding, + if (!fromwire_opening_funder_start(tmpctx, msg, + &state->opener_funding, &state->push_msat, &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw, @@ -3041,6 +3071,7 @@ int main(int argc, char *argv[]) /*~ The very first thing we read from lightningd is our init msg */ msg = wire_sync_read(tmpctx, REQ_FD); if (!fromwire_opening_init(state, msg, + &state->node_order, &chainparams, &state->our_features, &state->localconf, diff --git a/wire/extracted_peer_experimental_f6f06187472f7d8e5806b6d127e00f8fc297a4cb b/wire/extracted_peer_experimental_f6f06187472f7d8e5806b6d127e00f8fc297a4cb new file mode 100644 index 000000000000..4f99f6481121 --- /dev/null +++ b/wire/extracted_peer_experimental_f6f06187472f7d8e5806b6d127e00f8fc297a4cb @@ -0,0 +1,119 @@ +--- wire/extracted_peer_wire_csv 2020-01-30 14:52:42.094469728 -0600 ++++ - 2020-02-20 12:06:27.071294111 -0600 +@@ -31,6 +31,48 @@ + tlvdata,n2,tlv1,amount_msat,tu64, + tlvtype,n2,tlv2,11 + tlvdata,n2,tlv2,cltv_expiry,tu32, ++msgtype,tx_add_input,66 ++msgdata,tx_add_input,channel_id,channel_id, ++msgdata,tx_add_input,serial_id,u16, ++msgdata,tx_add_input,sats,u64, ++msgdata,tx_add_input,prevtx_txid,sha256, ++msgdata,tx_add_input,prevtx_vout,u32, ++msgdata,tx_add_input,prevtx_scriptpubkey_len,u16, ++msgdata,tx_add_input,prevtx_scriptpubkey,byte,prevtx_scriptpubkey_len ++msgdata,tx_add_input,max_witness_len,u16, ++msgdata,tx_add_input,scriptlen,u16, ++msgdata,tx_add_input,script,byte,scriptlen ++msgdata,tx_add_input,tlvs,tx_add_input_tlvs, ++tlvtype,tx_add_input_tlvs,podle_proof,2 ++tlvdata,tx_add_input_tlvs,podle_proof,p,point, ++tlvdata,tx_add_input_tlvs,podle_proof,p2,point, ++tlvdata,tx_add_input_tlvs,podle_proof,e,sha256, ++tlvdata,tx_add_input_tlvs,podle_proof,sig,byte,32 ++msgtype,tx_add_output,67 ++msgdata,tx_add_output,channel_id,channel_id, ++msgdata,tx_add_output,serial_id,u16, ++msgdata,tx_add_output,sats,u64, ++msgdata,tx_add_output,scriptlen,u16, ++msgdata,tx_add_output,script,byte,scriptlen ++msgtype,tx_remove_input,68 ++msgdata,tx_remove_input,channel_id,channel_id, ++msgdata,tx_remove_input,serial_id,u16, ++msgtype,tx_remove_output,69 ++msgdata,tx_remove_output,channel_id,channel_id, ++msgdata,tx_remove_output,serial_id,u16, ++msgtype,tx_complete,70 ++msgdata,tx_complete,channel_id,channel_id, ++msgtype,tx_signatures,71 ++msgdata,tx_signatures,channel_id,channel_id, ++msgdata,tx_signatures,txid,sha256, ++msgdata,tx_signatures,num_witnesses,u16, ++msgdata,tx_signatures,witness_stack,witness_stack,num_witnesses ++subtype,witness_stack ++subtypedata,witness_stack,num_input_witness,u16, ++subtypedata,witness_stack,witness_element,witness_element,num_input_witness ++subtype,witness_element ++subtypedata,witness_element,len,u16, ++subtypedata,witness_element,witness,byte,len + msgtype,open_channel,32 + msgdata,open_channel,chain_hash,chain_hash, + msgdata,open_channel,temporary_channel_id,byte,32 +@@ -80,6 +122,55 @@ + msgtype,funding_locked,36 + msgdata,funding_locked,channel_id,channel_id, + msgdata,funding_locked,next_per_commitment_point,point, ++msgtype,open_channel2,64 ++msgdata,open_channel2,chain_hash,chain_hash, ++msgdata,open_channel2,locktime,u32, ++msgdata,open_channel2,podle_h2,sha256, ++msgdata,open_channel2,feerate_per_kw_funding,u32, ++msgdata,open_channel2,funding_satoshis,u64, ++msgdata,open_channel2,push_msat,u64, ++msgdata,open_channel2,dust_limit_satoshis,u64, ++msgdata,open_channel2,max_htlc_value_in_flight_msat,u64, ++msgdata,open_channel2,htlc_minimum_msat,u64, ++msgdata,open_channel2,feerate_per_kw,u32, ++msgdata,open_channel2,to_self_delay,u16, ++msgdata,open_channel2,max_accepted_htlcs,u16, ++msgdata,open_channel2,funding_pubkey,point, ++msgdata,open_channel2,revocation_basepoint,point, ++msgdata,open_channel2,payment_basepoint,point, ++msgdata,open_channel2,delayed_payment_basepoint,point, ++msgdata,open_channel2,htlc_basepoint,point, ++msgdata,open_channel2,first_per_commitment_point,point, ++msgdata,open_channel2,channel_flags,byte, ++msgdata,open_channel2,opening_tlv,opening_tlvs, ++tlvtype,opening_tlvs,option_upfront_shutdown_script,1 ++tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, ++tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++msgtype,accept_channel2,65 ++msgdata,accept_channel2,channel_id,channel_id, ++msgdata,accept_channel2,funding_satoshis,u64, ++msgdata,accept_channel2,dust_limit_satoshis,u64, ++msgdata,accept_channel2,max_htlc_value_in_flight_msat,u64, ++msgdata,accept_channel2,htlc_minimum_msat,u64, ++msgdata,accept_channel2,minimum_depth,u32, ++msgdata,accept_channel2,to_self_delay,u16, ++msgdata,accept_channel2,max_accepted_htlcs,u16, ++msgdata,accept_channel2,funding_pubkey,point, ++msgdata,accept_channel2,revocation_basepoint,point, ++msgdata,accept_channel2,payment_basepoint,point, ++msgdata,accept_channel2,delayed_payment_basepoint,point, ++msgdata,accept_channel2,htlc_basepoint,point, ++msgdata,accept_channel2,first_per_commitment_point,point, ++msgdata,accept_channel2,accept_tlv,accept_tlvs, ++tlvtype,accept_tlvs,option_upfront_shutdown_script,1 ++tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, ++tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++msgtype,init_rbf,72 ++msgdata,init_rbf,channel_id,channel_id, ++msgdata,init_rbf,funding_satoshis,u64, ++msgdata,init_rbf,locktime,u32, ++msgdata,init_rbf,feerate_per_kw,u32, ++msgdata,init_rbf,fee_step,u8, + msgtype,shutdown,38 + msgdata,shutdown,channel_id,channel_id, + msgdata,shutdown,len,u16, +@@ -167,6 +258,11 @@ + msgdata,channel_update,fee_base_msat,u32, + msgdata,channel_update,fee_proportional_millionths,u32, + msgdata,channel_update,htlc_maximum_msat,u64,,option_channel_htlc_max ++msgtype,blacklist_podle,260 ++msgdata,blacklist_podle,signature,signature, ++msgdata,blacklist_podle,node_id,point, ++msgdata,blacklist_podle,podle_h2,sha256, ++msgdata,blacklist_podle,timestamp,u32, + msgtype,query_short_channel_ids,261,gossip_queries + msgdata,query_short_channel_ids,chain_hash,chain_hash, + msgdata,query_short_channel_ids,len,u16, diff --git a/wire/fromwire.c b/wire/fromwire.c index 56f91e4b8e9c..fde4848882c8 100644 --- a/wire/fromwire.c +++ b/wire/fromwire.c @@ -349,7 +349,7 @@ char *fromwire_wirestring(const tal_t *ctx, const u8 **cursor, size_t *max) REGISTER_TYPE_TO_HEXSTR(channel_id); -/* BOLT #2: +/* BOLT-FIXME #2: * * This message introduces the `channel_id` to identify the channel. It's * derived from the funding transaction by combining the `funding_txid` and @@ -364,6 +364,31 @@ void derive_channel_id(struct channel_id *channel_id, channel_id->id[sizeof(*channel_id)-2] ^= txout >> 8; channel_id->id[sizeof(*channel_id)-1] ^= txout; } +/* + * BOLT-FIXME #2 + * + * For channels established using the v2 protocol, the `channel_id` is the + * SHA256(lesser-peers-revocation-basepoint || greater-peers-revocation-basepoint), + * where the lesser and greater peer is based off the order of their respective + * node id, using the compressed key notation. + */ +void derive_channel_id2(struct channel_id *channel_id, + const struct pubkey *node_1_rev_base, + const struct pubkey *node_2_rev_base, + int comparison_result) +{ + struct sha256 h; + u8 ids[2 * PUBKEY_CMPR_LEN]; + size_t diff_1 = comparison_result < 0 ? 0 : PUBKEY_CMPR_LEN, + diff_2 = comparison_result >= 0 ? 0 : PUBKEY_CMPR_LEN; + + pubkey_to_der(ids + diff_1, node_1_rev_base); + pubkey_to_der(ids + diff_2, node_2_rev_base); + sha256(&h, ids, sizeof(ids)); + + BUILD_ASSERT(sizeof(*channel_id) == sizeof(h.u.u8)); + memcpy(channel_id, h.u.u8, sizeof(h.u.u8)); +} struct bitcoin_tx *fromwire_bitcoin_tx(const tal_t *ctx, const u8 **cursor, size_t *max) diff --git a/wire/test/Makefile b/wire/test/Makefile index 54bb5c6823a9..7b1f89a1860e 100644 --- a/wire/test/Makefile +++ b/wire/test/Makefile @@ -11,6 +11,8 @@ WIRE_TEST_COMMON_OBJS := \ wire/test/run-peer-wire: common/bigsize.o +wire/test/run-fromwire: common/node_id.o + update-mocks: $(WIRE_TEST_SRC:%=update-mocks/%) $(WIRE_TEST_PROGRAMS): $(WIRE_TEST_COMMON_OBJS) $(BITCOIN_OBJS) diff --git a/wire/test/run-fromwire.c b/wire/test/run-fromwire.c new file mode 100644 index 000000000000..5058f09abbb2 --- /dev/null +++ b/wire/test/run-fromwire.c @@ -0,0 +1,106 @@ +#include + +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for amount_asset_is_main */ +bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); } +/* Generated stub for amount_asset_to_sat */ +struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } +/* Generated stub for amount_sat_add */ + bool amount_sat_add(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_eq */ +bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } +/* Generated stub for amount_sat_sub */ + bool amount_sat_sub(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); } +/* Generated stub for bigsize_get */ +size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNNEEDED) +{ fprintf(stderr, "bigsize_get called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +struct channel_id_case { + const char *node_id_1; + const char *node_id_2; + const char *basepoint_1; + const char *basepoint_2; + const char *expected_channel_id; + bool succeeds; +}; + +const struct channel_id_case CASES[3] = { + { + .node_id_1 = "0281843858cc0db1fb200d039959d37d73506c930defefbce500735657ab5e8028", + .node_id_2 = "0266d801ddc5ab61892a55fbad0f5f997b798f9f967ba16a442d3b59802b22a4ef", + .basepoint_1 = "03e963488c5b152dc11a81c9314c1cb4b079111e18447a3be43c54a18c01fd2e9c", + .basepoint_2 = "02b5da66d2410c36a7fc705e9310eaa3cec6d7734e34d08cca73f172e26a5209b8", + .expected_channel_id = "30c551f400a3655146579a31b0602ed4d900ee52d7db209a3114eed690258ee0", + .succeeds = true, + }, + { + .node_id_1 = "029d2a3d899632b4ec1c8269d1e96dd92739b87d9d5a63cdd016c06648a99d3f82", + .node_id_2 = "02ffe66ef77ca3b6a459c3c1a19878cbe935088bd9dd7d7da0448b46a2e5daf00f", + .basepoint_1 = "0283bb6d3c637e73e80505661b2c22966706993f4899444889573c8f116731a965", + .basepoint_2 = "03512fa110c4b3a54069685107c7107a6abf1fc50d974a4e1feb80681b6da6b5a3", + .expected_channel_id = "a1caa6ca96fa9a53e12b908bf10099e49f42ee067f673837588b37463832cecb", + .succeeds = true, + }, + { + .node_id_1 = "02ffe66ef77ca3b6a459c3c1a19878cbe935088bd9dd7d7da0448b46a2e5daf00f", + .node_id_2 = "029d2a3d899632b4ec1c8269d1e96dd92739b87d9d5a63cdd016c06648a99d3f82", + .basepoint_1 = "0283bb6d3c637e73e80505661b2c22966706993f4899444889573c8f116731a965", + .basepoint_2 = "03512fa110c4b3a54069685107c7107a6abf1fc50d974a4e1feb80681b6da6b5a3", + .expected_channel_id = "82ab63012bc09293516e424d146442d7d1c7458a256467e2ccb9fe93c90c7379", + .succeeds = false, + }, +}; + +static void test_channel_id2(const tal_t *ctx) +{ + size_t i, len = ARRAY_SIZE(CASES); + struct channel_id_case c; + struct node_id n1, n2; + struct pubkey bp1, bp2; + struct channel_id a, b; + u8 *hex; + + for (i = 0; i < len; i++) { + c = CASES[i]; + + if (!node_id_from_hexstr(c.node_id_1, strlen(c.node_id_1), &n1)) + abort(); + if (!node_id_from_hexstr(c.node_id_2, strlen(c.node_id_2), &n2)) + abort(); + if (!pubkey_from_hexstr(c.basepoint_1, strlen(c.basepoint_1), &bp1)) + abort(); + if (!pubkey_from_hexstr(c.basepoint_2, strlen(c.basepoint_2), &bp2)) + abort(); + + hex = tal_hexdata(ctx, c.expected_channel_id, + strlen(c.expected_channel_id)); + assert(sizeof(a.id) == tal_bytelen(hex)); + memcpy(a.id, hex, sizeof(a.id)); + + derive_channel_id2(&b, &bp1, &bp2, node_id_cmp(&n1, &n2)); + assert(channel_id_eq(&a, &b) == c.succeeds); + } +} + +int main(void) +{ + const tal_t *ctx = tal(NULL, u8); + setup_locale(); + + test_channel_id2(ctx); + + tal_free(ctx); +} diff --git a/wire/wire.h b/wire/wire.h index 583ebb99baed..986e1f2a2106 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -45,6 +45,11 @@ typedef bigsize varint; void derive_channel_id(struct channel_id *channel_id, const struct bitcoin_txid *txid, u16 txout); +void derive_channel_id2(struct channel_id *channel_id, + const struct pubkey *node_1_rev_base, + const struct pubkey *node_2_rev_base, + int comparison_result); + /* Read the type; returns -1 if not long enough. cursor is a tal ptr. */ int fromwire_peektype(const u8 *cursor); const void *fromwire_fail(const u8 **cursor, size_t *max); From 1ce1051bfec9fedd95f6812134248a15e274baa0 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 11 Mar 2020 19:15:33 -0500 Subject: [PATCH 116/131] tx_locktime: port over locktime logic from bitcoind routine for calculating the locktime for a transaction, based on the wallet.cpp method in bitcoind 9 times out of 10, will use the current tip height, 10% of the time will use a randomly chosen height within 100 of tip --- lightningd/tx_locktime.c | 27 +++++++++++++++++++++++++++ lightningd/tx_locktime.h | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 lightningd/tx_locktime.c create mode 100644 lightningd/tx_locktime.h diff --git a/lightningd/tx_locktime.c b/lightningd/tx_locktime.c new file mode 100644 index 000000000000..70a0429d6911 --- /dev/null +++ b/lightningd/tx_locktime.c @@ -0,0 +1,27 @@ +#include +#include + +/* Cribbed from bitcoind's wallet.cpp GetLocktimeForNewTransaction */ +u32 locktime_for_new_tx(struct chain_topology *topology) +{ + u32 locktime; + + if (!topology_synced(topology)) + return 0; + + locktime = topology->tip->height; + + /* Occasionally randomly pick a locktime even further back, so + * that transactions that are delayed after signing for whatever reason, + * e.g. high-latency mix networks and some CoinJoin implementations, have + * better privacy. */ + if (pseudorand(10) == 0) { + locktime = locktime - pseudorand(100); + if (locktime < 0) + locktime = 0; + } + + assert(locktime <= topology->tip->height); + assert(locktime < LOCKTIME_THRESHOLD); + return locktime; +} diff --git a/lightningd/tx_locktime.h b/lightningd/tx_locktime.h new file mode 100644 index 000000000000..5a466e50fba5 --- /dev/null +++ b/lightningd/tx_locktime.h @@ -0,0 +1,21 @@ +#ifndef LIGHTNING_LIGHTNINGD_TX_LOCKTIME_H +#define LIGHTNING_LIGHTNINGD_TX_LOCKTIME_H + +#include "config.h" +#include + +/* Tue Nov 5 00:53:20 1985 UTC */ +#define LOCKTIME_THRESHOLD 500000000 + +/* locktime_for_new_tx - given a current height, return the locktime + * a new tx should lock to + * + * meant to 1) discourage fee sniping on the miner's part and 2) + * mimic the logic of bitcoind's locktime selection + * + * note that if our chain is lagging behind tip, we use zero to + * prevent leaking a 'locktime fingerprint' + */ +u32 locktime_for_new_tx(struct chain_topology *topology); + +#endif /* LIGHTNING_LIGHTNINGD_TX_LOCKTIME_H */ From 855ad9229764e8fb6e2b21f6af1afdc12fedab43 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 11 Mar 2020 19:18:02 -0500 Subject: [PATCH 117/131] df: wire up using adaptive locktime for dual-funding --- common/funding_tx.c | 3 ++- common/funding_tx.h | 2 ++ common/test/run-funding_tx_dual.c | 1 + hsmd/hsm_wire.csv | 1 + hsmd/hsmd.c | 4 +++- lightningd/Makefile | 1 + lightningd/opening_control.c | 8 ++++++++ openingd/opening_wire.csv | 1 + openingd/openingd.c | 12 +++++++++--- 9 files changed, 28 insertions(+), 5 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 219beb6733dc..157afb31b590 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -222,6 +222,7 @@ static void add_outputs(struct bitcoin_tx *tx, struct output_info **outputs, struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, const struct chainparams *chainparams, + u32 tx_locktime, u16 *outnum, u32 feerate_kw_funding, struct amount_sat *opener_funding, @@ -362,7 +363,7 @@ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, assert(output_count > 0); } - tx = bitcoin_tx(ctx, chainparams, input_count, output_count, 0); + tx = bitcoin_tx(ctx, chainparams, input_count, output_count, tx_locktime); /* Add the funding output */ wscript = bitcoin_redeem_2of2(tx, local_fundingkey, remote_fundingkey); diff --git a/common/funding_tx.h b/common/funding_tx.h index 3d0dd71c29b5..1f718b38a703 100644 --- a/common/funding_tx.h +++ b/common/funding_tx.h @@ -72,6 +72,7 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, * funding_tx: create a P2WSH funding transaction for a channel. * @ctx: context to tal from. * @chainparams: (in) the params for the resulting transaction. + * @locktime: (in) blockheight to use for the tx locktime * @outnum: (out) txout which is the funding output. * @feerate_kw_funding: (in) feerate for the funding transaction * @opener_funding: (in/out) funding amount contributed by opener @@ -88,6 +89,7 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx, */ struct bitcoin_tx *dual_funding_funding_tx(const tal_t *ctx, const struct chainparams *chainparams, + u32 tx_locktime, u16 *outnum, u32 feerate_kw_funding, struct amount_sat *opener_funding, diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index 22b67df77460..40e8b7b257f0 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -818,6 +818,7 @@ int main(void) /* Note that dust_limit is set to 546, via chainparams */ funding = dual_funding_funding_tx(tmpctx, chainparams, + 0, /* examples all have locktime at 0 */ &outnum, test.feerate, &test.opener_funding, test.accepter_funding, diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index 442d8e9b43f3..c2d85f324d85 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -67,6 +67,7 @@ msgtype,hsm_dual_funding_sigs,40 msgdata,hsm_dual_funding_sigs,num_utxos,u16, msgdata,hsm_dual_funding_sigs,our_utxos,utxo,num_utxos msgdata,hsm_dual_funding_sigs,feerate_kw_funding,u32, +msgdata,hsm_dual_funding_sigs,tx_locktime,u32, msgdata,hsm_dual_funding_sigs,opener_funding,amount_sat, msgdata,hsm_dual_funding_sigs,accepter_funding,amount_sat, msgdata,hsm_dual_funding_sigs,num_opener_inputs,u16, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 37ad858ef0c4..46bb95a032e5 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1648,7 +1648,7 @@ static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, { size_t i = 0, j; struct bitcoin_tx *tx; - u32 feerate_kw_funding, offset; + u32 feerate_kw_funding, offset, tx_locktime; struct pubkey local_pubkey, remote_pubkey; struct amount_sat opener_funding, accepter_funding; struct input_info **opener_inputs, **accepter_inputs; @@ -1662,6 +1662,7 @@ static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, msg_in, &our_utxos, &feerate_kw_funding, + &tx_locktime, &opener_funding, &accepter_funding, &opener_inputs, @@ -1683,6 +1684,7 @@ static struct io_plan *handle_sign_dual_funding_tx(struct io_conn *conn, tx = dual_funding_funding_tx(tmpctx, c->chainparams, + tx_locktime, NULL, feerate_kw_funding, &opener_funding, diff --git a/lightningd/Makefile b/lightningd/Makefile index 7d8444abdac9..a8724e2576c2 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -102,6 +102,7 @@ LIGHTNINGD_SRC := \ lightningd/plugin.c \ lightningd/plugin_control.c \ lightningd/plugin_hook.c \ + lightningd/tx_locktime.c \ lightningd/subd.c \ lightningd/watch.c diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index c7221a2b2146..3dbf2999249e 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1887,6 +1888,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, struct channel *channel; bool *announce_channel; u32 *feerate_per_kw; + u32 locktime; u8 *msg = NULL; struct amount_sat *amount; @@ -1976,6 +1978,11 @@ static struct command_result *json_fund_channel_start(struct command *cmd, type_to_string(fc, struct node_id, id)); } + /* BOLT-b746cacbde53ea6170ec43ee3eff46fbb4139bfd #2 + * `locktime` is the locktime for the funding transaction. + */ + locktime = locktime_for_new_tx(cmd->ld->topology); + peer->uncommitted_channel->fc = tal_steal(peer->uncommitted_channel, fc); fc->uc = peer->uncommitted_channel; @@ -1992,6 +1999,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, msg = towire_opening_funder_start(NULL, *amount, + locktime, fc->push, fc->our_upfront_shutdown_script, *feerate_per_kw, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index f611352df059..5f4c1225691f 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -87,6 +87,7 @@ msgdata,opening_funder_reply,shutdown_scriptpubkey,u8,shutdown_len # master->openingd: start channel establishment for a funding tx msgtype,opening_funder_start,6002 msgdata,opening_funder_start,funding_satoshis,amount_sat, +msgdata,opening_funder_start,tx_locktime,u32, msgdata,opening_funder_start,push_msat,amount_msat, msgdata,opening_funder_start,len_upfront,u16, msgdata,opening_funder_start,upfront_shutdown_script,u8,len_upfront diff --git a/openingd/openingd.c b/openingd/openingd.c index 76bf1bd62989..215c5772bfab 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -127,6 +127,9 @@ struct state { struct amount_sat accepter_funding; u32 feerate_per_kw_funding; + /* Locktime for funding transaction */ + u32 locktime; + /* List of queued add input/output/completes. * These get queued up while we're in transition * between fundchannel_start and fundchannel_complete @@ -636,7 +639,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) state->feerate_per_kw_funding = state->feerate_per_kw; msg = towire_open_channel2(NULL, &chainparams->genesis_blockhash, - 0, /* FIXME: use real locktime */ + state->locktime, NULL, /* FIXME: use real podleh2 */ state->feerate_per_kw_funding, state->opener_funding, @@ -1477,6 +1480,7 @@ static u8 *funder_finalize_channel_setup2(struct state *state, /* Build the funding transaction */ funding_tx = dual_funding_funding_tx(state, chainparams, + state->locktime, &state->funding_txout, state->feerate_per_kw_funding, &state->opener_funding, @@ -2125,13 +2129,12 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) const u8 *wscript; u8 channel_flags; u8 *msg; - u32 locktime; struct sha256 podle_h2; struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); if (!fromwire_open_channel2(open_channel2_msg, &chain_hash, - &locktime, + &state->locktime, &podle_h2, &state->feerate_per_kw_funding, &state->opener_funding, @@ -2275,6 +2278,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) /* Build the funding tx */ funding_tx = dual_funding_funding_tx(state, chainparams, + state->locktime, &state->funding_txout, state->feerate_per_kw_funding, &state->opener_funding, @@ -2418,6 +2422,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) msg = towire_hsm_dual_funding_sigs(tmpctx, cast_const2(const struct utxo **, utxos), state->feerate_per_kw_funding, + state->locktime, state->opener_funding, state->accepter_funding, cast_const2(const struct input_info **, their_inputs), @@ -2975,6 +2980,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_OPENING_FUNDER_START: if (!fromwire_opening_funder_start(tmpctx, msg, &state->opener_funding, + &state->locktime, &state->push_msat, &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw, From 5d018d12f314fef625bfb52822bec70f2203561a Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 11 Mar 2020 19:18:56 -0500 Subject: [PATCH 118/131] df: use RBF'able sequence for all inputs in dual-funded txs --- bitcoin/tx.h | 1 + common/funding_tx.c | 6 +++++- common/test/run-funding_tx_dual.c | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/bitcoin/tx.h b/bitcoin/tx.h index cac9193366a4..3dfa15427fab 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -11,6 +11,7 @@ #include #define BITCOIN_TX_DEFAULT_SEQUENCE 0xFFFFFFFF +#define BITCOIN_TX_RBF_SEQUENCE 0xFFFFFFFD struct witscript { u8 *ptr; diff --git a/common/funding_tx.c b/common/funding_tx.c index 157afb31b590..1a8e598ed55e 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -190,9 +190,13 @@ static bool calculate_output_value(struct output_info **outputs, static void add_inputs(struct bitcoin_tx *tx, struct input_info **inputs) { size_t i = 0; + + /* BOLT-b746cacbde53ea6170ec43ee3eff46fbb4139bfd #2 + * - Each input's sequence number is 0xFEFFFFFF (little endian). + */ for (i = 0; i < tal_count(inputs); i++) { bitcoin_tx_add_input(tx, &inputs[i]->prevtx_txid, inputs[i]->prevtx_vout, - BITCOIN_TX_DEFAULT_SEQUENCE, + BITCOIN_TX_RBF_SEQUENCE, inputs[i]->sats, inputs[i]->script); } } diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index 40e8b7b257f0..f1924e725b8d 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -218,7 +218,7 @@ static struct test_case test1(const tal_t *ctx) output_two->script = hex_to_u8(ctx, "001444cb0c39f93ecc372b5851725bd29d865d333b10"); accepter_outputs[0] = output_two; - char *expected_tx_str = "0200000004b932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430000000000ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430100000023220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430200000000ffffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430300000017160014fbb4db9d85fba5e301f4399e3038928e44e37d32ffffffff03ea7f0100000000001600141ca1cca8855bad6bc1ea5436edd8cff10b7e448b00c2eb0b0000000016001444cb0c39f93ecc372b5851725bd29d865d333b106081ad2f00000000220020297b92c238163e820b82486084634b4846b86a3c658d87b9384192e6bea98ec500000000"; + char *expected_tx_str = "0200000004b932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430000000000feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430100000023220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430200000000feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430300000017160014fbb4db9d85fba5e301f4399e3038928e44e37d32feffffff03ea7f0100000000001600141ca1cca8855bad6bc1ea5436edd8cff10b7e448b00c2eb0b0000000016001444cb0c39f93ecc372b5851725bd29d865d333b106081ad2f00000000220020297b92c238163e820b82486084634b4846b86a3c658d87b9384192e6bea98ec500000000"; struct test_case test1 = { .feerate = 1000, .opener_inputs = opener_inputs, @@ -342,7 +342,7 @@ static struct test_case test2(const tal_t *ctx) struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 253, .opener_inputs = opener_inputs, @@ -377,7 +377,7 @@ static struct test_case test3(const tal_t *ctx) struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 253, .opener_inputs = opener_inputs, @@ -412,7 +412,7 @@ static struct test_case test_no_change(const tal_t *ctx) struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5d8a4160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5d8a4160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 1000, .opener_inputs = opener_inputs, @@ -448,7 +448,7 @@ static struct test_case test_change(const tal_t *ctx) struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff046403000000000000160014d295f76da2319791f36df5759e45b15d5e10522188130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5f8a0160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff046403000000000000160014d295f76da2319791f36df5759e45b15d5e10522188130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5f8a0160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 1000, .opener_inputs = opener_inputs, @@ -484,7 +484,7 @@ static struct test_case test_change_trimmed(const tal_t *ctx) struct output_info **accepter_outputs = tal_arr(ctx, struct output_info *, 1); accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d56881160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d56881160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 10000, .opener_inputs = opener_inputs, @@ -522,7 +522,7 @@ static struct test_case test_dust_change_trimmed(const tal_t *ctx) accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff0364190000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d588a2160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0364190000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d588a2160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 100, .opener_inputs = opener_inputs, @@ -616,7 +616,7 @@ static struct test_case test_one_input(const tal_t *ctx) opener_inputs[0] = input_one(ctx, 1, txid_str_one); - char *expected_tx_str = "02000000013f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff01399f070000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000013f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff01399f070000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 1000, .opener_inputs = opener_inputs, @@ -648,7 +648,7 @@ static struct test_case test_two_input(const tal_t *ctx) opener_inputs[0] = input_one(ctx, 1, txid_str_one); opener_inputs[1] = input_three(ctx, 2, txid_str_one); - char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000ffffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0200000000ffffffff0188811e0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0200000000feffffff0188811e0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 1000, .opener_inputs = opener_inputs, @@ -688,7 +688,7 @@ static struct test_case test_full_set(const tal_t *ctx) accepter_outputs[0] = output_two(ctx, 10000); - char *expected_tx_str = "020000000451e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070000000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070100000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070200000000ffffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070300000000ffffffff0488130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5cae31c0000000000160014d295f76da2319791f36df5759e45b15d5e10522150262f0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + char *expected_tx_str = "020000000451e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070000000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070100000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070200000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070300000000feffffff0488130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5cae31c0000000000160014d295f76da2319791f36df5759e45b15d5e10522150262f0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; struct test_case test = { .feerate = 1000, .opener_inputs = opener_inputs, From c5941377ae64a75243b2597a5ef9d1d4aa1a2106 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 1 May 2020 18:04:05 -0500 Subject: [PATCH 119/131] bcli-bugfix: pass along entire script sizeof doesn't give the correct length, instead use tal_hex which will measure the script length correctly --- plugins/bcli.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/bcli.c b/plugins/bcli.c index 215408ebe313..5698f827aec9 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -381,8 +381,7 @@ static struct command_result *process_getutxout(struct bitcoin_cli *bcli) response = jsonrpc_stream_success(bcli->cmd); json_add_amount_sat_only(response, "amount", output.amount); - json_add_string(response, "script", - tal_hexstr(response, output.script, sizeof(output.script))); + json_add_string(response, "script", tal_hex(response, output.script)); return command_finished(bcli->cmd, response); } From 24c31e3dfb04011dd77597a32cde1e3c9c252a0b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 1 May 2020 18:24:39 -0500 Subject: [PATCH 120/131] wire: suppress printout from patch command We were using a 'quiet' flag, but that broke on the busybox implementation of `patch`, since they don't support it. Instead, we use the universally supported "pipe to /dev/null" approach Suggested-By: @rustyrussell --- wire/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wire/Makefile b/wire/Makefile index 92bec190bdc8..651a4dfda462 100644 --- a/wire/Makefile +++ b/wire/Makefile @@ -53,10 +53,10 @@ EXPERIMENTAL_PEER_PATCHES := $(wildcard wire/extracted_peer_experimental_*) EXPERIMENTAL_ONION_PATCHES := $(wildcard wire/extracted_onion_experimental_*) wire/gen_peer_wire_csv: wire/extracted_peer_wire_csv $(EXPERIMENTAL_PEER_PATCHES) - @set -e; trap "rm -f $@.$$$$" 0; cp $< $@.$$$$; for exp in $(EXPERIMENTAL_PEER_PATCHES); do patch $@.$$$$ $$exp; done; mv $@.$$$$ $@ + @set -e; trap "rm -f $@.$$$$" 0; cp $< $@.$$$$; for exp in $(EXPERIMENTAL_PEER_PATCHES); do patch $@.$$$$ $$exp >/dev/null ; done; mv $@.$$$$ $@ wire/gen_onion_wire_csv: wire/extracted_onion_wire_csv $(EXPERIMENTAL_ONION_PATCHES) - @set -e; trap "rm -f $@.$$$$" 0; cp $< $@.$$$$; for exp in $(EXPERIMENTAL_ONION_PATCHES); do patch $@.$$$$ $$exp; done; mv $@.$$$$ $@ + @set -e; trap "rm -f $@.$$$$" 0; cp $< $@.$$$$; for exp in $(EXPERIMENTAL_ONION_PATCHES); do patch $@.$$$$ $$exp; done >/dev/null ; mv $@.$$$$ $@ else # /* EXPERIMENTAL_FEATURES */ wire/gen_peer_wire_csv: wire/extracted_peer_wire_csv From 0e796e590625a6128a5509dc5b73a6e96ac4ca46 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:00:55 -0500 Subject: [PATCH 121/131] fixup! df: wire in feature flag --- common/features.c | 2 +- common/features.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/common/features.c b/common/features.c index 421d7fa3015f..629efaffc512 100644 --- a/common/features.c +++ b/common/features.c @@ -73,7 +73,7 @@ static const struct feature_style feature_styles[] = { #endif { OPT_FUNDCHANNEL_V2, .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL, - [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, + [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL, [CHANNEL_FEATURE] = FEATURE_REPRESENT_AS_OPTIONAL} }, }; diff --git a/common/features.h b/common/features.h index 8fc10372564e..d1958dd520de 100644 --- a/common/features.h +++ b/common/features.h @@ -114,7 +114,6 @@ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES); * | Bits | Name |... * | 28/29 | `option_dual_fund` |... */ -/* FIXME: update the RFC to match */ -#define OPT_FUNDCHANNEL_V2 18 +#define OPT_FUNDCHANNEL_V2 28 #endif /* LIGHTNING_COMMON_FEATURES_H */ From b444ece061412dc7c67eacb3a0edd2ba511917e4 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:02:08 -0500 Subject: [PATCH 122/131] fixup! df: update to 'interactive tx construction' draft protocols --- common/funding_tx.c | 8 ++------ common/test/run-funding_tx.c | 4 ++++ common/test/run-funding_tx_dual.c | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/common/funding_tx.c b/common/funding_tx.c index 1a8e598ed55e..528b917bc598 100644 --- a/common/funding_tx.c +++ b/common/funding_tx.c @@ -438,18 +438,14 @@ void towire_input_info(u8 **pptr, const struct input_info *input_info) struct input_info *fromwire_input_info(const tal_t *ctx, const u8 **ptr, size_t *max) { struct input_info *input = tal(ctx, struct input_info); - u16 prevtx_scriptlen; - u16 script_len; input->serial_id = fromwire_u16(ptr, max); input->sats = fromwire_amount_sat(ptr, max); fromwire_bitcoin_txid(ptr, max, &input->prevtx_txid); input->prevtx_vout = fromwire_u32(ptr, max); - prevtx_scriptlen = fromwire_u16(ptr, max); - fromwire_u8_array(ptr, max, input->prevtx_scriptpubkey, prevtx_scriptlen); + input->prevtx_scriptpubkey = fromwire_tal_arrn(input, ptr, max, fromwire_u16(ptr, max)); input->max_witness_len = fromwire_u16(ptr, max); - script_len = fromwire_u16(ptr, max); - fromwire_u8_array(ptr, max, input->script, script_len); + input->script = fromwire_tal_arrn(input, ptr, max, fromwire_u16(ptr, max)); return input; } diff --git a/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 4c131cd5aaba..f85938b31e6a 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -37,6 +37,10 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n /* Generated stub for fromwire_pubkey */ void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_tal_arrn */ +u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED, + const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); } /* Generated stub for fromwire_u16 */ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u16 called!\n"); abort(); } diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c index f1924e725b8d..f89026a7c152 100644 --- a/common/test/run-funding_tx_dual.c +++ b/common/test/run-funding_tx_dual.c @@ -37,6 +37,10 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n /* Generated stub for fromwire_pubkey */ void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_tal_arrn */ +u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED, + const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); } /* Generated stub for fromwire_u16 */ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u16 called!\n"); abort(); } From a6993c55fd880c3f6eb6939ef57a219929537a99 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:03:23 -0500 Subject: [PATCH 123/131] df-interactive: there's no counts in the interactive protocol There's no counts for the interactive protocol, so we remove them. --- lightningd/opening_control.c | 9 ------- openingd/channel_establishment.h | 25 ------------------- openingd/openingd.c | 43 -------------------------------- 3 files changed, 77 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 3dbf2999249e..2ea71d0029b1 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1457,15 +1457,6 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS, 0, 0, UINT32_MAX, /* minconf 1 */ &fee_estimate, &change); - - /* Verify that we're still under the max remote that is allowed */ - if (tal_count(pf->utxos) > REMOTE_ACCEPTER_INPUT_LIMIT) { - log_info(openingd->log, - "Too many utxos selected (%zu), only %"PRIu16" allowed", - tal_count(pf->utxos), REMOTE_ACCEPTER_INPUT_LIMIT); - pf->utxos = tal_free(pf->utxos); - change = AMOUNT_SAT(0); - } } else { change = AMOUNT_SAT(0); pf->utxos = NULL; diff --git a/openingd/channel_establishment.h b/openingd/channel_establishment.h index c821b14bcda7..c20c5c25169c 100644 --- a/openingd/channel_establishment.h +++ b/openingd/channel_establishment.h @@ -2,31 +2,6 @@ #define LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H #include -/** - * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - if is the `opener`: - * ... - * - MUST NOT send a total count of more than 64 inputs, - * across all `funding_add_input` messages. - */ -#define REMOTE_OPENER_INPUT_LIMIT 64 - -/* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - * - if is the `accepter`: - * ... - * - MUST NOT send a total count of more than 16 inputs, - * across all `funding_add_input` messages. - */ -#define REMOTE_ACCEPTER_INPUT_LIMIT 16 - -/* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - if is the `accepter`: - * - MUST NOT send a total count of more than 8 outputs, - * across all `funding_add_output` messages. - */ -#define REMOTE_OUTPUT_LIMIT 8 - /* Designator for flagging what role a peer * is playing in channel establishment (v2) */ diff --git a/openingd/openingd.c b/openingd/openingd.c index 215c5772bfab..4bd64c4697c8 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1011,49 +1011,6 @@ static bool check_remote_input_outputs(struct state *state, size_t i = 0; u8 *msg, *err_msg, *wscript; - if (remote_role == OPENER) { - /** - * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - if is the `opener`: - * ... - * - MUST NOT send a total count of more than 64 inputs, - * across all `funding_add_input` messages. - */ - if (tal_count(remote_inputs) > REMOTE_OPENER_INPUT_LIMIT) - peer_failed(state->pps, - &state->channel_id, - "%zu surpassed maximum input limit %u", - tal_count(remote_inputs), - REMOTE_OPENER_INPUT_LIMIT); - } else { - /** - * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - if is the `accepter`: - * - MUST NOT send a total count of more than 16 inputs, across - * all `funding_add_input` messages. - */ - if (tal_count(remote_inputs) > REMOTE_ACCEPTER_INPUT_LIMIT) - peer_failed(state->pps, - &state->channel_id, - "Too many inputs added. " - "Received %ld inputs, max allowed is %d", - tal_count(remote_inputs), - REMOTE_ACCEPTER_INPUT_LIMIT); - - /* BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 - * - if is the `accepter`: - * - MUST NOT send a total count of more than 8 outputs, - * across all `funding_add_output` messages. - */ - if (tal_count(remote_outputs) > REMOTE_OUTPUT_LIMIT) - peer_failed(state->pps, - &state->channel_id, - "Too many outputs added. " - "Received %ld outputs, max allowed is %d", - tal_count(remote_outputs), - REMOTE_OUTPUT_LIMIT); - } - if (!check_remote_inputs(state, local_inputs, remote_inputs, &funding)) peer_failed(state->pps, &state->channel_id, From a8fb6120a89b218ce87672011ab0e2e528083eeb Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:04:25 -0500 Subject: [PATCH 124/131] interactive: the max is now wallet max, not bounded Since we're not limiting the number of inputs to a funding transaction, we now report the entire wallet's balance to the openchannel hook for the available_funds --- lightningd/opening_control.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 2ea71d0029b1..95a633c23855 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1560,13 +1560,16 @@ static void opening_got_offer(struct subd *openingd, } if (payload->is_v2) { + struct amount_sat fee_est UNUSED; + u32 maxheight; uc->pf = tal(uc, struct peer_funding); - /* Calculate the max we can contribute to this channel */ - /* We use one less than the contribution count limit - * to leave room for a change output */ - wallet_compute_max(openingd->ld->wallet, - REMOTE_ACCEPTER_INPUT_LIMIT, - &payload->available_funds); + /* Calculate the max we can contribute to this channel, i.e. the entire + * current, unreserved or reservation expired, at least once + * confirmed utxo value */ + maxheight = minconf_to_maxheight(1, openingd->ld); + tal_free(wallet_select_all(NULL, openingd->ld->wallet, + 0, 0, maxheight, + &payload->available_funds, &fee_est)); } else uc->pf = NULL; From f0688a66904de277f39973e723b41d10832e2bf0 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:07:31 -0500 Subject: [PATCH 125/131] fixup! df: update channel id to sha256 of revocation basepoints --- lightningd/opening_control.c | 2 +- openingd/opening_wire.csv | 2 +- openingd/openingd.c | 8 ++++---- wire/fromwire.c | 6 +++--- wire/wire.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 95a633c23855..1591a51a5790 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1726,7 +1726,7 @@ void peer_start_openingd(struct peer *peer, msg = towire_opening_init(NULL, /* We need sorting order to derive channel_id2 */ - node_id_cmp(&peer->ld->id, &peer->id), + node_id_cmp(&peer->ld->id, &peer->id) > 0, chainparams, peer->ld->our_features, &uc->our_config, diff --git a/openingd/opening_wire.csv b/openingd/opening_wire.csv index 5f4c1225691f..bcfde22ac07a 100644 --- a/openingd/opening_wire.csv +++ b/openingd/opening_wire.csv @@ -6,7 +6,7 @@ msgtype,opening_init,6000 # We need the node ordering (us/peer) for deriving the channel_id (v2) -msgdata,opening_init,node_order,u8, +msgdata,opening_init,node_order_us_first,bool, # Which network are we configured for? msgdata,opening_init,chainparams,chainparams, msgdata,opening_init,our_features,feature_set, diff --git a/openingd/openingd.c b/openingd/openingd.c index 4bd64c4697c8..6160e826f47d 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -70,7 +70,7 @@ struct state { /* We need the node ordering between us and our peer * for v2 channel ids; is ordering given us/them */ - u8 node_order; + bool first_node_is_us; /* Features they offered */ u8 *their_features; @@ -812,7 +812,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) derive_channel_id2(&state->channel_id, &state->our_points.revocation, &state->their_points.revocation, - state->node_order); + state->first_node_is_us); /* BOLT #2: * @@ -2195,7 +2195,7 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) derive_channel_id2(&state->channel_id, &state->our_points.revocation, &state->their_points.revocation, - state->node_order); + state->first_node_is_us); msg = towire_accept_channel2(tmpctx, &state->channel_id, state->accepter_funding, @@ -3034,7 +3034,7 @@ int main(int argc, char *argv[]) /*~ The very first thing we read from lightningd is our init msg */ msg = wire_sync_read(tmpctx, REQ_FD); if (!fromwire_opening_init(state, msg, - &state->node_order, + &state->first_node_is_us, &chainparams, &state->our_features, &state->localconf, diff --git a/wire/fromwire.c b/wire/fromwire.c index fde4848882c8..e886305eef51 100644 --- a/wire/fromwire.c +++ b/wire/fromwire.c @@ -375,12 +375,12 @@ void derive_channel_id(struct channel_id *channel_id, void derive_channel_id2(struct channel_id *channel_id, const struct pubkey *node_1_rev_base, const struct pubkey *node_2_rev_base, - int comparison_result) + bool node_1_first) { struct sha256 h; u8 ids[2 * PUBKEY_CMPR_LEN]; - size_t diff_1 = comparison_result < 0 ? 0 : PUBKEY_CMPR_LEN, - diff_2 = comparison_result >= 0 ? 0 : PUBKEY_CMPR_LEN; + size_t diff_1 = node_1_first ? 0 : PUBKEY_CMPR_LEN, + diff_2 = !node_1_first ? 0 : PUBKEY_CMPR_LEN; pubkey_to_der(ids + diff_1, node_1_rev_base); pubkey_to_der(ids + diff_2, node_2_rev_base); diff --git a/wire/wire.h b/wire/wire.h index 986e1f2a2106..af90f2f3c179 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -48,7 +48,7 @@ void derive_channel_id(struct channel_id *channel_id, void derive_channel_id2(struct channel_id *channel_id, const struct pubkey *node_1_rev_base, const struct pubkey *node_2_rev_base, - int comparison_result); + bool node_1_first); /* Read the type; returns -1 if not long enough. cursor is a tal ptr. */ int fromwire_peektype(const u8 *cursor); From 5f8a82b307cc8342f7de82969630f9ecd0975f7c Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:11:00 -0500 Subject: [PATCH 126/131] fixup! df: update to 'interactive tx construction' draft protocols --- openingd/openingd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 6160e826f47d..4d9eebe1b01a 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -627,6 +627,9 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) if (state->use_v2) { #if EXPERIMENTAL_FEATURES struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); + /* FIXME: use real podleh2 */ + struct sha256 *podleh2 = tal(tmpctx, struct sha256); + if (state->upfront_shutdown_script[LOCAL]) { tlv->option_upfront_shutdown_script = tal(tlv, struct tlv_opening_tlvs_option_upfront_shutdown_script); @@ -640,7 +643,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) msg = towire_open_channel2(NULL, &chainparams->genesis_blockhash, state->locktime, - NULL, /* FIXME: use real podleh2 */ + podleh2, state->feerate_per_kw_funding, state->opener_funding, state->push_msat, From 8fa174ea1631ebbbe41fcd9f7fc537edfb6abc65 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:11:58 -0500 Subject: [PATCH 127/131] interactive: don't send completes at every juncture This needs more thought, but for now is a hack that allows to c-lightning nodes to successfully communicate their inputs/outputs. Since we send everything and then start rolling through the stack of things that they sent us, the 'completes' aren't exactly "chronologically" ordered between nodes. In fact, they can/could send us a 'complete' from the past. If we then read off the complete, which is followed by more adds, with this construction we'll miss them and the whole thing will fall apart. There's a better policy here, tbd. --- openingd/openingd.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 4d9eebe1b01a..65bce79603e5 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1164,7 +1164,7 @@ static bool send_receive_funding_tx_info(struct state *state, struct channel_id id_in; struct input_info *input; struct output_info *output; - bool complete; + bool complete, last_sent_complete = false; size_t i, queue_count; u8 *msg; @@ -1225,6 +1225,7 @@ static bool send_receive_funding_tx_info(struct state *state, /* We expect the peer to send us their inputs/outputs. Read * until we get funding_add_complete */ complete = false; + last_sent_complete = true; *remote_inputs = tal_arr(state, struct input_info *, 0); *remote_outputs = tal_arr(state, struct output_info *, 0); @@ -1267,8 +1268,6 @@ static bool send_receive_funding_tx_info(struct state *state, // FIXME: verify podle? tal_arr_expand(remote_inputs, input); - msg = towire_tx_complete(tmpctx, &state->channel_id); - sync_crypto_write(state->pps, take(msg)); break; case WIRE_TX_ADD_OUTPUT: output = tal(remote_outputs, struct output_info); @@ -1282,8 +1281,6 @@ static bool send_receive_funding_tx_info(struct state *state, check_channel_id(state, &id_in, &state->channel_id); tal_arr_expand(remote_outputs, output); - msg = towire_tx_complete(tmpctx, &state->channel_id); - sync_crypto_write(state->pps, take(msg)); break; case WIRE_TX_REMOVE_INPUT: if (!fromwire_tx_remove_input(msg, &id_in, &serial_id)) @@ -1297,8 +1294,6 @@ static bool send_receive_funding_tx_info(struct state *state, "Attempted to remove unknown input %u", serial_id); - msg = towire_tx_complete(tmpctx, &state->channel_id); - sync_crypto_write(state->pps, take(msg)); break; case WIRE_TX_REMOVE_OUTPUT: if (!fromwire_tx_remove_output(msg, &id_in, &serial_id)) @@ -1312,8 +1307,6 @@ static bool send_receive_funding_tx_info(struct state *state, "Attempted to remove unknown output %u", serial_id); - msg = towire_tx_complete(tmpctx, &state->channel_id); - sync_crypto_write(state->pps, take(msg)); break; case WIRE_TX_COMPLETE: if (!fromwire_tx_complete(msg, &id_in)) @@ -1330,8 +1323,10 @@ static bool send_receive_funding_tx_info(struct state *state, peer_failed(state->pps, &state->channel_id, "Opener must send at lease one input"); - msg = towire_tx_complete(tmpctx, &state->channel_id); - sync_crypto_write(state->pps, take(msg)); + if (!last_sent_complete) { + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); + } complete = true; break; default: From b86c9e69178bc8aec6009a6f9632d73f378d37fc Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:18:01 -0500 Subject: [PATCH 128/131] fixup! df: update to 'interactive tx construction' draft protocols --- openingd/openingd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index 65bce79603e5..ec44ae6126ef 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -1177,7 +1177,7 @@ static bool send_receive_funding_tx_info(struct state *state, * - if is the `accepter`: * - MAY omit this message */ - for (i = 0; i < tal_count(local_inputs); i++) { + for (i = 0; i < tal_count(*local_inputs); i++) { input = *local_inputs[i]; msg = towire_tx_add_input(tmpctx, &state->channel_id, next_serial(role), @@ -1193,7 +1193,7 @@ static bool send_receive_funding_tx_info(struct state *state, } - if (tal_count(local_inputs) == 0) + if (tal_count(*local_inputs) == 0) assert(role == ACCEPTER); else peer_billboard(false, "Opening channel: tx_add_inputs sent"); @@ -1205,7 +1205,7 @@ static bool send_receive_funding_tx_info(struct state *state, * Either node: * - MAY omit this message */ - for (i = 0; i < tal_count(local_outputs); i++) { + for (i = 0; i < tal_count(*local_outputs); i++) { output = *local_outputs[i]; msg = towire_tx_add_output(tmpctx, &state->channel_id, next_serial(role), @@ -1214,7 +1214,7 @@ static bool send_receive_funding_tx_info(struct state *state, sync_crypto_write(state->pps, take(msg)); } - if (tal_count(local_outputs) > 0) + if (tal_count(*local_outputs) > 0) peer_billboard(false, "Opening channel: tx_add_outputs sent"); @@ -1248,7 +1248,7 @@ static bool send_receive_funding_tx_info(struct state *state, type = fromwire_peektype(msg); switch (type) { case WIRE_TX_ADD_INPUT: - input = tal(remote_inputs, struct input_info); + input = tal(*remote_inputs, struct input_info); struct tlv_tx_add_input_tlvs *tlv = tlv_tx_add_input_tlvs_new(input); @@ -1270,7 +1270,7 @@ static bool send_receive_funding_tx_info(struct state *state, tal_arr_expand(remote_inputs, input); break; case WIRE_TX_ADD_OUTPUT: - output = tal(remote_outputs, struct output_info); + output = tal(*remote_outputs, struct output_info); if (!fromwire_tx_add_output(output, msg, &id_in, &output->serial_id, &output->sats, From 533ed164a511e580b1749581a622541e5f37544b Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:18:22 -0500 Subject: [PATCH 129/131] mock updates?? --- lightningd/test/run-invoice-select-inchan.c | 5 +---- lightningd/test/run-jsonrpc.c | 5 +---- wallet/test/run-wallet.c | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 75fcc750ddbf..90b0a888086b 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -381,11 +381,8 @@ void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, { fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ void plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, - tal_t *cb_arg UNNEEDED) + tal_t *cb_arg STEALS UNNEEDED) { fprintf(stderr, "plugin_hook_call_ called!\n"); abort(); } -/* Generated stub for plugin_hook_continue */ -bool plugin_hook_continue(void *arg UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *toks UNNEEDED) -{ fprintf(stderr, "plugin_hook_continue called!\n"); abort(); } /* Generated stub for reinstate_channel_watches */ void reinstate_channel_watches(struct wallet *w UNNEEDED, struct channel *c UNNEEDED) { fprintf(stderr, "reinstate_channel_watches called!\n"); abort(); } diff --git a/lightningd/test/run-jsonrpc.c b/lightningd/test/run-jsonrpc.c index 1d62de49c212..5bb185784aba 100644 --- a/lightningd/test/run-jsonrpc.c +++ b/lightningd/test/run-jsonrpc.c @@ -96,11 +96,8 @@ struct command_result *param_tok(struct command *cmd UNNEEDED, const char *name { fprintf(stderr, "param_tok called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ void plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, - tal_t *cb_arg UNNEEDED) + tal_t *cb_arg STEALS UNNEEDED) { fprintf(stderr, "plugin_hook_call_ called!\n"); abort(); } -/* Generated stub for plugin_hook_continue */ -bool plugin_hook_continue(void *arg UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *toks UNNEEDED) -{ fprintf(stderr, "plugin_hook_continue called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ bool deprecated_apis; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index ff6be1903c62..76c69c2c4b46 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -547,11 +547,8 @@ void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, { fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ void plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, - tal_t *cb_arg UNNEEDED) + tal_t *cb_arg STEALS UNNEEDED) { fprintf(stderr, "plugin_hook_call_ called!\n"); abort(); } -/* Generated stub for plugin_hook_continue */ -bool plugin_hook_continue(void *arg UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *toks UNNEEDED) -{ fprintf(stderr, "plugin_hook_continue called!\n"); abort(); } /* Generated stub for process_onionpacket */ struct route_step *process_onionpacket( const tal_t * ctx UNNEEDED, From 6f892c1a5e76d00c222054373fe015c9c2eee56e Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:18:34 -0500 Subject: [PATCH 130/131] fixup! df: update to 'interactive tx construction' draft protocols --- openingd/openingd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openingd/openingd.c b/openingd/openingd.c index ec44ae6126ef..01207ea11bba 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -2312,11 +2312,6 @@ static u8 *fundee_channel2(struct state *state, const u8 *open_channel2_msg) &state->channel_id, "Peer sent HTLCs with initial commitment signed msg"); - /* We expect to have switched over to using the funding_tx - * derived channel_id as of now */ - derive_channel_id(&state->channel_id, - &state->funding_txid, state->funding_txout); - /* If this check fails, we know that they've derived a different funding * tx than we have */ check_channel_id(state, &id_in, &state->channel_id); From 9dac1fc395276fd1e568dd50aa5182523ad46b6c Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Wed, 6 May 2020 18:56:07 -0500 Subject: [PATCH 131/131] interactive: flag for whether to include 'common' fields --- common/wallet_tx.c | 4 ++-- lightningd/opening_control.c | 6 +++--- wallet/test/run-wallet.c | 12 ++++++------ wallet/wallet.c | 34 ++++++++++++++++++++++++++-------- wallet/wallet.h | 1 + 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/common/wallet_tx.c b/common/wallet_tx.c index da9a1a171523..7b1e8b553200 100644 --- a/common/wallet_tx.c +++ b/common/wallet_tx.c @@ -160,14 +160,14 @@ struct command_result *wtx_select_utxos(struct wallet_tx *tx, } tx->utxos = wallet_select_coins(tx, tx->cmd->ld->wallet, - true, tx->amount, + true, true, tx->amount, fee_rate_per_kw, out_len, maxheight, &fee_estimate, &tx->change); if (!tx->utxos) { /* Try again, without change this time */ tx->utxos = wallet_select_coins(tx, tx->cmd->ld->wallet, - false, tx->amount, + false, true, tx->amount, fee_rate_per_kw, out_len, maxheight, &fee_estimate, &tx->change); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 1591a51a5790..09cc5161d66c 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1453,9 +1453,9 @@ static void openchannel_hook_cb(struct openchannel_hook_payload *payload STEALS, struct amount_sat fee_estimate UNUSED; pf->utxos = (struct utxo **)wallet_select_coins(pf, openingd->ld->wallet, - true, pf->accepter_funding, - 0, 0, - UINT32_MAX, /* minconf 1 */ + true, false, + pf->accepter_funding, + 0, 0, UINT32_MAX, /* minconf 1 */ &fee_estimate, &change); } else { change = AMOUNT_SAT(0); diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 76c69c2c4b46..4731240d16f9 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -928,7 +928,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "wallet_add_utxo with close_info"); /* Now select them */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(2), 0, 21, + utxos = wallet_select_coins(w, w, true, true, AMOUNT_SAT(2), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); CHECK(utxos && tal_count(utxos) == 2); @@ -966,7 +966,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "could not change output state ignoring oldstate"); /* Check for 'reserved' state changes */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + utxos = wallet_select_coins(w, w, true, true, AMOUNT_SAT(1), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); CHECK(utxos && tal_count(utxos) == 1); @@ -982,7 +982,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) tal_free(utxos); /* Now should be unable to select 1 sat amount */ - CHECK_MSG(!wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + CHECK_MSG(!wallet_select_coins(w, w, true, true, AMOUNT_SAT(1), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis), "too many utxos available"); @@ -1000,7 +1000,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) /* Expire the lease! */ ld->topology->tip->height = height + reserve_for_blocks; - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(1), 0, 21, + utxos = wallet_select_coins(w, w, true, true, AMOUNT_SAT(1), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); CHECK_MSG(utxos && tal_count(utxos) == 1, "utxo count is incorrect"); @@ -1021,7 +1021,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "wallet_add_utxo high priority utxo"); /* check that we get back two high priority utxos */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(2), 0, 21, + utxos = wallet_select_coins(w, w, true, true, AMOUNT_SAT(2), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); CHECK_MSG(utxos && tal_count(utxos) == 2, "utxo count is incorrect"); @@ -1043,7 +1043,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) "wallet_add_utxo with close_info no commitment_point"); /* Now select it */ - utxos = wallet_select_coins(w, w, true, AMOUNT_SAT(5), 0, 21, + utxos = wallet_select_coins(w, w, true, true, AMOUNT_SAT(5), 0, 21, 0 /* no confirmations required */, &fee_estimate, &change_satoshis); CHECK(utxos && tal_count(utxos) == 1); diff --git a/wallet/wallet.c b/wallet/wallet.c index ad0648a3467a..3c4f3161facc 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -767,11 +767,14 @@ void wallet_confirm_utxos(struct wallet *w, const struct utxo **utxos) } } + + static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, struct amount_sat sat, const u32 feerate_per_kw, size_t outscriptlen, bool may_have_change, + bool include_common_fields, u32 maxheight, struct amount_sat *satoshi_in, struct amount_sat *fee_estimate) @@ -783,11 +786,25 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, const struct utxo **utxos = tal_arr(ctx, const struct utxo *, 0); tal_add_destructor2(utxos, destroy_utxos, w); - /* version, input count, output count, locktime */ - weight = (4 + 1 + 1 + 4) * 4; - - /* Add segwit fields: marker + flag */ - weight += 1 + 1; + /* BOLT-937cbac261629c046ad7dbff7dd0b285e98e7d70 #2 + * The initiator is responsible for paying the fees for the following fields, + * to be referred to as the `common` fields. + * + * - version + * - segwit marker + flag + * - input count + * - output count + * - locktime + * + * Each party to the transaction is responsible for paying the fees + * for their input, output, and witness, at the agreed `feerate`. + */ + if (include_common_fields) + /* version, input count, output count, locktime, + * segwit marker + flag */ + weight = (4 + 1 + 1 + 4) * 4 + 1 + 1; + else + weight = 0; /* The main output: amount, len, scriptpubkey */ weight += (8 + 1 + outscriptlen) * 4; @@ -880,6 +897,7 @@ static const struct utxo **wallet_select(const tal_t *ctx, struct wallet *w, const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w, bool with_change, + bool include_common_fields, struct amount_sat sat, const u32 feerate_per_kw, size_t outscriptlen, @@ -891,8 +909,8 @@ const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w, const struct utxo **utxo; utxo = wallet_select(ctx, w, sat, feerate_per_kw, - outscriptlen, with_change, maxheight, - &satoshi_in, fee_estimate); + outscriptlen, with_change, include_common_fields, + maxheight, &satoshi_in, fee_estimate); /* Couldn't afford it? */ if (!amount_sat_sub(change, satoshi_in, sat) @@ -947,7 +965,7 @@ const struct utxo **wallet_select_all(const tal_t *ctx, struct wallet *w, /* Huge value, but won't overflow on addition */ utxo = wallet_select(ctx, w, AMOUNT_SAT(1ULL << 56), feerate_per_kw, - outscriptlen, false, maxheight, + outscriptlen, false, true, maxheight, &satoshi_in, fee_estimate); /* Can't afford fees? */ diff --git a/wallet/wallet.h b/wallet/wallet.h index 47de5f182ac0..31070d82510f 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -452,6 +452,7 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, const struct utxo **wallet_select_coins(const tal_t *ctx, struct wallet *w, bool with_change, + bool include_common_fields, struct amount_sat value, const u32 feerate_per_kw, size_t outscriptlen,