diff --git a/channeld/Makefile b/channeld/Makefile index 88c1742dc..5929c53a4 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -16,14 +16,17 @@ LIGHTNINGD_CHANNEL_HEADERS_NOGEN := \ channeld/channeld_htlc.h \ channeld/commit_tx.h \ channeld/full_channel.h \ - channeld/full_channel_error.h + channeld/full_channel_error.h \ + channeld/watchtower.h LIGHTNINGD_CHANNEL_HEADERS := $(LIGHTNINGD_CHANNEL_HEADERS_GEN) $(LIGHTNINGD_CHANNEL_HEADERS_NOGEN) LIGHTNINGD_CHANNEL_SRC := channeld/channeld.c \ channeld/commit_tx.c \ - channeld/full_channel.c \ - channeld/gen_channel_wire.c + channeld/full_channel.c \ + channeld/gen_channel_wire.c \ + channeld/watchtower.c + LIGHTNINGD_CHANNEL_OBJS := $(LIGHTNINGD_CHANNEL_SRC:.c=.o) # Make sure these depend on everything. diff --git a/channeld/watchtower.c b/channeld/watchtower.c new file mode 100644 index 000000000..235781cbd --- /dev/null +++ b/channeld/watchtower.c @@ -0,0 +1,120 @@ +#include "watchtower.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const u8 ONE = 0x1; +#define HSM_FD 6 + +const struct bitcoin_tx * +penalty_tx_create(const tal_t *ctx, + const struct channel *channel, + u32 penalty_feerate, + u8 *final_scriptpubkey, + const struct secret *revocation_preimage, + const struct bitcoin_txid *commitment_txid, + s16 to_them_outnum, struct amount_sat to_them_sats) +{ + u8 *wscript; + struct bitcoin_tx *tx; + struct keyset keyset; + size_t weight; + u8 *msg; + struct amount_sat fee, min_out, amt; + struct bitcoin_signature sig; + u32 locktime = 0; + bool option_static_remotekey = channel->option_static_remotekey; + u8 **witness; + u32 remote_to_self_delay = channel->config[REMOTE].to_self_delay; + const struct amount_sat dust_limit = channel->config[LOCAL].dust_limit; + BUILD_ASSERT(sizeof(struct secret) == sizeof(*revocation_preimage)); + const struct secret remote_per_commitment_secret = *revocation_preimage; + struct pubkey remote_per_commitment_point; + const struct basepoints *basepoints = channel->basepoints; + + if (to_them_outnum == -1 || + amount_sat_less_eq(to_them_sats, dust_limit)) { + status_unusual( + "Cannot create penalty transaction because there " + "is no non-dust to_them output in the commitment."); + return NULL; + } + + if (!pubkey_from_secret(&remote_per_commitment_secret, &remote_per_commitment_point)) + status_broken("Failed derive from per_commitment_secret %s", + type_to_string(tmpctx, struct secret, + &remote_per_commitment_secret)); + + if (!derive_keyset(&remote_per_commitment_point, + &basepoints[REMOTE], + &basepoints[LOCAL], + option_static_remotekey, + &keyset)) + abort(); /* TODO(cdecker) Handle a bit more gracefully */ + + wscript = bitcoin_wscript_to_local(tmpctx, remote_to_self_delay, + &keyset.self_revocation_key, + &keyset.self_delayed_payment_key); + + tx = bitcoin_tx(ctx, chainparams, 1, 1, locktime); + bitcoin_tx_add_input(tx, commitment_txid, to_them_outnum, 0xFFFFFFFF, + to_them_sats, NULL); + + bitcoin_tx_add_output(tx, final_scriptpubkey, to_them_sats); + + /* Worst-case sig is 73 bytes */ + weight = bitcoin_tx_weight(tx) + 1 + 3 + 73 + 0 + tal_count(wscript); + weight = elements_add_overhead(weight, 1, 1); + fee = amount_tx_fee(penalty_feerate, weight); + + if (!amount_sat_add(&min_out, dust_limit, fee)) + status_broken( + "Cannot add dust_limit %s and fee %s", + type_to_string(tmpctx, struct amount_sat, &dust_limit), + type_to_string(tmpctx, struct amount_sat, &fee)); + + if (amount_sat_less(to_them_sats, min_out)) { + /* FIXME: We should use SIGHASH_NONE so others can take it */ + fee = amount_tx_fee(feerate_floor(), weight); + } + + /* This can only happen if feerate_floor() is still too high; shouldn't + * happen! */ + if (!amount_sat_sub(&amt, to_them_sats, fee)) { + amt = dust_limit; + status_broken( + "TX can't afford minimal feerate" + "; setting output to %s", + type_to_string(tmpctx, struct amount_sat, &amt)); + } + bitcoin_tx_output_set_amount(tx, 0, amt); + bitcoin_tx_finalize(tx); + + u8 *hsm_sign_msg = + towire_hsm_sign_penalty_to_us(ctx, &remote_per_commitment_secret, tx, + wscript, *tx->input_amounts[0]); + + if (!wire_sync_write(HSM_FD, take(hsm_sign_msg))) + status_broken("Writing sign request to hsm"); + + msg = wire_sync_read(tmpctx, HSM_FD); + if (!msg || !fromwire_hsm_sign_tx_reply(msg, &sig)) { + status_broken("Reading sign_tx_reply: %s", tal_hex(tmpctx, msg)); + abort(); + } + + witness = bitcoin_witness_sig_and_element(tx, &sig, &ONE, sizeof(ONE), + wscript); + + bitcoin_tx_input_set_witness(tx, 0, take(witness)); + return tx; +} diff --git a/channeld/watchtower.h b/channeld/watchtower.h new file mode 100644 index 000000000..9e197f0d3 --- /dev/null +++ b/channeld/watchtower.h @@ -0,0 +1,18 @@ +#ifndef LIGHTNING_CHANNELD_WATCHTOWER_H +#define LIGHTNING_CHANNELD_WATCHTOWER_H +#include "config.h" +#include +#include +#include +#include + +const struct bitcoin_tx * +penalty_tx_create(const tal_t *ctx, + const struct channel *channel, + u32 penalty_feerate, + u8 *final_scriptpubkey, + const struct secret *revocation_preimage, + const struct bitcoin_txid *commitment_txid, + s16 to_them_outnum, struct amount_sat to_them_sats); + +#endif /* LIGHTNING_CHANNELD_WATCHTOWER_H */ diff --git a/common/initial_channel.h b/common/initial_channel.h index 35bee57ea..cca1e14fa 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/lightningd/Makefile b/lightningd/Makefile index 8606f8865..4419d5f54 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -42,6 +42,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/htlc_trim.o \ common/htlc_wire.o \ common/key_derive.o \ + common/keyset.o \ common/io_lock.o \ common/json.o \ common/json_helpers.o \