mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
lightningd/opening: opening daemon.
This conducts the conversation up until we have the txid to wait for (or broadcast). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
e3f2d72d4d
commit
065f11b42a
5 changed files with 793 additions and 0 deletions
|
@ -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)
|
||||
|
||||
|
|
66
lightningd/opening/Makefile
Normal file
66
lightningd/opening/Makefile
Normal file
|
@ -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
|
648
lightningd/opening/opening.c
Normal file
648
lightningd/opening/opening.c
Normal file
|
@ -0,0 +1,648 @@
|
|||
/* FIXME: Handle incoming gossip messages! */
|
||||
/* FIXME: send peer PKT_ERR when failing! */
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/breakpoint/breakpoint.h>
|
||||
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/fdpass/fdpass.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/channel.h>
|
||||
#include <lightningd/commit_tx.h>
|
||||
#include <lightningd/crypto_sync.h>
|
||||
#include <lightningd/key_derive.h>
|
||||
#include <lightningd/opening/gen_opening_control_wire.h>
|
||||
#include <lightningd/opening/gen_opening_status_wire.h>
|
||||
#include <secp256k1.h>
|
||||
#include <signal.h>
|
||||
#include <status.h>
|
||||
#include <stdio.h>
|
||||
#include <type_to_string.h>
|
||||
#include <version.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
#include <wire/wire.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
/* 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 */
|
58
lightningd/opening/opening_control_wire.csv
Normal file
58
lightningd/opening/opening_control_wire.csv
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <lightningd/cryptomsg.h>
|
||||
#include <lightningd/channel_config.h>
|
||||
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
|
|
20
lightningd/opening/opening_status_wire.csv
Normal file
20
lightningd/opening/opening_status_wire.csv
Normal file
|
@ -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
|
|
Loading…
Add table
Reference in a new issue