diff --git a/.gitignore b/.gitignore index 0ff353425168..2a7ed297a6df 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 @@ -44,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/ 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/bitcoin/tx.c b/bitcoin/tx.c index 6ac439d84e58..725576c765f2 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) { @@ -160,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; @@ -228,6 +239,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 29eeb897484f..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; @@ -46,10 +47,16 @@ 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, + 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); @@ -115,6 +122,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/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/channel_wire.csv b/channeld/channel_wire.csv index 3f36ac80e5d0..22ec4c35d387 100644 --- a/channeld/channel_wire.csv +++ b/channeld/channel_wire.csv @@ -24,7 +24,8 @@ 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,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 24b037fd5be7..9d2e69e2d977 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, @@ -1967,6 +1967,17 @@ 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_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_INIT_RBF: +#endif /* EXPERIMENTAL_FEATURES */ break; /* These are all swallowed by handle_peer_gossip_or_error */ @@ -1981,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(); } @@ -2107,7 +2121,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 +2826,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,17 +3081,17 @@ 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; + u8 *sigs_msg; const u8 *msg; struct fee_states *fee_states; u32 minimum_depth; 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 @@ -3102,7 +3116,8 @@ static void init_channel(struct peer *peer) &points[REMOTE], &peer->remote_per_commit, &peer->old_remote_per_commit, - &funder, + &opener, + &local_funded, &peer->fee_base, &peer->fee_per_satoshi, &local_msat, @@ -3127,7 +3142,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, @@ -3148,7 +3163,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 +3212,8 @@ static void init_channel(struct peer *peer) &funding_pubkey[LOCAL], &funding_pubkey[REMOTE], option_static_remotekey, - funder); + local_funded, + opener); if (!channel_force_htlcs(peer->channel, cast_const2(const struct existing_htlc **, htlcs))) @@ -3211,7 +3227,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 */ @@ -3221,9 +3237,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/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..56596968d02e 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -101,7 +101,8 @@ 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) + bool local_funded, + enum side opener) { struct channel *channel = new_initial_channel(ctx, funding_txid, @@ -116,7 +117,8 @@ struct channel *new_full_channel(const tal_t *ctx, local_funding_pubkey, remote_funding_pubkey, option_static_remotekey, - funder); + local_funded, + opener); if (channel) { channel->htlcs = tal(channel, struct htlc_map); @@ -295,7 +297,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 +420,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 +542,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 +616,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 +636,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 +651,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 +669,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 +972,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 +1003,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 +1034,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..aaaeb4e52f6e 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -25,7 +25,8 @@ 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. + * @local_funded: true if local has inputs in funding tx + * @opener: which side initiated it. * * Returns state, or NULL if malformed. */ @@ -43,7 +44,8 @@ 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); + bool local_funded, + enum side opener); /** * channel_txs: Get the current commitment and htlc txs for the channel. @@ -151,7 +153,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 +162,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..017479f22c3f 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); @@ -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/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/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/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); diff --git a/common/features.c b/common/features.c index 490cb18a94f8..629efaffc512 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_AS_OPTIONAL, + [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..d1958dd520de 100644 --- a/common/features.h +++ b/common/features.h @@ -108,4 +108,12 @@ 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` |... + */ +#define OPT_FUNDCHANNEL_V2 28 + #endif /* LIGHTNING_COMMON_FEATURES_H */ diff --git a/common/funding_tx.c b/common/funding_tx.c index f75cbd9d25f5..528b917bc598 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,413 @@ 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 */ +/* 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) +{ + u64 scriptlen; + 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 */ + 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; + + if (!amount_sat_add(total, *total, inputs[i]->sats)) + return false; + } + + return true; +} + +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 */ + output_weights += (8 + scriptlen + varint_size(scriptlen)) * 4; + } + + return output_weights; +} + +/* 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) + +{ + /* version, input count, output count, locktime */ + *weight = (4 + 1 + 1 + 4) * 4; + + /* add segwit fields: marker + flag */ + *weight += 1 + 1; + + if (!calculate_input_weights(opener_inputs, opener_total, weight)) + return false; + + if (!calculate_input_weights(accepter_inputs, accepter_total, weight)) + return false; + + /* + * 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); + *weight += calculate_output_weights(accepter_outputs); + + return true; +} + +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]->sats, AMOUNT_SAT(0))) + return outputs[i]; + } + return NULL; +} + +static bool calculate_output_value(struct output_info **outputs, + struct amount_sat *total) +{ + size_t i = 0; + + for (i = 0; i < tal_count(outputs); i++) { + if (!amount_sat_add(total, *total, outputs[i]->sats)) + return false; + } + return true; +} + +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_RBF_SEQUENCE, + inputs[i]->sats, 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]->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]->sats; + + 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, + u32 tx_locktime, + 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, + struct amount_sat *opener_change, + const void **input_map) +{ + size_t weight = 0; + struct amount_sat est_tx_fee, opener_total_sat, + accepter_total_sat, output_val, change; + 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 */ + if (!calculate_weight(opener_inputs, accepter_inputs, + opener_outputs, accepter_outputs, + &opener_total_sat, &accepter_total_sat, + &weight)) + return NULL; + + /* 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 + * only 'flexible' / change output that's removable etc is indicated + * by a zero value. */ + 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; + + /* + * 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); + + /* + * 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(&change, *opener_change, est_tx_fee) && + amount_sat_greater(change, chainparams->dust_limit)) { + if (!change_output) { + /* + * 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, + change)) + return NULL; + *opener_change = AMOUNT_SAT(0); + } else + *opener_change = change; + + goto build_tx; + } + + /* + * 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; + 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(&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; + } + } + + /* + * 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; + + *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 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); + } + + tx = bitcoin_tx(ctx, chainparams, input_count, output_count, tx_locktime); + + /* 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; + if (!amount_sat_add(total_funding, *total_funding, accepter_funding)) + return NULL; + + /* + * 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); + + 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); + + /* Set funding_output index for caller */ + 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 */ + +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); + + 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); + input->prevtx_scriptpubkey = fromwire_tal_arrn(input, ptr, max, fromwire_u16(ptr, max)); + input->max_witness_len = fromwire_u16(ptr, max); + input->script = fromwire_tal_arrn(input, ptr, max, fromwire_u16(ptr, max)); + + 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 577a4cafb2ee..1f718b38a703 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; @@ -12,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. @@ -44,4 +66,42 @@ 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. + * @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 + * @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. + * @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, + const struct chainparams *chainparams, + u32 tx_locktime, + 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, + struct amount_sat *opener_change, + const void **input_map); +#endif /* EXPERIMENTAL_FEATURES */ #endif /* LIGHTNING_COMMON_FUNDING_TX_H */ 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/common/initial_channel.c b/common/initial_channel.c index 6074ee585f81..238afa3c2560 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -24,7 +24,8 @@ 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) + bool local_funded, + enum side opener) { struct channel *channel = tal(ctx, struct channel); struct amount_msat remote_msatoshi; @@ -32,12 +33,13 @@ 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)) 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 +60,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 +97,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 +113,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 +130,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..3829cf0e73aa 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -39,7 +39,10 @@ struct channel { u32 minimum_depth; /* Who is paying fees. */ - enum side funder; + 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,7 +81,9 @@ struct channel { * @remote_basepoints: remote basepoints. * @local_fundingkey: local funding key * @remote_fundingkey: remote funding key - * @funder: which side initiated it. + * @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,7 +101,8 @@ 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); + bool local_funded, + 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/common/test/run-funding_tx.c b/common/test/run-funding_tx.c index 24e04e3974a0..f85938b31e6a 100644 --- a/common/test/run-funding_tx.c +++ b/common/test/run-funding_tx.c @@ -37,12 +37,25 @@ 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(); } /* 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 */ +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(); } /* 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 +71,21 @@ 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 */ +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(); } /* AUTOGENERATED MOCKS END */ #if 0 @@ -175,6 +197,9 @@ int main(void) if (!amount_sat_sub(&change, utxo.amount, funding_sat) || !amount_sat_sub(&change, change, fee)) abort(); + + /* Make a funding tx with change */ + change = AMOUNT_SAT(1); funding = funding_tx(tmpctx, chainparams, &funding_outnum, utxomap, funding_sat, @@ -188,10 +213,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); @@ -204,6 +235,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); diff --git a/common/test/run-funding_tx_dual.c b/common/test/run-funding_tx_dual.c new file mode 100644 index 000000000000..f89026a7c152 --- /dev/null +++ b/common/test/run-funding_tx_dual.c @@ -0,0 +1,860 @@ +#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_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(); } +/* 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 */ +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(); } +/* 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_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 */ +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(); } +/* 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 amount_sat expected_change; + 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)); +} + +/* + * 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; + 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->sats = 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->sats = 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->sats = 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->sats = 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->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->sats = AMOUNT_SAT(200000000); + output_two->script = hex_to_u8(ctx, "001444cb0c39f93ecc372b5851725bd29d865d333b10"); + accepter_outputs[0] = output_two; + + char *expected_tx_str = "0200000004b932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430000000000feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430100000023220020fd89acf65485df89797d9ba7ba7a33624ac4452f00db08107f34257d33e5b946feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430200000000feffffffb932b0669cd0394d0d5bcc27e01ab8c511f1662a6799925b346c0cf18fca03430300000017160014fbb4db9d85fba5e301f4399e3038928e44e37d32feffffff03ea7f0100000000001600141ca1cca8855bad6bc1ea5436edd8cff10b7e448b00c2eb0b0000000016001444cb0c39f93ecc372b5851725bd29d865d333b106081ad2f00000000220020297b92c238163e820b82486084634b4846b86a3c658d87b9384192e6bea98ec500000000"; + 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", + .expected_change = AMOUNT_SAT(98282), + }; + + 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->sats = 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->sats = 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->sats = 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->sats = 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->sats = (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->sats = (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->sats = (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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(9745), + }; + + 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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0311260000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d54095160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5d8a4160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff046403000000000000160014d295f76da2319791f36df5759e45b15d5e10522188130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5f8a0160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(868), + }; + + 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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0388130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d56881160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(0), + }; + + assert(test.expected_tx); + + return test; +} + +/* 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); + 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, 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); + + + char *expected_tx_str = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0000000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff0364190000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d588a2160000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + struct test_case test = { + .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(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); + + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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 = "02000000013f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff01399f070000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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 = "02000000023f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0100000000feffffff3f05da71fb470a53807eb01db4a9220941e3737fa44bccd1fb00f1968c98396c0200000000feffffff0188811e0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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 = "020000000451e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070000000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070100000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070200000000feffffff51e9e94af2fbef69f74fa0c5aa955f1fc169df751461daaaf659bea2ee83f9070300000000feffffff0488130000000000001600140f0963bc774334ebc14d11ce940c35cfa69864151027000000000000160014d640ab16f347d1de5aba5a715321a5fc4ba9a5d5cae31c0000000000160014d295f76da2319791f36df5759e45b15d5e10522150262f0000000000220020c46bf3d1686d6dbb2d9244f8f67b90370c5aa2747045f1aeccb77d818711738200000000"; + 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", + .expected_change = AMOUNT_SAT(1893322), + }; + + 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", + .expected_change = AMOUNT_SAT(0), + }; + + 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", + .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_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, +}; + +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, opener_change; + + 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, + 0, /* examples all have locktime at 0 */ + &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, + &opener_change, NULL); + + if (!test.expected_tx && !funding) + continue; + + if (!test.expected_tx ^ !funding) + 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)); + } + + /* No memory leaks please */ + secp256k1_context_destroy(secp256k1_ctx); + tal_free(tmpctx); + + return 0; +} +#else +int main(void) +{ + return 0; +} +#endif /* EXPERIMENTAL_FEATURES */ diff --git a/common/utxo.c b/common/utxo.c index b39adde67df2..ae61f8e254f9 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -10,12 +10,19 @@ 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); 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,11 +31,20 @@ 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) { 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); @@ -36,9 +52,13 @@ 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; + 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); @@ -54,6 +74,16 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) } else { 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/common/utxo.h b/common/utxo.h index 459d5c5ccea1..a0b9ec8105f6 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -39,8 +39,30 @@ 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; + + /* 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; + + /* scriptSig. Only for P2SH outputs */ + 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); 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/common/withdraw_tx.c b/common/withdraw_tx.c index 1aee140bd288..19c61a1103d0 100644 --- a/common/withdraw_tx.c +++ b/common/withdraw_tx.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -12,49 +13,50 @@ 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 pubkey *changekey, - struct amount_sat change, const struct ext_key *bip32_base, - int *change_outnum, u32 nlocktime) + u32 nlocktime, + const void **input_map) { 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; - - permute_inputs(tx, (const void **)utxos); + 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); + } + + /* 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, 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 163f1b4757ac..3bdeff0f4bb6 100644 --- a/common/withdraw_tx.h +++ b/common/withdraw_tx.h @@ -20,20 +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. - * @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. + * @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 pubkey *changekey, - struct amount_sat change, const struct ext_key *bip32_base, - int *change_outnum, u32 nlocktime); + u32 nlocktime, + const void **input_map); #endif /* LIGHTNING_COMMON_WITHDRAW_TX_H */ diff --git a/connectd/Makefile b/connectd/Makefile index 28d41d7e4dd9..619aa4446e9e 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -52,14 +52,17 @@ 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 \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ 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/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) diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 92bde08c069b..e62e5d4b611c 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): @@ -713,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) 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/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 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/gossipd/Makefile b/gossipd/Makefile index 7de9fae19ec6..f7dcf8ca929f 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -54,14 +54,17 @@ 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 \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ 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 c2d77373ad91..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,7 +495,16 @@ 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_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_INIT_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/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 eb1eb96e32ba..c2d85f324d85 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -57,6 +57,38 @@ 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,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, +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, @@ -67,13 +99,12 @@ 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_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 39ad012b195e..46bb95a032e5 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,39 +1599,156 @@ 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); + sign_input(tx, utxos[i], &inkey, &sig, i); + } +} + +/* 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; + } } - /* 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))); + 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); } } +#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, tx_locktime; + 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, + &tx_locktime, + &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, + tx_locktime, + 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, @@ -1645,28 +1797,95 @@ 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_input **inputs; struct bitcoin_tx_output **outputs; u32 nlocktime; - if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &satoshi_out, - &change_out, &change_keyindex, - &outputs, &utxos, &nlocktime)) + 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, + &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); + input_count = tal_count(utxos) + tal_count(inputs); + const void *map[input_count]; + 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), outputs, - &changekey, change_out, NULL, NULL, nlocktime); + 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) { + offset = tal_count(utxos) + i; + 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))); @@ -1892,6 +2111,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: @@ -1911,6 +2137,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: @@ -1964,6 +2191,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); @@ -2016,6 +2249,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: 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/chaintopology.c b/lightningd/chaintopology.c index adf2b4cba8e5..2b1088d166d4 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); } } @@ -280,20 +280,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)); } } @@ -774,7 +775,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); } @@ -955,8 +956,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/channel.c b/lightningd/channel.c index 94687ea0d4b5..b5fe812dd036 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, @@ -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, @@ -197,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 { @@ -204,7 +206,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); @@ -227,6 +229,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; @@ -294,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; @@ -412,8 +427,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); @@ -427,7 +446,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..54deb1f9ddf1 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; @@ -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. */ @@ -129,13 +133,16 @@ 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, /* 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, @@ -149,6 +156,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, @@ -209,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); @@ -248,11 +260,23 @@ 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 && channel->state != CLOSINGD_COMPLETE - && !channel_on_chain(channel); + && !channel_on_chain(channel) + && !channel_is_borked(channel); } void get_channel_basepoints(struct lightningd *ld, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 9fba5eb7e2df..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; } @@ -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,13 +278,35 @@ 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); } +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 + + /* 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; +} + +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); @@ -372,7 +394,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; @@ -481,7 +503,8 @@ 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, + !amount_sat_eq(channel->our_funds, AMOUNT_SAT(0)), channel->feerate_base, channel->feerate_ppm, channel->our_msat, @@ -506,7 +529,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, @@ -523,7 +546,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,13 +606,20 @@ 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. */ 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) @@ -703,7 +733,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, @@ -746,11 +776,18 @@ 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"); + 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/lightningd/channel_control.h b/lightningd/channel_control.h index 10542e77fee2..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, @@ -31,6 +54,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/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/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/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/lightningd.c b/lightningd/lightningd.c index 2b0ded7e7ae3..ee8c98a6d3fa 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -901,14 +901,21 @@ 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 * 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/onchain_control.c b/lightningd/onchain_control.c index d6f0d03364f9..f38756c9b25c 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) @@ -295,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); @@ -560,7 +566,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..09cc5161d66c 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1,6 +1,8 @@ #include "bitcoin/feerate.h" #include #include +#include +#include #include #include #include @@ -8,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -31,11 +35,15 @@ #include #include #include +#include +#include #include #include #include #include +#define UTXO_RESERVATION_BLOCKS 18 + /* Channel we're still opening. */ struct uncommitted_channel { /* peer->uncommitted_channel == this */ @@ -56,6 +64,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; @@ -64,7 +76,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. */ @@ -96,6 +108,20 @@ struct funding_channel { /* Any commands trying to cancel us. */ struct command **cancels; + + /* 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, @@ -164,8 +190,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, @@ -184,17 +212,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); @@ -227,7 +266,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, @@ -236,8 +275,9 @@ wallet_commit_channel(struct lightningd *ld, 1, 1, 0, funding_txid, funding_outnum, - funding, + total_funding, push, + local_funding, false, /* !remote_funding_locked */ NULL, /* no scid yet */ /* The three arguments below are msatoshi_to_us, @@ -291,6 +331,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)); } @@ -313,6 +358,8 @@ static void funding_started_success(struct funding_channel *fc, json_add_hex_talarr(response, "close_to", fc->our_upfront_shutdown_script); } + 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; was_pending(command_success(cmd, response)); @@ -355,6 +402,411 @@ 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 watches for channel.", + 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); + + 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; + } + + /* 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, + 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); + } + + /* FIXME: make sure inputs are ordered corrrectly (by serial_id) */ + utx->inputs[i]->witness = tal_steal(utx->inputs[i], witnesses_arr); + } + + return true; +} + +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) +{ + 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; + + 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; + in->amount = input_amts[index]; + + /* 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; + + 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); + utx->wtx->change = opener_change; + + 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, opener_change; + struct channel *channel; + struct lightningd *ld = openingd->ld; + u8 *remote_upfront_shutdown_script; + struct per_peer_state *pps; + struct witness_stack **remote_witnesses; + 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; + + if (!fromwire_opening_dual_funding_signed(resp, resp, + &pps, + &remote_commit, + &remote_commit_sig, + &funding_tx, + &funding_txout, + &opener_change, + &remote_witnesses, + &input_amts, + &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_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 cleanup; + } + + /* Update the funding tx that we have for this */ + 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; + } + + 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); + + /* 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 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); + + /* 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) @@ -412,7 +864,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, @@ -440,25 +894,118 @@ 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, 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; + const struct bitcoin_tx_input **remote_inputs; 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; + const struct utxo **utxos; log_debug(uc->log, "Got opening_fundee_finish_response"); @@ -478,11 +1025,13 @@ static void opening_fundee_finished(struct subd *openingd, &channel_info.remote_fundingkey, &funding_txid, &funding_outnum, - &funding, + &opener_funding, + &accepter_funding, + (struct bitcoin_tx_input ***)&remote_inputs, &push, &channel_flags, &feerate, - &funding_signed, + &final_peer_msg, &uc->our_config.channel_reserve, &local_upfront_shutdown_script, &remote_upfront_shutdown_script)) { @@ -497,21 +1046,33 @@ 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; } + if (!amount_sat_add(&total_funding, opener_funding, accepter_funding)) + abort(); + + if (uc->pf) + /* We steal here, because otherwise gets eaten below */ + utxos = cast_const2(const struct utxo **, + 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, + total_funding, + accepter_funding, push, + REMOTE, channel_flags, &channel_info, feerate, @@ -520,9 +1081,23 @@ static void opening_fundee_finished(struct subd *openingd, if (!channel) { uncommitted_channel_disconnect(uc, LOG_BROKEN, "Commit channel failed"); - goto failed; + goto failed_later; } + /* Add a watch for all the inputs for this channel open */ + watch_tx_inputs(ld->wallet, channel, &channel->funding_txid, + remote_inputs, 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); + } + + if (utxos) + tal_free(utxos); + log_debug(channel->log, "Watching funding tx %s", type_to_string(reply, struct bitcoin_txid, &channel->funding_txid)); @@ -534,13 +1109,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]); @@ -573,7 +1151,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)); @@ -705,13 +1283,17 @@ 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; 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; u16 max_accepted_htlcs; u8 channel_flags; @@ -725,8 +1307,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->funding_satoshis); + 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); + 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); @@ -736,7 +1323,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); @@ -755,12 +1348,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); @@ -818,12 +1416,106 @@ 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, false, + pf->accepter_funding, + 0, 0, UINT32_MAX, /* minconf 1 */ + &fee_estimate, &change); + } 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, @@ -838,23 +1530,25 @@ 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; } payload = tal(openingd, struct openchannel_hook_payload); payload->openingd = openingd; if (!fromwire_opening_got_offer(payload, msg, - &payload->funding_satoshis, + &payload->is_v2, + &payload->opener_satoshis, &payload->push_msat, &payload->dust_limit_satoshis, &payload->max_htlc_value_in_flight_msat, &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, @@ -865,6 +1559,20 @@ static void opening_got_offer(struct subd *openingd, return; } + 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, 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; + tal_add_destructor2(openingd, openchannel_payload_remove_openingd, payload); plugin_hook_call_openchannel(openingd->ld, payload); } @@ -887,6 +1595,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", @@ -905,7 +1624,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; @@ -916,12 +1634,20 @@ 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: 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_CHECK_INPUTS_REPLY: case WIRE_OPENING_DEV_MEMLEAK: /* Replies never get here */ case WIRE_OPENING_DEV_MEMLEAK_REPLY: @@ -963,7 +1689,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", @@ -998,6 +1725,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) > 0, chainparams, peer->ld->our_features, &uc->our_config, @@ -1030,6 +1759,8 @@ 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; + const struct utxo **utxos; if (!param(cmd, buffer, params, p_req("id", param_node_id, &id), @@ -1049,7 +1780,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)); @@ -1063,11 +1794,37 @@ 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; + 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); + funding_txid, funding_txout, + utxos, tx); + subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); } @@ -1125,6 +1882,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; @@ -1177,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)); @@ -1214,6 +1972,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; @@ -1222,12 +1985,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 + fc->is_v2 = feature_offered(peer->their_features, OPT_FUNDCHANNEL_V2); +#else + fc->is_v2 = false; +#endif + msg = towire_opening_funder_start(NULL, *amount, + locktime, fc->push, fc->our_upfront_shutdown_script, *feerate_per_kw, - fc->channel_flags); + fc->channel_flags, + fc->is_v2); subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); return command_still_pending(cmd); 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 b3e0db5b7cb7..b5cc6fd61db9 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); @@ -233,10 +240,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; @@ -423,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. */ - if (!err_for_them && channel->funder == REMOTE + * 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, @@ -453,7 +462,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 +535,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; @@ -613,6 +622,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 +663,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->funder == 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->funder == 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)) { @@ -735,8 +732,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 +764,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))) @@ -940,6 +937,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); @@ -1015,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); } @@ -1109,6 +1107,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; @@ -1120,10 +1128,14 @@ 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; } -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) @@ -1161,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); @@ -1243,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, @@ -1304,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); @@ -1324,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. @@ -1480,6 +1496,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); + } } } @@ -1562,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", @@ -1792,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 */ @@ -1999,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/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. 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/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; diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 40d25a6b17ee..90b0a888086b 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) @@ -375,11 +381,11 @@ 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(); } /* 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 +547,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(); } @@ -577,7 +586,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)) @@ -663,6 +673,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); 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/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 */ diff --git a/lightningd/watch.c b/lightningd/watch.c index f5a041295906..0beff66fd450 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 { @@ -149,6 +151,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) @@ -195,16 +220,21 @@ 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)) { 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; @@ -243,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); @@ -260,7 +291,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) @@ -275,12 +307,13 @@ 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); 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 b5c7f2544231..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); @@ -65,7 +67,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 +81,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); @@ -91,4 +94,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/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/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/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) diff --git a/openingd/channel_establishment.h b/openingd/channel_establishment.h new file mode 100644 index 000000000000..c20c5c25169c --- /dev/null +++ b/openingd/channel_establishment.h @@ -0,0 +1,14 @@ +#ifndef LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H +#define LIGHTNING_OPENINGD_CHANNEL_ESTABLISHMENT_H +#include + +/* 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 ef1adb13f501..bcfde22ac07a 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_us_first,bool, # Which network are we configured for? msgdata,opening_init,chainparams,chainparams, msgdata,opening_init,our_features,feature_set, @@ -31,6 +33,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 +41,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, @@ -47,7 +51,17 @@ 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 +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. @@ -73,11 +87,13 @@ 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 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 @@ -87,10 +103,14 @@ 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,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 msgtype,opening_funder_cancel,6013 @@ -114,19 +134,67 @@ 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,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, -# 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 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 +#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,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, +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 + +# 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 + +# 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 46e33f315cee..01207ea11bba 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 @@ -66,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 */ + bool first_node_is_us; + /* Features they offered */ u8 *their_features; @@ -94,7 +100,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; @@ -115,6 +121,20 @@ 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; + + /* 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 + */ + u8 **funding_msg_queue; }; static u8 *dev_upfront_shutdown_script(const tal_t *ctx) @@ -128,9 +148,21 @@ 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 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 +175,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)); } @@ -158,10 +190,11 @@ static void negotiation_aborted(struct state *state, bool am_funder, * 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. */ -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 +209,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,10 +217,11 @@ 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; + struct amount_sat capacity, reserve, all_funding; + + all_funding = total_funding(state); /* BOLT #2: * @@ -196,7 +230,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 +253,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, @@ -228,8 +262,8 @@ 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, + if (!amount_sat_sub(&capacity, all_funding, reserve)) { + negotiation_failed(state, am_opener, "channel_reserve_satoshis %s" " and %s too large for funding %s", type_to_string(tmpctx, struct amount_sat, @@ -237,7 +271,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; } @@ -250,14 +284,14 @@ 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", 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; @@ -267,13 +301,13 @@ 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," " 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, @@ -289,7 +323,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 +336,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 +350,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, @@ -333,7 +367,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: * @@ -346,6 +380,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: @@ -367,7 +413,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 +475,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 +483,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. */ @@ -468,21 +514,68 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, } } -static bool setup_channel_funder(struct state *state) +static bool check_reserves(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); - - /*~ 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); + /* 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) +{ + 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) */ + /* 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; + /* --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); + /* BOLT #2: * * The sending node: @@ -494,13 +587,13 @@ 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; } @@ -531,83 +624,198 @@ 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); + /* 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); + 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 set separately */ + state->feerate_per_kw_funding = state->feerate_per_kw; + msg = towire_open_channel2(NULL, + &chainparams->genesis_blockhash, + state->locktime, + 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->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-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->first_node_is_us); /* BOLT #2: * @@ -617,22 +825,15 @@ 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)); - 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; @@ -656,239 +857,1593 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) OPT_UPFRONT_SHUTDOWN_SCRIPT)); } -static bool funder_finalize_channel_setup(struct state *state, - struct amount_msat local_msat, - struct bitcoin_signature *sig, - struct bitcoin_tx **tx) +#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) { - u8 *msg; - struct channel_id id_in; - const u8 *wscript; - char *err_reason; - - /*~ Now we can initialize the `struct channel`. This represents - * the current channel state and is how we can generate the current - * commitment transaction. - * - * The routines to support `struct channel` are split into a common - * part (common/initial_channel) which doesn't support HTLCs and is - * enough for us here, and the complete channel support required by - * `channeld` which lives in channeld/full_channel. */ - state->channel = new_initial_channel(state, - &state->funding_txid, - state->funding_txout, - state->minimum_depth, - state->funding, - local_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, - /* Opener is local */ - LOCAL); - /* We were supposed to do enough checks above, but just in case, - * new_initial_channel will fail to create absurd channels */ - if (!state->channel) - peer_failed(state->pps, - &state->channel_id, - "could not create channel with given config"); + 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) +{ /* BOLT #2: * - * ### The `funding_created` Message - * - * This message describes the outpoint which the funder has created - * for the initial commitment transactions. After receiving the - * peer's signature, via `funding_signed`, it will broadcast the funding - * transaction. + * The `temporary_channel_id` MUST be the same as the + * `temporary_channel_id` in the `open_channel` message. */ - /* This gives us their first commitment transaction. */ - *tx = initial_channel_tx(state, &wscript, state->channel, - &state->first_per_commitment_point[REMOTE], - REMOTE, &err_reason); - if (!*tx) { - /* This should not happen: we should never create channels we - * can't afford the fees for after reserve. */ - negotiation_failed(state, true, - "Could not meet their fees and reserve: %s", err_reason); - goto fail; + 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->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, + 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; + + /* + * 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); + memcpy(in->script, tx->wtx->inputs[i].script, + tx->wtx->inputs[i].script_len); + } else + in->script = NULL; + + (*inputs)[i] = in; } - /* We ask the HSM to sign their commitment transaction for us: it knows - * our funding key, it just needs the remote funding key to create the - * witness script. It also needs the amount of the funding output, - * as segwit signatures commit to that as well, even though it doesn't - * explicitly appear in the transaction itself. */ - msg = towire_hsm_sign_remote_commitment_tx(NULL, - *tx, - &state->channel->funding_pubkey[REMOTE], - state->channel->funding, - (const struct witscript **) (*tx)->output_witscripts, - &state->first_per_commitment_point[REMOTE], - state->channel->option_static_remotekey); + *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; - wire_sync_write(HSM_FD, take(msg)); - msg = wire_sync_read(tmpctx, HSM_FD); - if (!fromwire_hsm_sign_tx_reply(msg, sig)) - status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s", - tal_hex(tmpctx, msg)); + wo = tx->wtx->outputs[i]; - /* You can tell this has been a problem before, since there's a debug - * message here: */ - status_debug("signature %s on tx %s using key %s", - type_to_string(tmpctx, struct bitcoin_signature, sig), - type_to_string(tmpctx, struct bitcoin_tx, *tx), - type_to_string(tmpctx, struct pubkey, - &state->our_funding_pubkey)); + /* This is a hack that excludes P2WSH outputs + * which for our implementation, are funding outputs */ + if (exclude_funding_output && wo.script_len == 34) + continue; - /* Now we give our peer the signature for their first commitment - * transaction. */ - msg = towire_funding_created(state, &state->channel_id, - &state->funding_txid, - state->funding_txout, - &sig->s); - sync_crypto_write(state->pps, msg); + out = tal(*outputs, struct output_info); + 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); - /* BOLT #2: - * - * ### The `funding_signed` Message - * - * This message gives the funder the signature it needs for the first - * commitment transaction, so it can broadcast the transaction knowing - * that funds can be redeemed, if need be. - */ - peer_billboard(false, - "Funding channel: create first tx, now waiting for their signature"); + tal_arr_expand(outputs, out); + } +} + +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, j; + + *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]->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]->sats), + type_to_string(tmpctx, struct amount_sat, + input_funding)); + + /** 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_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)) + 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 **local_inputs, + struct input_info **remote_inputs, + struct output_info **remote_outputs, + struct amount_sat stated_funding_sats) +{ + struct amount_sat funding, other_outputs, funding_tx_sats; + bool has_change_address; + size_t i = 0; + u8 *msg, *err_msg, *wscript; + + if (!check_remote_inputs(state, local_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; + /* 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 + * - 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]->sats)) { + 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]->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]->sats)); + + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - 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."); + + /* + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * - MUST NOT include the channel funding output. + */ + 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"); + } + + /** + * BOLT-343afe6a339617807ced92ab10480188f8e6970e #2 + * The receiving node: + * - 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", + 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)); + + /* 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; +} + +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, + struct output_info ***local_outputs, + struct input_info ***remote_inputs, + struct output_info ***remote_outputs) + +{ + struct channel_id id_in; + struct input_info *input; + struct output_info *output; + bool complete, last_sent_complete = false; + size_t i, queue_count; + 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 + */ + 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)); + + } + + if (tal_count(*local_inputs) == 0) + assert(role == ACCEPTER); + else + peer_billboard(false, "Opening channel: tx_add_inputs sent"); + + + /* + * BOLT-3f9f65d3ad5a21835994f9d9226ed9e0e4066662 #2 + * + * Either node: + * - MAY omit this message + */ + 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)); + } + + if (tal_count(*local_outputs) > 0) + peer_billboard(false, "Opening channel: tx_add_outputs sent"); + + + /* FIXME: allow for more interactive input/output composition */ + msg = towire_tx_complete(tmpctx, &state->channel_id); + sync_crypto_write(state->pps, take(msg)); + + /* 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); + + queue_count = 0; + while (!complete) { + u16 serial_id; + int type; + + /* 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; + + type = fromwire_peektype(msg); + switch (type) { + 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 tx_add_input %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + + // FIXME: verify podle? + tal_arr_expand(remote_inputs, input); + break; + 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 tx_add_output %s", + tal_hex(msg, msg)); + check_channel_id(state, &id_in, &state->channel_id); + + tal_arr_expand(remote_outputs, output); + break; + case WIRE_TX_REMOVE_INPUT: + if (!fromwire_tx_remove_input(msg, &id_in, &serial_id)) + peer_failed(state->pps, &state->channel_id, + "Parsing received tx_remove_input %s", + tal_hex(msg, msg)); + + check_channel_id(state, &id_in, &state->channel_id); + if (!remove_input(*remote_inputs, serial_id)) + peer_failed(state->pps, &state->channel_id, + "Attempted to remove unknown input %u", + serial_id); + + break; + case WIRE_TX_REMOVE_OUTPUT: + if (!fromwire_tx_remove_output(msg, &id_in, &serial_id)) + peer_failed(state->pps, &state->channel_id, + "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); + + 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 (tal_count(*remote_inputs) == 0) + peer_failed(state->pps, &state->channel_id, + "Opener must send at lease one input"); + + if (!last_sent_complete) { + 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 tx_ message, got %s", + tal_hex(msg, msg)); + + } + } + + /* Free the message queue */ + state->funding_msg_queue = tal_free(state->funding_msg_queue); + + return true; +} + +static u32 sum_witness_len(struct witness_stack *witness) +{ + u32 len = 0; + for (size_t i = 0; i < tal_count(witness->witness_element); i++) + /* 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; +} + +static char *check_remote_witnesses(struct witness_stack **witnesses, + struct input_info **inputs) +{ + size_t i; + 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)); + + //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++) { + 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, + &inputs[i]->prevtx_txid), + inputs[i]->prevtx_vout, + witness_len, inputs[i]->max_witness_len); + } + } + + return NULL; +} +#endif /*EXPERIMENTAL_FEATURES */ + +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 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; + struct bitcoin_txid remote_txid; + + struct witness_stack **remote_witnesses; + + /* Derive components, omitting the funding output */ + derive_input_output_info(state, *tx, utxos, true, + &local_ins, &local_outs); + + if (!send_receive_funding_tx_info(state, OPENER, + &local_ins, &local_outs, + &remote_ins, &remote_outs)) + return NULL; + + if (!check_remote_input_outputs(state, ACCEPTER, + local_ins, remote_ins, + remote_outs, + state->accepter_funding)) + return NULL; + + input_count = tal_count(local_ins) + tal_count(remote_ins); + void **map = tal_arr(state, void *, 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->locktime, + &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, + &opener_change, + (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, + true, + 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 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); + goto fail_1; + } + + 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_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"); + + /* Check that they're using the right channel_id */ + 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, + "Did not meet fees and reserve: %s", err_reason); + goto fail_2; + } + + + /* + * 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, + "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: 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); + } + map = tal_free(map); + + /* + * 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_tx_signatures(state, msg, &id_in, + &remote_txid, + &remote_witnesses)) + peer_failed(state->pps, + &state->channel_id, + "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); + 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, + &their_sig, + funding_tx, + state->funding_txout, + opener_change, + cast_const2(const struct witness_stack **, + remote_witnesses), + input_amts, + 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]); + + +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, + struct amount_msat local_msat, + struct bitcoin_signature *sig, + struct bitcoin_tx **tx) +{ + u8 *msg; + struct channel_id id_in; + const u8 *wscript; + char *err_reason; + + /*~ Now we can initialize the `struct channel`. This represents + * the current channel state and is how we can generate the current + * commitment transaction. + * + * The routines to support `struct channel` are split into a common + * part (common/initial_channel) which doesn't support HTLCs and is + * enough for us here, and the complete channel support required by + * `channeld` which lives in channeld/full_channel. */ + state->channel = new_initial_channel(state, + &state->funding_txid, + state->funding_txout, + state->minimum_depth, + total_funding(state), + local_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, + true, + LOCAL); + /* We were supposed to do enough checks above, but just in case, + * new_initial_channel will fail to create absurd channels */ + if (!state->channel) + peer_failed(state->pps, + &state->channel_id, + "could not create channel with given config"); + + /* BOLT #2: + * + * ### The `funding_created` Message + * + * This message describes the outpoint which the funder has created + * for the initial commitment transactions. After receiving the + * peer's signature, via `funding_signed`, it will broadcast the funding + * transaction. + */ + /* This gives us their first commitment transaction. */ + *tx = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[REMOTE], + REMOTE, &err_reason); + if (!*tx) { + /* This should not happen: we should never create channels we + * can't afford the fees for after reserve. */ + negotiation_failed(state, true, + "Could not meet their fees and reserve: %s", err_reason); + goto fail; + } + + /* We ask the HSM to sign their commitment transaction for us: it knows + * our funding key, it just needs the remote funding key to create the + * witness script. It also needs the amount of the funding output, + * as segwit signatures commit to that as well, even though it doesn't + * explicitly appear in the transaction itself. */ + msg = towire_hsm_sign_remote_commitment_tx(NULL, + *tx, + &state->channel->funding_pubkey[REMOTE], + state->channel->funding, + (const struct witscript **) (*tx)->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, sig)) + status_failed(STATUS_FAIL_HSM_IO, "Bad sign_tx_reply %s", + tal_hex(tmpctx, msg)); + + /* You can tell this has been a problem before, since there's a debug + * message here: */ + status_debug("signature %s on tx %s using key %s", + type_to_string(tmpctx, struct bitcoin_signature, sig), + type_to_string(tmpctx, struct bitcoin_tx, *tx), + type_to_string(tmpctx, struct pubkey, + &state->our_funding_pubkey)); + + /* Now we give our peer the signature for their first commitment + * transaction. */ + msg = towire_funding_created(state, &state->channel_id, + &state->funding_txid, + state->funding_txout, + &sig->s); + sync_crypto_write(state->pps, msg); + + /* BOLT #2: + * + * ### The `funding_signed` Message + * + * This message gives the funder the signature it needs for the first + * commitment transaction, so it can broadcast the transaction knowing + * that funds can be redeemed, if need be. + */ + peer_billboard(false, + "Funding channel: create first tx, now waiting for their signature"); + + /* Now they send us their signature for that first commitment + * transaction. */ + msg = opening_negotiate_msg(tmpctx, state, true); + if (!msg) + goto fail; + + sig->sighash_type = SIGHASH_ALL; + if (!fromwire_funding_signed(msg, &id_in, &sig->s)) + peer_failed(state->pps, + &state->channel_id, + "Parsing funding_signed: %s", tal_hex(msg, msg)); + + /* BOLT #2: + * + * This message introduces the `channel_id` to identify the channel. + * It's derived from the funding transaction by combining the + * `funding_txid` and the `funding_output_index`, using big-endian + * exclusive-OR (i.e. `funding_output_index` alters the last 2 + * bytes). + */ + + /*~ Back in Milan, we chose to allow multiple channels between peers in + * the protocol. I insisted that we multiplex these over the same + * socket, and (even though I didn't plan on implementing it anytime + * soon) that we put it into the first version of the protocol + * because it would be painful to add in later. + * + * My logic seemed sound: we treat new connections as an implication + * that the old connection has disconnected, which happens more often + * than you'd hope on modern networks. However, supporting multiple + * channels via multiple connections would be far easier for us to + * support with our (introduced-since) separate daemon model. + * + * Let this be a lesson: beware premature specification, even if you + * suspect "we'll need it later!". */ + derive_channel_id(&state->channel_id, + &state->funding_txid, state->funding_txout); + + if (!channel_id_eq(&id_in, &state->channel_id)) + peer_failed(state->pps, &id_in, + "funding_signed ids don't match: expected %s got %s", + type_to_string(msg, struct channel_id, + &state->channel_id), + type_to_string(msg, struct channel_id, &id_in)); + + /* BOLT #2: + * + * The recipient: + * - if `signature` is incorrect: + * - MUST fail the channel. + */ + /* So we create *our* initial commitment transaction, and check the + * signature they sent against that. */ + *tx = initial_channel_tx(state, &wscript, state->channel, + &state->first_per_commitment_point[LOCAL], + LOCAL, &err_reason); + if (!*tx) { + negotiation_failed(state, true, + "Could not meet our fees and reserve: %s", err_reason); + goto fail; + } + + if (!check_tx_sig(*tx, 0, NULL, wscript, &state->their_funding_pubkey, sig)) { + peer_failed(state->pps, + &state->channel_id, + "Bad signature %s on tx %s using key %s", + type_to_string(tmpctx, struct bitcoin_signature, + sig), + type_to_string(tmpctx, struct bitcoin_tx, *tx), + type_to_string(tmpctx, struct pubkey, + &state->their_funding_pubkey)); + } + + peer_billboard(false, "Funding channel: opening negotiation succeeded"); + + return true; + +fail: + tal_free(wscript); + return false; +} + +static u8 *funder_channel_complete(struct state *state, + struct bitcoin_tx *tx, + struct utxo **utxos) +{ + struct bitcoin_signature sig; + struct amount_msat local_msat; + + /* Update the billboard about what we're doing*/ + peer_billboard(false, + "Funding channel con't: continuing with funding_txid %s", + type_to_string(tmpctx, struct bitcoin_txid, &state->funding_txid)); + + /* We recalculate the local_msat from cached values; should + * succeed because we checked it earlier */ + 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->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; + + return towire_opening_funder_reply(state, + &state->remoteconf, + tx, + &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->minimum_depth, + &state->their_funding_pubkey, + &state->funding_txid, + state->funding_txout, + state->feerate_per_kw, + state->localconf.channel_reserve, + 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->sats = 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-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, + 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->sats = outputs[i]->amount; + infos[i] = info; + } + + 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; + 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; + const struct bitcoin_tx_input **remote_inputs; + 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 sha256 podle_h2; + + struct tlv_opening_tlvs *tlv = tlv_opening_tlvs_new(tmpctx); + if (!fromwire_open_channel2(open_channel2_msg, + &chain_hash, + &state->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->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; + + /* 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]; + } + + /* + * 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->first_node_is_us); + + 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"); + + /* Convert our inputs/outputs to the correct format */ + inputs_to_infos(state, utxos, &our_inputs); + our_outputs = outputs_to_infos(state, outputs); + + 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, + their_inputs, + their_outputs, + state->opener_funding)) + return NULL; + + /* 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, + 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 they send us their signature for that first commitment - * transaction. */ - msg = opening_negotiate_msg(tmpctx, state, true); + + /* We expect to get commitment_signed here */ + msg = opening_negotiate_msg(tmpctx, state, false); if (!msg) - goto fail; + return NULL; - sig->sighash_type = SIGHASH_ALL; - if (!fromwire_funding_signed(msg, &id_in, &sig->s)) + 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, - "Parsing funding_signed: %s", tal_hex(msg, msg)); + "Bad commitment_signed %s", tal_hex(msg, msg)); - /* BOLT #2: - * - * This message introduces the `channel_id` to identify the channel. - * It's derived from the funding transaction by combining the - * `funding_txid` and the `funding_output_index`, using big-endian - * exclusive-OR (i.e. `funding_output_index` alters the last 2 - * bytes). - */ + peer_billboard(false, "Incoming channel: commitment_signed received," + " composing funding tx"); - /*~ Back in Milan, we chose to allow multiple channels between peers in - * the protocol. I insisted that we multiplex these over the same - * socket, and (even though I didn't plan on implementing it anytime - * soon) that we put it into the first version of the protocol - * because it would be painful to add in later. - * - * My logic seemed sound: we treat new connections as an implication - * that the old connection has disconnected, which happens more often - * than you'd hope on modern networks. However, supporting multiple - * channels via multiple connections would be far easier for us to - * support with our (introduced-since) separate daemon model. - * - * Let this be a lesson: beware premature specification, even if you - * suspect "we'll need it later!". */ - derive_channel_id(&state->channel_id, - &state->funding_txid, state->funding_txout); + 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)); - if (!channel_id_eq(&id_in, &state->channel_id)) - peer_failed(state->pps, &id_in, - "funding_signed ids don't match: expected %s got %s", - type_to_string(msg, struct channel_id, - &state->channel_id), - type_to_string(msg, struct channel_id, &id_in)); + 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); - /* BOLT #2: - * - * The recipient: - * - if `signature` is incorrect: - * - MUST fail the channel. - */ - /* So we create *our* initial commitment transaction, and check the + /* 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"); + + /* 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. */ - *tx = initial_channel_tx(state, &wscript, state->channel, - &state->first_per_commitment_point[LOCAL], - LOCAL, &err_reason); - if (!*tx) { - negotiation_failed(state, true, + 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); - goto fail; + return NULL; } - if (!check_tx_sig(*tx, 0, NULL, wscript, &state->their_funding_pubkey, sig)) { + 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, - sig), - type_to_string(tmpctx, struct bitcoin_tx, *tx), + &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); + return NULL; } - peer_billboard(false, "Funding channel: opening negotiation succeeded"); + 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); - return true; + 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)); -fail: - tal_free(wscript); - return false; -} + /* + * 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, + state->locktime, + 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); -static u8 *funder_channel_complete(struct state *state) -{ - struct bitcoin_tx *tx; - struct bitcoin_signature sig; - struct amount_msat local_msat; + 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)); + } - /* Update the billboard about what we're doing*/ - peer_billboard(false, - "Funding channel con't: continuing with funding_txid %s", - type_to_string(tmpctx, struct bitcoin_txid, &state->funding_txid)); + /* 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 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)) - 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)); - if (!funder_finalize_channel_setup(state, local_msat, &sig, &tx)) - return NULL; + /* 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); - return towire_opening_funder_reply(state, - &state->remoteconf, - tx, - &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->minimum_depth, - &state->their_funding_pubkey, - &state->funding_txid, - state->funding_txout, - state->feerate_per_kw, - state->localconf.channel_reserve, - state->upfront_shutdown_script[REMOTE]); + /* 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 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 + * 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. */ + 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, + remote_inputs, + 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) @@ -917,7 +2472,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, @@ -939,7 +2494,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, @@ -959,76 +2514,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)); - 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->funding, chainparams->max_funding)) { - negotiation_failed(state, false, - "funding_satoshis %s too large", - type_to_string(tmpctx, struct amount_sat, - &state->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->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->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); + if (!fundee_check_primitives(state, chain_hash)) return NULL; - } /* This reserves 1% of the channel (rounded up) */ set_reserve(state); @@ -1065,20 +2552,22 @@ 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; /* 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->use_v2, + state->opener_funding, state->push_msat, state->remoteconf.dust_limit, state->remoteconf.max_htlc_value_in_flight, 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, @@ -1159,7 +2648,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)), @@ -1169,6 +2658,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. */ @@ -1285,7 +2775,9 @@ 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, + AMOUNT_SAT(0), + NULL, state->push_msat, channel_flags, state->feerate_per_kw, @@ -1304,8 +2796,28 @@ 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 + if (t == WIRE_OPEN_CHANNEL2) { + state->use_v2 = true; + return fundee_channel2(state, msg); + } + 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); + return NULL; + } +#endif /* EXPERIMENTAL_FEATURES */ #if DEVELOPER /* Handle custommsgs */ @@ -1410,15 +2922,20 @@ 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; + struct utxo **utxos; u16 funding_txout; 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->locktime, &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); @@ -1427,13 +2944,15 @@ 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, + &utxos, + &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, utxos); case WIRE_OPENING_FUNDER_CANCEL: /* We're aborting this, simple */ if (!fromwire_opening_funder_cancel(msg)) @@ -1451,11 +2970,15 @@ 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: 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; } @@ -1504,6 +3027,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->first_node_is_us, &chainparams, &state->our_features, &state->localconf, @@ -1546,6 +3070,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. */ 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); } diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 7caf703880a6..c598e52a6da0 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, @@ -101,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"); @@ -108,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); @@ -210,6 +222,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, @@ -233,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, @@ -242,6 +257,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? */ + 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", prepare_actual, cancel_start, @@ -408,6 +427,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/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 new file mode 100755 index 000000000000..883cbc188034 --- /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 pyln.client 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.to_satoshi_str()} + else: + return {'result': 'continue', 'funding_sats': their_funds.to_satoshi_str()} + + +plugin.run() 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_closing.py b/tests/test_closing.py index 5557b42e41fe..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,10 +504,13 @@ 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-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) diff --git a/tests/test_connection.py b/tests/test_connection.py index 0c06a85b695e..68ac78a35130 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 @@ -248,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() @@ -276,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) @@ -304,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) @@ -321,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) @@ -348,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) @@ -517,7 +547,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', @@ -541,13 +572,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', @@ -567,7 +599,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' @@ -907,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: + 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) @@ -992,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") @@ -1043,12 +1089,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 +1111,36 @@ 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'] + + # FIXME: external wallet opens currently disabled for v2 + if resp['open_channel_version'] == 2: + pytest.skip('running as v2, external wallet funding not permitted') + + 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 +1159,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) @@ -1151,7 +1195,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] @@ -1456,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. + # 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)) @@ -1766,7 +1819,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) @@ -2057,8 +2110,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. @@ -2074,7 +2132,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. diff --git a/tests/test_misc.py b/tests/test_misc.py index 37f3aaa1a214..ee2a2d5ad2fa 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 @@ -277,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) @@ -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 diff --git a/tests/test_opening.py b/tests/test_opening.py new file mode 100644 index 000000000000..4ec0022ade33 --- /dev/null +++ b/tests/test_opening.py @@ -0,0 +1,678 @@ +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, wait_for + +import os +import pytest +import re +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 + 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_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_rbf(node_factory, bitcoind): + # TODO: implement RBF! + assert True + + +@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual funding is experimental") +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") +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(may_reconnect=True, 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 + + 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'] + 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) + 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) + l3.rpc.fundchannel(l2.info['id'], amount) + + # 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']: + 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 + 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, [l1, l2, l3]) + + peers = l2.rpc.listpeers()['peers'] + assert len(peers) == 2 + for p in peers: + if p['id'] == l3.info['id']: + assert only_one(p['channels'])['state'] == 'CHANNELD_NORMAL' + else: + 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'): + 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 + 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'Channel is BORKED, cannot be closed'): + 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) + + +@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) == 2 + # The status for l1<->l2 is ok, l2<->l3 is borked + for p in peers: + 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 + + # 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) + + 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.""" + 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' + 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() + 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 + + +# 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 +# - an enterprising human can do this pretty straightforwardly. hmmmmmm diff --git a/tests/test_pay.py b/tests/test_pay.py index fad831c1d8f0..91fcf625fb92 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,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'], + + # 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)) @@ -1940,7 +1945,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) 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) 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/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 diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 1e2552dbade4..df554d651347 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -229,6 +229,10 @@ class Type(FieldSet): 'feature_set', 'onionmsg_path', 'route_hop', + 'bitcoin_tx_input', + 'output_info', + 'input_info', + 'witness_stack', ] # Some BOLT types are re-typed based on their field name @@ -238,6 +242,8 @@ 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', '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/tools/headerversions.tmp.28501 b/tools/headerversions.tmp.28501 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/wallet/db.c b/wallet/db.c index 3e06ce436a98..97c762316fc1 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,18 @@ 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}, + {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. */ @@ -1072,6 +1086,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/test/run-wallet.c b/wallet/test/run-wallet.c index 3a12cda3793b..4731240d16f9 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, @@ -562,6 +559,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, @@ -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)) @@ -756,6 +757,33 @@ 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); + channel->txowatches = tal(channel, u8); + + /* 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, 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, struct basepoints *basepoints, struct pubkey *funding_pubkey) @@ -854,7 +882,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; @@ -863,11 +891,16 @@ 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; 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)); @@ -895,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); @@ -932,8 +965,75 @@ 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, 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, 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); + CHECK(utxos[0]->spend_priority == spend_first); + tal_free(utxos); + + /* Expire the lease! */ + ld->topology->tip->height = height + reserve_for_blocks; + + 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"); + + /* 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); + + /* 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, 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"); + 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; @@ -943,12 +1043,12 @@ 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) == 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)); @@ -959,6 +1059,7 @@ static bool test_wallet_outputs(struct lightningd *ld, const tal_t *ctx) return true; } + static bool test_shachain_crud(struct lightningd *ld, const tal_t *ctx) { struct wallet_shachain a, b; @@ -1039,8 +1140,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 +1226,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, @@ -1450,6 +1551,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 86f1b6c0f0dd..3c4f3161facc 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 @@ -104,12 +107,15 @@ 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); 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); @@ -140,17 +146,89 @@ 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; } +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; + + 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, input_txid); + db_bind_int(stmt, 1, input_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_input_tx_exists(struct wallet *w, struct bitcoin_txid *txid, + u64 channel_dbid) +{ + 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); + + if (db_step(stmt)) { + match = db_column_u64(stmt, 0) > 0; + } else + match = false; + + tal_free(stmt); + return match; +} + +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)); +} + +void wallet_transaction_delete(struct wallet *w, const struct bitcoin_txid *txid) +{ + struct db_stmt *stmt; + + stmt = db_prepare_v2(w->db, SQL("DELETE FROM transactions" + " WHERE id = ?;")); + db_bind_txid(stmt, 0, txid); + db_exec_prepared_v2(take(stmt)); +} + /** * wallet_stmt2output - Extract data from stmt and fill an 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); @@ -175,6 +253,9 @@ 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; + utxo->reserved_at = NULL; + utxo->reserved_for = NULL; if (!db_column_is_null(stmt, 9)) { blockheight = tal(utxo, u32); @@ -193,10 +274,113 @@ 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; + } + + utxo->spend_priority = db_column_int(stmt, 14); return utxo; } +static bool reservation_expired(struct wallet *w, const struct utxo *utxo) +{ + 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, const struct utxo *utxo) +{ + return wallet_output_reservation_update(w, utxo, 0, 0); +} + +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" + ", 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); +} + +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, @@ -226,6 +410,134 @@ 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, + const 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 = ?" + ", spend_priority = ?" + " 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); + } + + /* 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); + + 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" + ", spend_priority" + " 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; @@ -245,8 +557,12 @@ 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" + ", spend_priority" + " FROM outputs " + " ORDER BY spend_priority DESC")); } else { stmt = db_prepare_v2(w->db, SQL("SELECT" " prev_out_tx" @@ -260,9 +576,13 @@ 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" + ", spend_priority" + " FROM outputs" + " WHERE status= ?" + " ORDER BY spend_priority DESC")); db_bind_int(stmt, 0, output_status_in_db(state)); } db_query_prepared(stmt); @@ -297,6 +617,9 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, ", confirmation_height" ", spend_height" ", scriptpubkey" + ", reserved_at" + ", reserved_for" + ", spend_priority" " FROM outputs" " WHERE channel_id IS NOT NULL AND " "confirmation_height IS NULL")); @@ -312,16 +635,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" + ", spend_priority" + " 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 */ +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); } /** @@ -339,33 +762,49 @@ 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"); - } } } + + 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) { 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); 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; @@ -393,12 +832,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 @@ -411,9 +850,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 */ @@ -436,8 +873,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, @@ -446,20 +883,21 @@ 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; } 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, @@ -471,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) @@ -527,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? */ @@ -537,6 +975,105 @@ 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 " + ", reserved_at" + ", reserved_for" + ", spend_priority" + " 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 " + ", reserved_at" + ", reserved_for" + ", spend_priority" + " 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; + 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); +} + +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) { @@ -873,7 +1410,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 +1430,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); - local_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 46, u8); + remote_shutdown_scriptpubkey = db_column_arr(tmpctx, stmt, 29, 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, 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 +1450,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 +1493,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 +1503,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 +1527,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 +1541,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 +1594,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" @@ -1088,7 +1628,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); @@ -1100,6 +1640,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; @@ -1335,6 +1881,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=?," @@ -1359,7 +1906,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); @@ -1371,37 +1918,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); @@ -1616,6 +2165,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; @@ -2867,21 +3417,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); @@ -3276,6 +3828,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) @@ -3643,24 +4217,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) diff --git a/wallet/wallet.h b/wallet/wallet.h index 540c26e0edaa..31070d82510f 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -63,11 +63,11 @@ 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; - /* Index of change output, or -1 if none. */ - int change_outnum; }; /* Possible states for tracked outputs in the database. Not sure yet @@ -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) { @@ -342,6 +349,33 @@ 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, const struct bitcoin_txid *input_txid, + u32 input_outnum, struct channel *channel, + struct bitcoin_txid *txid); + +/* 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. + */ +void wallet_transaction_delete(struct wallet *w, const struct bitcoin_txid *txid); + /** * wallet_confirm_tx - Confirm a tx which contains a UTXO. */ @@ -364,11 +398,44 @@ 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_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_channel_reservations_fetch(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. + * 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, + const struct utxo *utxo, + const u32 current_height, + const u32 reserved_for); /** * wallet_get_utxos - Retrieve all utxos matching a given state * * 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); @@ -385,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, @@ -399,6 +467,25 @@ 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_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 * @@ -1155,6 +1242,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 6ec384873a58..17906d31b941 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -82,12 +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, - utx->wtx->amount, - utx->wtx->change, - utx->wtx->change_key_index, + cast_const2(const struct bitcoin_tx_input **, + utx->inputs), cast_const2(const struct bitcoin_tx_output **, utx->outputs), utx->wtx->utxos, @@ -123,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 @@ -137,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; @@ -159,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) { @@ -170,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(); @@ -254,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. */ @@ -271,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, @@ -311,10 +362,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; @@ -328,46 +377,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; - - /* 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); + struct bitcoin_tx_output *output; - 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; - 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)); + 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" @@ -375,19 +399,17 @@ 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); } 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 +426,36 @@ 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; + 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"); - } else - changekey = NULL; + + + 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); + } + + (*utx)->inputs = NULL; + (*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)->inputs, + (*utx)->outputs, cmd->ld->wallet->bip32_base, - &(*utx)->change_outnum, - locktime); + locktime, + NULL); + bitcoin_txid((*utx)->tx, &(*utx)->txid); return NULL; @@ -795,6 +834,82 @@ 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 void add_utxo_info(struct command *cmd, + struct json_stream *stream, + struct channel *c) +{ + struct utxo_reservation **rezzies; + size_t i; + + 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); + 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, @@ -803,8 +918,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(); @@ -813,42 +927,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); @@ -864,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", @@ -880,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); } } 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 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 e18075749a01..e886305eef51 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, + bool node_1_first) +{ + struct sha256 h; + u8 ids[2 * 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); + 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) @@ -403,9 +428,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 +456,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/peer_wire.c b/wire/peer_wire.c index 737e2fbb6caa..7e314e6d1177 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -33,7 +33,17 @@ static bool unknown_type(enum wire_type t) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: -#endif + 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_INIT_RBF: + case WIRE_BLACKLIST_PODLE: +#endif /* EXPERIMENTAL_FEATURES */ return false; } return true; @@ -51,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: @@ -73,7 +86,16 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_GOSSIP_TIMESTAMP_FILTER: #if EXPERIMENTAL_FEATURES case WIRE_ONION_MESSAGE: -#endif + 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_INIT_RBF: +#endif /* EXPERIMENTAL_FEATURES */ break; } return false; diff --git a/wire/test/Makefile b/wire/test/Makefile index d0a8f542d203..7b1f89a1860e 100644 --- a/wire/test/Makefile +++ b/wire/test/Makefile @@ -9,6 +9,10 @@ WIRE_TEST_PROGRAMS := $(WIRE_TEST_OBJS:.o=) WIRE_TEST_COMMON_OBJS := \ common/utils.o +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/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 07c08f7c4816..ff5a109feac0 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,23 @@ 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)) +/* 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 { struct channel_id channel_id; @@ -180,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; @@ -236,6 +259,87 @@ struct msg_update_fee { u32 feerate_per_kw; }; +/* Open Channel 2 */ +struct msg_open_channel2 { + struct bitcoin_blkid chain_hash; + 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; + 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 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_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_tx_add_output { + struct amount_sat sats; + struct channel_id channel_id; + u16 serial_id; + u8 *script; +}; +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_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; + u8 fee_step; +}; + static void *towire_struct_channel_announcement(const tal_t *ctx, const struct msg_channel_announcement *s) { @@ -773,6 +877,404 @@ static struct msg_init *fromwire_struct_init(const tal_t *ctx, const void *p) return s; } +#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) +{ + return towire_open_channel2(ctx, + &s->chain_hash, + 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); +} + +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->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); +} +static void *towire_struct_accept_channel2(const tal_t *ctx, + const struct msg_accept_channel2 *s) +{ + return towire_accept_channel2(ctx, + &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) +{ + struct msg_accept_channel2 *s = tal(ctx, struct msg_accept_channel2); + s->tlv = tlv_accept_tlvs_new(ctx); + + if (fromwire_accept_channel2(p, &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)) + return s; + return tal_free(s); +} +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_tx_add_input *fromwire_struct_tx_add_input(const tal_t *ctx, const void *p) +{ + struct msg_tx_add_input *s = tal(ctx, struct msg_tx_add_input); + s->tlv = tlv_tx_add_input_tlvs_new(s); + + 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_tx_add_output(const tal_t *ctx, struct msg_tx_add_output *s) +{ + return towire_tx_add_output(ctx, + &s->channel_id, + s->serial_id, + s->sats, + s->script); +} +static struct msg_tx_add_output *fromwire_struct_tx_add_output(const tal_t *ctx, const void *p) +{ + struct msg_tx_add_output *s = tal(ctx, struct msg_tx_add_output); + + 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_tx_remove_input(const tal_t *ctx, struct msg_tx_remove_input *s) +{ + return towire_tx_remove_input(ctx, &s->channel_id, + s->serial_id); +} +static struct msg_tx_remove_input *fromwire_struct_tx_remove_input(const tal_t *ctx, const void *p) +{ + struct msg_tx_remove_input *s = tal(ctx, struct msg_tx_remove_input); + + if (fromwire_tx_remove_input(p, &s->channel_id, + &s->serial_id)) + return s; + return tal_free(s); +} +static void *towire_struct_tx_remove_output(const tal_t *ctx, struct msg_tx_remove_output *s) +{ + return towire_tx_remove_output(ctx, &s->channel_id, + s->serial_id); +} +static struct msg_tx_remove_output *fromwire_struct_tx_remove_output(const tal_t *ctx, const void *p) +{ + struct msg_tx_remove_output *s = tal(ctx, struct msg_tx_remove_output); + + 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); + + 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_tx_signatures(ctx, &s->channel_id, + &s->txid, + (const struct witness_stack **)s->witness_stacks); +} +static struct msg_tx_signatures *fromwire_struct_tx_signatures(const tal_t *ctx, const void *p) +{ + struct msg_tx_signatures *s = tal(ctx, struct msg_tx_signatures); + + if (fromwire_tx_signatures(ctx, p, + &s->channel_id, + &s->txid, + &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->locktime, + s->feerate_per_kw, + s->fee_step); +} +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(p, &s->channel_id, + &s->funding_satoshis, + &s->locktime, + &s->feerate_per_kw, + &s->fee_step)) + 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 podle_proof_eq(const struct tlv_tx_add_input_tlvs_podle_proof *a, + const struct tlv_tx_add_input_tlvs_podle_proof *b) +{ + return (!a && !b) + || (a && b && eq_between(a, b, p, sig)); +} + +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 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) +{ + 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 tx_add_input_eq(const struct msg_tx_add_input *a, + const struct msg_tx_add_input *b) +{ + 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 tx_add_output_eq(const struct msg_tx_add_output *a, + const struct msg_tx_add_output *b) +{ + return eq_with(a, b, serial_id) + && eq_var(a, b, script); +} + +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, 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 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); + 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) +{ + return eq_with(a, b, fee_step); +} + +static bool blacklist_podle_eq(const struct msg_blacklist_podle *a, + const struct msg_blacklist_podle *b) +{ + 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, const struct msg_channel_announcement *b) { @@ -943,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++) { \ @@ -955,6 +1457,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 +1501,21 @@ 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_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_blacklist_podle bp, *bp2; +#endif /* EXPERIMENTAL_FEATURES */ + void *ctx = tal(NULL, char); size_t i; u8 *msg; @@ -1177,6 +1707,130 @@ 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 = 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); + + 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 = 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); + + 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(&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++) { + 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++) { + 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_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)); + + 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(&bp, 2, sizeof(bp)); + set_node_id(&bp.node_id); + set_sha256(&bp.podle_h2); + + 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 */ secp256k1_context_destroy(secp256k1_ctx); tal_free(ctx); 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 a9bc8e89d9d7..af90f2f3c179 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -44,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, + bool node_1_first); + /* 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); @@ -167,4 +173,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 */