From 065f11b42adc1e9d540a9f58af4a618de53287ad Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 21 Feb 2017 15:15:29 +1030 Subject: [PATCH] lightningd/opening: opening daemon. This conducts the conversation up until we have the txid to wait for (or broadcast). Signed-off-by: Rusty Russell --- lightningd/Makefile | 1 + lightningd/opening/Makefile | 66 ++ lightningd/opening/opening.c | 648 ++++++++++++++++++++ lightningd/opening/opening_control_wire.csv | 58 ++ lightningd/opening/opening_status_wire.csv | 20 + 5 files changed, 793 insertions(+) create mode 100644 lightningd/opening/Makefile create mode 100644 lightningd/opening/opening.c create mode 100644 lightningd/opening/opening_control_wire.csv create mode 100644 lightningd/opening/opening_status_wire.csv diff --git a/lightningd/Makefile b/lightningd/Makefile index 3ba8c5f8d..88c6129c8 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -93,6 +93,7 @@ LIGHTNINGD_HEADERS = $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) $(LIG include lightningd/hsm/Makefile include lightningd/handshake/Makefile include lightningd/gossip/Makefile +include lightningd/opening/Makefile $(LIGHTNINGD_OBJS) $(LIGHTNINGD_LIB_OBJS): $(LIGHTNINGD_HEADERS) diff --git a/lightningd/opening/Makefile b/lightningd/opening/Makefile new file mode 100644 index 000000000..a93ccebe0 --- /dev/null +++ b/lightningd/opening/Makefile @@ -0,0 +1,66 @@ +#! /usr/bin/make + +# Designed to be run one level up +lightningd/opening-wrongdir: + $(MAKE) -C ../.. lightningd/opening-all + +default: lightningd/opening-all + +lightningd/opening-all: lightningd/lightningd_opening + +# lightningd/opening needs these: +LIGHTNINGD_OPENING_HEADERS_GEN := \ + lightningd/opening/gen_opening_control_wire.h \ + lightningd/opening/gen_opening_status_wire.h + +LIGHTNINGD_OPENING_HEADERS_NOGEN := + +LIGHTNINGD_OPENING_HEADERS := $(LIGHTNINGD_OPENING_HEADERS_GEN) $(LIGHTNINGD_OPENING_HEADERS_NOGEN) + +LIGHTNINGD_OPENING_SRC := lightningd/opening/opening.c \ + $(LIGHTNINGD_OPENING_HEADERS:.h=.c) +LIGHTNINGD_OPENING_OBJS := $(LIGHTNINGD_OPENING_SRC:.c=.o) + +# Control daemon uses this: +LIGHTNINGD_OPENING_CONTROL_HEADERS := $(LIGHTNINGD_OPENING_HEADERS) +LIGHTNINGD_OPENING_CONTROL_SRC := $(LIGHTNINGD_OPENING_HEADERS:.h=.c) +LIGHTNINGD_OPENING_CONTROL_OBJS := $(LIGHTNINGD_OPENING_CONTROL_SRC:.c=.o) + +LIGHTNINGD_OPENING_GEN_SRC := $(filter lightningd/opening/gen_%, $(LIGHTNINGD_OPENING_SRC) $(LIGHTNINGD_OPENING_CONTROL_SRC)) + +LIGHTNINGD_OPENING_SRC_NOGEN := $(filter-out lightningd/opening/gen_%, $(LIGHTNINGD_OPENING_SRC)) + +# Add to headers which any object might need. +LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_OPENING_HEADERS_GEN) +LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_OPENING_HEADERS_NOGEN) + +$(LIGHTNINGD_OPENING_OBJS): $(LIGHTNINGD_HEADERS) + +lightningd/opening/gen_opening_control_wire.h: $(WIRE_GEN) lightningd/opening/opening_control_wire.csv + $(WIRE_GEN) --header $@ opening_control_wire_type < lightningd/opening/opening_control_wire.csv > $@ + +lightningd/opening/gen_opening_control_wire.c: $(WIRE_GEN) lightningd/opening/opening_control_wire.csv + $(WIRE_GEN) ${@:.c=.h} opening_control_wire_type < lightningd/opening/opening_control_wire.csv > $@ + +lightningd/opening/gen_opening_status_wire.h: $(WIRE_GEN) lightningd/opening/opening_status_wire.csv + $(WIRE_GEN) --header $@ opening_status_wire_type < lightningd/opening/opening_status_wire.csv > $@ + +lightningd/opening/gen_opening_status_wire.c: $(WIRE_GEN) lightningd/opening/opening_status_wire.csv + $(WIRE_GEN) ${@:.c=.h} opening_status_wire_type < lightningd/opening/opening_status_wire.csv > $@ + +LIGHTNINGD_OPENING_OBJS := $(LIGHTNINGD_OPENING_SRC:.c=.o) $(LIGHTNINGD_OPENING_GEN_SRC:.c=.o) + +lightningd/lightningd_opening: $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_OPENING_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a libsodium.a + $(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) + +check-source: $(LIGHTNINGD_OPENING_SRC_NOGEN:%=check-src-include-order/%) +check-source-bolt: $(LIGHTNINGD_OPENING_SRC:%=bolt-check/%) $(LIGHTNINGD_OPENING_HEADERS:%=bolt-check/%) + +check-whitespace: $(LIGHTNINGD_OPENING_SRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_OPENING_HEADERS_NOGEN:%=check-whitespace/%) + +clean: lightningd/opening-clean + +lightningd/opening-clean: + $(RM) $(LIGHTNINGD_OPENING_OBJS) gen_* + +-include lightningd/opening/test/Makefile diff --git a/lightningd/opening/opening.c b/lightningd/opening/opening.c new file mode 100644 index 000000000..5d1fab6d3 --- /dev/null +++ b/lightningd/opening/opening.c @@ -0,0 +1,648 @@ +/* FIXME: Handle incoming gossip messages! */ +/* FIXME: send peer PKT_ERR when failing! */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Stdout == status, stdin == requests, 3 == peer */ +#define STATUS_FD STDOUT_FILENO +#define REQ_FD STDIN_FILENO +#define PEER_FD 3 + +struct points { + struct pubkey funding_pubkey; + struct pubkey revocation_basepoint; + struct pubkey payment_basepoint; + struct pubkey delayed_payment_basepoint; +}; + +struct secrets { + struct privkey funding_privkey; + struct privkey revocation_basepoint_secret; + struct privkey payment_basepoint_secret; + struct privkey delayed_payment_basepoint_secret; +}; + +struct state { + struct crypto_state *cs; + struct pubkey next_per_commit[NUM_SIDES]; + + /* Funding and feerate: set by opening peer. */ + u64 funding_satoshis, push_msat; + u32 feerate_per_kw; + struct sha256_double funding_txid; + u8 funding_txout; + + /* Secret keys and basepoint secrets. */ + struct secrets our_secrets; + + /* Our shaseed for generating per-commitment-secrets. */ + struct sha256 shaseed; + struct channel_config *localconf, *remoteconf, *minconf, *maxconf; + + struct channel *channel; +}; + +static void derive_our_basepoints(const struct sha256 *seed, + struct points *points, + struct secrets *secrets, + struct sha256 *shaseed, + struct pubkey *first_per_commit) +{ + struct sha256 per_commit_secret; + struct keys { + struct privkey f, r, p, d; + struct sha256 shaseed; + } keys; + + hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(seed), + "c-lightning", strlen("c-lightning")); + + secrets->funding_privkey = keys.f; + secrets->revocation_basepoint_secret = keys.r; + secrets->payment_basepoint_secret = keys.p; + secrets->delayed_payment_basepoint_secret = keys.d; + + if (!pubkey_from_privkey(&keys.f, &points->funding_pubkey) + || !pubkey_from_privkey(&keys.r, &points->revocation_basepoint) + || !pubkey_from_privkey(&keys.p, &points->payment_basepoint) + || !pubkey_from_privkey(&keys.d, &points->delayed_payment_basepoint)) + status_failed(WIRE_OPENING_KEY_DERIVATION_FAILED, + "seed = %s", + type_to_string(trc, struct sha256, seed)); + + /* BOLT #3: + * + * A node MUST select an unguessable 256-bit seed for each connection, + * and MUST NOT reveal the seed. + */ + *shaseed = keys.shaseed; + + /* BOLT #3: + * + * the first secret used MUST be index 281474976710655, and then the + * index decremented. */ + shachain_from_seed(shaseed, 281474976710655ULL, &per_commit_secret); + + /* BOLT #3: + * + * The `per-commitment-point` is generated using EC multiplication: + * + * per-commitment-point = per-commitment-secret * G + */ + if (secp256k1_ec_pubkey_create(secp256k1_ctx, + &first_per_commit->pubkey, + per_commit_secret.u.u8) != 1) + status_failed(WIRE_OPENING_KEY_DERIVATION_FAILED, + "first_per_commit create failed, secret = %s", + type_to_string(trc, struct sha256, + &per_commit_secret)); +} + +/* Yes, this multi-evaluates, and isn't do-while wrapped. */ +#define test_config_inrange(conf, min, max, field, fmt) \ + if ((conf)->field < (min)->field || (conf)->field > (max)->field) \ + status_failed(WIRE_OPENING_PEER_BAD_CONFIG, \ + #field " %"fmt" too large (%"fmt"-%"fmt")", \ + (conf)->field, (min)->field, (max)->field) + +#define test_config_inrange_u64(conf, min, max, field) \ + test_config_inrange(conf, min, max, field, PRIu64) +#define test_config_inrange_u32(conf, min, max, field) \ + test_config_inrange(conf, min, max, field, "u") +#define test_config_inrange_u16(conf, min, max, field) \ + test_config_inrange(conf, min, max, field, "u") + +static void check_config_bounds(const struct channel_config *remoteconf, + const struct channel_config *minc, + const struct channel_config *maxc) +{ + /* BOLT #2: + * + * It MUST fail the channel if `max-accepted-htlcs` is greater than + * 511. + */ + if (maxc->max_accepted_htlcs > 511) + status_failed(WIRE_OPENING_BAD_PARAM, + "max->max_accepted_htlcs %u too large", + maxc->max_accepted_htlcs); + + /* BOLT #2: + * + * The receiving node MUST fail the channel if `to-self-delay` is + * unreasonably large. The receiver MAY fail the channel if + * `funding-satoshis` is too small.... The receiving node MAY fail + * the channel if it considers `htlc-minimum-msat` too large, + * `max-htlc-value-in-flight` too small, `channel-reserve-satoshis` + * too large, or `max-accepted-htlcs` too small. + * + * The receiver MUST fail the channel if it considers `feerate-per-kw` + * too small for timely processing, or unreasonably large. + */ + /* We simply compare every field, and let the master daemon sort out + the bounds. */ + test_config_inrange_u64(remoteconf, minc, maxc, dust_limit_satoshis); + test_config_inrange_u64(remoteconf, minc, maxc, channel_reserve_satoshis); + test_config_inrange_u32(remoteconf, minc, maxc, minimum_depth); + test_config_inrange_u32(remoteconf, minc, maxc, htlc_minimum_msat); + test_config_inrange_u16(remoteconf, minc, maxc, to_self_delay); + test_config_inrange_u16(remoteconf, minc, maxc, max_accepted_htlcs); +} + +static bool check_commit_sig(const struct state *state, + const struct pubkey *our_funding_key, + const struct pubkey *their_funding_key, + struct bitcoin_tx *tx, + const secp256k1_ecdsa_signature *remotesig) +{ + u8 *wscript; + bool ret; + + wscript = bitcoin_redeem_2of2(state, + our_funding_key, their_funding_key); + + ret = check_tx_sig(tx, 0, NULL, wscript, their_funding_key, remotesig); + tal_free(wscript); + return ret; +} + +static secp256k1_ecdsa_signature +sign_remote_commit(const struct state *state, + const struct pubkey *our_funding_key, + const struct pubkey *their_funding_key, + struct bitcoin_tx *tx) +{ + u8 *wscript; + secp256k1_ecdsa_signature sig; + + wscript = bitcoin_redeem_2of2(state, + our_funding_key, their_funding_key); + + /* Commit tx only has one input: funding tx. */ + sign_tx_input(tx, 0, NULL, wscript, &state->our_secrets.funding_privkey, + our_funding_key, &sig); + tal_free(wscript); + return sig; +} + +static void open_channel(struct state *state, const struct points *ours) +{ + struct channel_id tmpid, tmpid2; + u8 *msg; + struct bitcoin_tx *tx; + struct points theirs; + secp256k1_ecdsa_signature sig; + + /* BOLT #2: + * + * A sending node MUST set the most significant bit in + * `temporary-channel-id`, and MUST ensure it is unique from any other + * channel id with the same peer. + */ + /* We don't support more than one channel, so this is easy. */ + memset(&tmpid, 0xFF, sizeof(tmpid)); + + /* BOLT #2: + * + * The sender MUST set `funding-satoshis` to less than 2^24 satoshi. */ + if (state->funding_satoshis >= 1 << 24) + status_failed(WIRE_OPENING_BAD_PARAM, + "funding_satoshis must be < 2^24"); + + /* BOLT #2: + * + * The sender MUST set `push-msat` to equal or less than to 1000 * + * `funding-satoshis`. + */ + if (state->push_msat > 1000 * state->funding_satoshis) + status_failed(WIRE_OPENING_BAD_PARAM, + "push-msat must be < %"PRIu64, + 1000 * state->funding_satoshis); + + msg = towire_open_channel(state, &tmpid, + state->funding_satoshis, state->push_msat, + state->localconf->dust_limit_satoshis, + state->localconf->max_htlc_value_in_flight_msat, + state->localconf->channel_reserve_satoshis, + state->localconf->htlc_minimum_msat, + state->feerate_per_kw, + state->localconf->to_self_delay, + state->localconf->max_accepted_htlcs, + &ours->funding_pubkey, + &ours->revocation_basepoint, + &ours->payment_basepoint, + &ours->delayed_payment_basepoint, + &state->next_per_commit[LOCAL]); + if (!sync_crypto_write(state->cs, PEER_FD, msg)) + status_failed(WIRE_OPENING_PEER_WRITE_FAILED, + "Writing open_channel"); + + state->remoteconf = tal(state, struct channel_config); + + msg = sync_crypto_read(state, state->cs, PEER_FD); + if (!msg) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Reading accept_channel"); + + /* BOLT #2: + * + * The receiver MUST fail the channel if `funding-pubkey`, + * `revocation-basepoint`, `payment-basepoint` or + * `delayed-payment-basepoint` are not valid DER-encoded compressed + * secp256k1 pubkeys. + */ + if (!fromwire_accept_channel(msg, NULL, &tmpid2, + &state->remoteconf->dust_limit_satoshis, + &state->remoteconf + ->max_htlc_value_in_flight_msat, + &state->remoteconf + ->channel_reserve_satoshis, + &state->remoteconf->htlc_minimum_msat, + &state->feerate_per_kw, + &state->remoteconf->to_self_delay, + &state->remoteconf->max_accepted_htlcs, + &theirs.funding_pubkey, + &theirs.revocation_basepoint, + &theirs.payment_basepoint, + &theirs.delayed_payment_basepoint, + &state->next_per_commit[REMOTE])) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Parsing accept_channel %s", tal_hex(msg, msg)); + + /* BOLT #2: + * + * The `temporary-channel-id` MUST be the same as the + * `temporary-channel-id` in the `open_channel` message. */ + if (!structeq(&tmpid, &tmpid2)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "accept_channel ids don't match: sent %s got %s", + type_to_string(msg, struct channel_id, &tmpid), + type_to_string(msg, struct channel_id, &tmpid2)); + + check_config_bounds(state->remoteconf, + state->minconf, state->maxconf); + + /* Now, ask master create a transaction to pay those two addresses. */ + msg = towire_opening_open_resp(state, &ours->funding_pubkey, + &theirs.funding_pubkey); + wire_sync_write(STATUS_FD, msg); + + /* Expect funding tx. */ + msg = wire_sync_read(state, REQ_FD); + if (!fromwire_opening_open_funding(msg, NULL, + &state->funding_txid, + &state->funding_txout)) + status_failed(WIRE_BAD_COMMAND, "reading opening_open_funding"); + + state->channel = new_channel(state, + &state->funding_txid, + state->funding_txout, + state->funding_satoshis, + state->push_msat, + state->feerate_per_kw, + state->localconf, + state->remoteconf, + &ours->revocation_basepoint, + &theirs.revocation_basepoint, + &ours->payment_basepoint, + &theirs.payment_basepoint, + &ours->delayed_payment_basepoint, + &theirs.delayed_payment_basepoint, + LOCAL); + if (!state->channel) + status_failed(WIRE_OPENING_BAD_PARAM, + "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, it will broadcast the funding transaction. + */ + tx = channel_tx(state, state->channel, + &state->next_per_commit[REMOTE], + NULL, REMOTE); + sig = sign_remote_commit(state, + &ours->funding_pubkey, &theirs.funding_pubkey, + tx); + msg = towire_funding_created(state, &tmpid, + &state->funding_txid.sha, + state->funding_txout, + &sig); + if (!sync_crypto_write(state->cs, PEER_FD, msg)) + status_failed(WIRE_OPENING_PEER_WRITE_FAILED, + "Writing funding_created"); + + /* BOLT #2: + * + * ### The `funding_signed` message + * + * This message gives the funder the signature they need for the first + * commitment transaction, so they can broadcast it knowing they can + * redeem their funds if they need to. + */ + msg = sync_crypto_read(state, state->cs, PEER_FD); + if (!msg) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Reading funding_signed"); + + if (!fromwire_funding_signed(msg, NULL, &tmpid2, &sig)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Parsing funding_signed"); + if (!structeq(&tmpid, &tmpid2)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "funding_signed ids don't match: sent %s got %s", + type_to_string(msg, struct channel_id, &tmpid), + type_to_string(msg, struct channel_id, &tmpid2)); + + /* BOLT #2: + * + * The recipient MUST fail the channel if `signature` is incorrect. + */ + tx = channel_tx(state, state->channel, + &state->next_per_commit[LOCAL], NULL, LOCAL); + + if (!check_commit_sig(state, &ours->funding_pubkey, + &theirs.funding_pubkey, tx, &sig)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Bad signature %s on tx %s using key %s", + type_to_string(trc, secp256k1_ecdsa_signature, + &sig), + type_to_string(trc, struct bitcoin_tx, tx), + type_to_string(trc, struct pubkey, + &theirs.funding_pubkey)); + + /* BOLT #2: + * + * Once the channel funder receives the `funding_signed` message, they + * must broadcast the funding transaction to the Bitcoin network. + */ + msg = towire_opening_open_funding_resp(state, + state->remoteconf, + &sig, + state->cs, + &theirs.revocation_basepoint, + &theirs.payment_basepoint, + &theirs.delayed_payment_basepoint, + &state->next_per_commit[REMOTE]); + + status_send(msg); +} + +/* This is handed the message the peer sent which caused gossip to stop: + * it should be an open_channel */ +static void recv_channel(struct state *state, const struct points *ours, + const u8 *peer_msg) +{ + struct channel_id tmpid, tmpid2; + struct points theirs; + secp256k1_ecdsa_signature theirsig, sig; + struct bitcoin_tx *tx; + u8 *msg; + + state->remoteconf = tal(state, struct channel_config); + + /* BOLT #2: + * + * The receiver MUST fail the channel if `funding-pubkey`, + * `revocation-basepoint`, `payment-basepoint` or + * `delayed-payment-basepoint` are not valid DER-encoded compressed + * secp256k1 pubkeys. + */ + if (!fromwire_open_channel(peer_msg, NULL, &tmpid, + &state->funding_satoshis, &state->push_msat, + &state->remoteconf->dust_limit_satoshis, + &state->remoteconf->max_htlc_value_in_flight_msat, + &state->remoteconf->channel_reserve_satoshis, + &state->remoteconf->htlc_minimum_msat, + &state->feerate_per_kw, + &state->remoteconf->to_self_delay, + &state->remoteconf->max_accepted_htlcs, + &theirs.funding_pubkey, + &theirs.revocation_basepoint, + &theirs.payment_basepoint, + &theirs.delayed_payment_basepoint, + &state->next_per_commit[REMOTE])) + status_failed(WIRE_OPENING_PEER_BAD_INITIAL_MESSAGE, + "Parsing open_channel %s", + tal_hex(peer_msg, peer_msg)); + + /* BOLT #2: + * + * The receiving node ... MUST fail the channel if `funding-satoshis` + * is greater than or equal to 2^24 */ + if (state->funding_satoshis >= 1 << 24) + status_failed(WIRE_OPENING_PEER_BAD_FUNDING, + "funding_satoshis %"PRIu64" too large", + state->funding_satoshis); + + /* BOLT #2: + * + * The receiving node ... MUST fail the channel if `push-msat` is + * greater than `funding-satoshis` * 1000. + */ + if (state->push_msat > state->funding_satoshis * 1000) + status_failed(WIRE_OPENING_PEER_BAD_FUNDING, + "push_msat %"PRIu64 + " too large for funding_satoshis %"PRIu64, + state->push_msat, state->funding_satoshis); + + check_config_bounds(state->remoteconf, + state->minconf, state->maxconf); + + msg = towire_accept_channel(state, &tmpid, + state->localconf->dust_limit_satoshis, + state->localconf + ->max_htlc_value_in_flight_msat, + state->localconf->channel_reserve_satoshis, + state->localconf->htlc_minimum_msat, + state->feerate_per_kw, + state->localconf->to_self_delay, + state->localconf->max_accepted_htlcs, + &ours->funding_pubkey, + &ours->revocation_basepoint, + &ours->payment_basepoint, + &ours->delayed_payment_basepoint, + &state->next_per_commit[REMOTE]); + + if (!sync_crypto_write(state->cs, PEER_FD, msg)) + status_failed(WIRE_OPENING_PEER_WRITE_FAILED, + "Writing accept_channel"); + + msg = sync_crypto_read(state, state->cs, PEER_FD); + if (!msg) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Reading funding_created"); + + if (!fromwire_funding_created(msg, NULL, &tmpid2, + &state->funding_txid.sha, + &state->funding_txout, + &theirsig)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Parsing funding_created"); + + /* BOLT #2: + * + * The sender MUST set `temporary-channel-id` the same as the + * `temporary-channel-id` in the `open_channel` message. */ + if (!structeq(&tmpid, &tmpid2)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "funding_created ids don't match: sent %s got %s", + type_to_string(msg, struct channel_id, &tmpid), + type_to_string(msg, struct channel_id, &tmpid2)); + + state->channel = new_channel(state, + &state->funding_txid, + state->funding_txout, + state->funding_satoshis, + state->push_msat, + state->feerate_per_kw, + state->localconf, + state->remoteconf, + &ours->revocation_basepoint, + &theirs.revocation_basepoint, + &ours->payment_basepoint, + &theirs.payment_basepoint, + &ours->delayed_payment_basepoint, + &theirs.delayed_payment_basepoint, + REMOTE); + if (!state->channel) + status_failed(WIRE_OPENING_BAD_PARAM, + "could not create channel with given config"); + + /* BOLT #2: + * + * The recipient MUST fail the channel if `signature` is incorrect. + */ + tx = channel_tx(state, state->channel, + &state->next_per_commit[LOCAL], NULL, LOCAL); + + if (!check_commit_sig(state, &ours->funding_pubkey, + &theirs.funding_pubkey, tx, &theirsig)) + status_failed(WIRE_OPENING_PEER_READ_FAILED, + "Bad signature %s on tx %s using key %s", + type_to_string(trc, secp256k1_ecdsa_signature, + &sig), + type_to_string(trc, struct bitcoin_tx, tx), + type_to_string(trc, struct pubkey, + &theirs.funding_pubkey)); + + /* BOLT #2: + * + * ### The `funding_signed` message + * + * This message gives the funder the signature they need for the first + * commitment transaction, so they can broadcast it knowing they can + * redeem their funds if they need to. + */ + tx = channel_tx(state, state->channel, + &state->next_per_commit[REMOTE], NULL, REMOTE); + sig = sign_remote_commit(state, + &ours->funding_pubkey, &theirs.funding_pubkey, + tx); + + msg = towire_funding_signed(state, &tmpid, &sig); + if (!sync_crypto_write(state->cs, PEER_FD, msg)) + status_failed(WIRE_OPENING_PEER_WRITE_FAILED, + "Writing funding_signed"); + + msg = towire_opening_accept_resp(state, + &state->funding_txid, + state->funding_txout, + state->remoteconf, + &theirsig, + state->cs, + &theirs.funding_pubkey, + &theirs.revocation_basepoint, + &theirs.payment_basepoint, + &theirs.delayed_payment_basepoint, + &state->next_per_commit[REMOTE]); + + status_send(msg); +} + +#ifndef TESTING +int main(int argc, char *argv[]) +{ + u8 *msg, *peer_msg; + struct state *state = tal(NULL, struct state); + struct sha256 seed; + struct points our_points; + + if (argc == 2 && streq(argv[1], "--version")) { + printf("%s\n", version()); + exit(0); + } + + breakpoint(); + + /* We handle write returning errors! */ + signal(SIGCHLD, SIG_IGN); + secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY + | SECP256K1_CONTEXT_SIGN); + status_setup(STATUS_FD); + + msg = wire_sync_read(state, REQ_FD); + if (!msg) + status_failed(WIRE_BAD_COMMAND, "%s", strerror(errno)); + + state->cs = tal(state, struct crypto_state); + if (!fromwire_opening_init(msg, NULL, + &state->localconf, + &state->minconf, + &state->maxconf, + state->cs, + &seed)) + status_failed(WIRE_BAD_COMMAND, "%s", strerror(errno)); + tal_free(msg); + + /* We derive everything from the one secret seed. */ + derive_our_basepoints(&seed, &our_points, &state->our_secrets, + &state->shaseed, &state->next_per_commit[LOCAL]); + + msg = wire_sync_read(state, REQ_FD); + if (fromwire_opening_open(msg, NULL, + &state->funding_satoshis, + &state->push_msat, + &state->feerate_per_kw)) + open_channel(state, &our_points); + else if (fromwire_opening_accept(state, msg, NULL, &peer_msg)) + recv_channel(state, &our_points, peer_msg); + + /* Hand back the fd. */ + fdpass_send(REQ_FD, PEER_FD); + + /* Wait for exit command (avoid state close being read before reqfd) */ + msg = wire_sync_read(state, REQ_FD); + if (!msg) + status_failed(WIRE_BAD_COMMAND, "%s", strerror(errno)); + if (!fromwire_opening_exit_req(msg, NULL)) + status_failed(WIRE_BAD_COMMAND, "Expected exit req not %i", + fromwire_peektype(msg)); + tal_free(state); + return 0; +} +#endif /* TESTING */ diff --git a/lightningd/opening/opening_control_wire.csv b/lightningd/opening/opening_control_wire.csv new file mode 100644 index 000000000..506a63b41 --- /dev/null +++ b/lightningd/opening/opening_control_wire.csv @@ -0,0 +1,58 @@ +#include +#include +opening_init,0 +# What configuration we'll offer +opening_init,0,our_config,36,struct channel_config +# Minimum/maximum configuration values we'll accept +opening_init,36,min_config,36,struct channel_config +opening_init,72,max_config,36,struct channel_config +opening_init,108,crypto_state,144,struct crypto_state +# Seed to generate all the keys from +opening_init,252,seed,32 + +# This means we offer the open. +opening_open,1 +opening_open,0,funding_satoshis,8 +opening_open,8,push_msat,8 +opening_open,16,feerate_per_kw,4 + +# Response asks for txid of funding transaction. +opening_open_resp,101 +opening_open_resp,0,local_fundingkey,33 +opening_open_resp,0,remote_fundingkey,33 + +# Now we give the funding txid and outnum. +opening_open_funding,2 +opening_open_funding,0,txid,32,struct sha256_double +opening_open_funding,32,txout,1,u8 + +# This gives their sig, means we can broadcast tx: we're done. +opening_open_funding_resp,102 +opening_open_funding_resp,0,their_config,36,struct channel_config +opening_open_funding_resp,36,first_commit_sig,64,secp256k1_ecdsa_signature +opening_open_funding_resp,100,crypto_state,144,struct crypto_state +opening_open_funding_resp,244,revocation_basepoint,33 +opening_open_funding_resp,277,payment_basepoint,33 +opening_open_funding_resp,310,delayed_payment_basepoint,33 +opening_open_funding_resp,343,their_per_commit_point,33 + +# This means they offer the open (contains their offer packet) +opening_accept,3 +opening_accept,0,len,2 +opening_accept,2,msg,len,u8 + +# This gives the txid of their funding tx: we're done. +opening_accept_resp,103 +opening_accept_resp,0,funding_txid,32,struct sha256_double +opening_accept_resp,32,funding_txout,1,u8 +opening_accept_resp,33,their_config,36,struct channel_config +opening_accept_resp,69,first_commit_sig,64,secp256k1_ecdsa_signature +opening_accept_resp,133,crypto_state,144,struct crypto_state +opening_accept_resp,277,remote_fundingkey,33 +opening_accept_resp,310,revocation_basepoint,33 +opening_accept_resp,343,payment_basepoint,33 +opening_accept_resp,376,delayed_payment_basepoint,33 +opening_accept_resp,409,their_per_commit_point,33 + +# You're OK to exit. +opening_exit_req,99 diff --git a/lightningd/opening/opening_status_wire.csv b/lightningd/opening/opening_status_wire.csv new file mode 100644 index 000000000..772ea0e7d --- /dev/null +++ b/lightningd/opening/opening_status_wire.csv @@ -0,0 +1,20 @@ +# Shouldn't happen +bad_command,0x8000 +# Also shouldn't happen +opening_key_derivation_failed,0x8001 +# Also shouldn't happen +opening_bad_param,0x8002 +# Also shouldn't happen +opening_hsm_failed,0x8003 + +# These are due to peer. +opening_peer_write_failed,0x8010 +opening_peer_read_failed,0x8011 +opening_peer_bad_funding,0x8012 +opening_peer_bad_config,0x8013 +opening_peer_bad_initial_message,0x8014 + +opening_watch_funding_req,1 +opening_watch_funding_req,0,txid,32,struct sha256_double +opening_watch_funding_resp,101 +opening_watch_funding_resp,0,channel_id,8,struct channel_id