mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-23 15:04:19 +01:00
Rename subdaemons, move them into top level.
We leave the *build* results in lightningd/ for ease of in-place testing though. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
739b163f8b
commit
bbed5e3411
14
lightningd/.gitignore
vendored
14
lightningd/.gitignore
vendored
@@ -1,7 +1,9 @@
|
||||
lightningd
|
||||
lightningd_channel
|
||||
lightningd_connect
|
||||
lightningd_gossip
|
||||
lightningd_handshake
|
||||
lightningd_hsm
|
||||
lightningd_opening
|
||||
lightning_channeld
|
||||
lightning_connectd
|
||||
lightning_gossipd
|
||||
lightning_handshaked
|
||||
lightning_hsmd
|
||||
lightning_openingd
|
||||
lightning_closingd
|
||||
lightning_onchaind
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
lightningd-wrongdir:
|
||||
$(MAKE) -C .. lightningd-all
|
||||
|
||||
LIGHTNINGD_BINS := lightningd/lightningd lightningd/lightningd_hsm lightningd/lightningd_handshake lightningd/lightningd_gossip lightningd/lightningd_opening lightningd/lightningd_channel lightningd/lightningd_closing lightningd/lightningd_onchain
|
||||
LIGHTNINGD_PROGRAM := lightningd/lightningd
|
||||
|
||||
ALL_PROGRAMS += $(LIGHTNINGD_BINS)
|
||||
ALL_PROGRAMS += $(LIGHTNINGD_PROGRAM)
|
||||
|
||||
lightningd-all: $(LIGHTNINGD_BINS)
|
||||
lightningd-all: $(LIGHTNINGD_PROGRAM)
|
||||
|
||||
default: lightningd-all
|
||||
|
||||
@@ -76,19 +76,11 @@ LIGHTNINGD_HEADERS_NOGEN = \
|
||||
LIGHTNINGD_HEADERS_GEN = \
|
||||
lightningd/gen_peer_state_names.h
|
||||
|
||||
ALL_GEN_HEADERS += $(LIGHTNINGD_HEADERS_GEN)
|
||||
|
||||
# All together in one convenient var
|
||||
LIGHTNINGD_HEADERS = $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) $(EXTERNAL_HEADERS) $(WIRE_HEADERS) $(BITCOIN_HEADERS) $(COMMON_HEADERS) $(WALLET_LIB_HEADERS)
|
||||
|
||||
# These included makefiles add their headers to the LIGHTNINGD_HEADERS
|
||||
# variable so the include must preceed any actual use of the variable.
|
||||
include lightningd/hsm/Makefile
|
||||
include lightningd/handshake/Makefile
|
||||
include lightningd/gossip/Makefile
|
||||
include lightningd/opening/Makefile
|
||||
include lightningd/channel/Makefile
|
||||
include lightningd/closing/Makefile
|
||||
include lightningd/onchain/Makefile
|
||||
|
||||
$(LIGHTNINGD_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
lightningd/gen_peer_state_names.h: lightningd/peer_state.h ccan/ccan/cdump/tools/cdump-enumstr
|
||||
@@ -104,11 +96,11 @@ check-makefile: check-lightningd-makefile
|
||||
check-lightningd-makefile:
|
||||
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
|
||||
|
||||
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(LIGHTNINGD_CLOSING_CONTROL_OBJS) $(LIGHTNINGD_ONCHAIN_CONTROL_OBJS) $(WALLET_LIB_OBJS)
|
||||
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(LIGHTNINGD_CLOSING_CONTROL_OBJS) $(LIGHTNINGD_ONCHAIN_CONTROL_OBJS) $(WALLET_LIB_OBJS)
|
||||
|
||||
clean: lightningd-clean
|
||||
|
||||
lightningd-clean:
|
||||
$(RM) $(LIGHTNINGD_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(LIGHTNINGD_BINS)
|
||||
$(RM) $(LIGHTNINGD_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(LIGHTNINGD_PROGRAM)
|
||||
|
||||
include lightningd/test/Makefile
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/channel-wrongdir:
|
||||
$(MAKE) -C ../.. lightningd/channel-all
|
||||
|
||||
default: lightningd/channel-all
|
||||
|
||||
lightningd/channel-all: lightningd/lightningd_channel
|
||||
|
||||
# lightningd/channel needs these:
|
||||
LIGHTNINGD_CHANNEL_HEADERS_GEN := \
|
||||
lightningd/channel/gen_channel_wire.h
|
||||
|
||||
LIGHTNINGD_CHANNEL_HEADERS_NOGEN := \
|
||||
lightningd/channel/channeld_htlc.h \
|
||||
lightningd/channel/commit_tx.h \
|
||||
lightningd/channel/full_channel.h
|
||||
|
||||
LIGHTNINGD_CHANNEL_HEADERS := $(LIGHTNINGD_CHANNEL_HEADERS_GEN) $(LIGHTNINGD_CHANNEL_HEADERS_NOGEN)
|
||||
|
||||
LIGHTNINGD_CHANNEL_SRC := lightningd/channel/channel.c \
|
||||
lightningd/channel/commit_tx.c \
|
||||
lightningd/channel/full_channel.c \
|
||||
$(LIGHTNINGD_CHANNEL_HEADERS_GEN:.h=.c)
|
||||
LIGHTNINGD_CHANNEL_OBJS := $(LIGHTNINGD_CHANNEL_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_CHANNEL_OBJS)
|
||||
|
||||
# Common source we use.
|
||||
CHANNELD_COMMON_OBJS := \
|
||||
common/channel_config.o \
|
||||
common/crypto_sync.o \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/derive_basepoints.o \
|
||||
common/dev_disconnect.o \
|
||||
common/htlc_state.o \
|
||||
common/htlc_tx.o \
|
||||
common/htlc_wire.o \
|
||||
common/initial_channel.o \
|
||||
common/initial_commit_tx.o \
|
||||
common/keyset.o \
|
||||
common/key_derive.o \
|
||||
common/msg_queue.o \
|
||||
common/ping.o \
|
||||
common/peer_failed.o \
|
||||
common/permute_tx.o \
|
||||
common/pseudorand.o \
|
||||
common/sphinx.o \
|
||||
common/status.o \
|
||||
common/timeout.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_CHANNEL_CONTROL_HEADERS := $(LIGHTNINGD_CHANNEL_HEADERS_GEN)
|
||||
LIGHTNINGD_CHANNEL_CONTROL_SRC := $(LIGHTNINGD_CHANNEL_HEADERS_GEN:.h=.c)
|
||||
LIGHTNINGD_CHANNEL_CONTROL_OBJS := $(LIGHTNINGD_CHANNEL_CONTROL_SRC:.c=.o)
|
||||
|
||||
LIGHTNINGD_CHANNEL_GEN_SRC := $(filter lightningd/channel/gen_%, $(LIGHTNINGD_CHANNEL_SRC) $(LIGHTNINGD_CHANNEL_CONTROL_SRC))
|
||||
|
||||
LIGHTNINGD_CHANNEL_SRC_NOGEN := $(filter-out lightningd/channel/gen_%, $(LIGHTNINGD_CHANNEL_SRC))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_CHANNEL_HEADERS_GEN)
|
||||
LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_CHANNEL_HEADERS_NOGEN)
|
||||
|
||||
$(LIGHTNINGD_CHANNEL_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
lightningd/channel/gen_channel_wire.h: $(WIRE_GEN) lightningd/channel/channel_wire.csv
|
||||
$(WIRE_GEN) --header $@ channel_wire_type < lightningd/channel/channel_wire.csv > $@
|
||||
|
||||
lightningd/channel/gen_channel_wire.c: $(WIRE_GEN) lightningd/channel/channel_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} channel_wire_type < lightningd/channel/channel_wire.csv > $@
|
||||
|
||||
LIGHTNINGD_CHANNEL_OBJS := $(LIGHTNINGD_CHANNEL_SRC:.c=.o) $(LIGHTNINGD_CHANNEL_GEN_SRC:.c=.o)
|
||||
|
||||
lightningd/lightningd_channel: $(LIGHTNINGD_CHANNEL_OBJS) $(WIRE_ONION_OBJS) $(CHANNELD_COMMON_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS)
|
||||
|
||||
check-source: $(LIGHTNINGD_CHANNEL_SRC_NOGEN:%=check-src-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_CHANNEL_SRC:%=bolt-check/%) $(LIGHTNINGD_CHANNEL_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-whitespace: $(LIGHTNINGD_CHANNEL_SRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_CHANNEL_HEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/channel-clean
|
||||
|
||||
lightningd/channel-clean:
|
||||
$(RM) $(LIGHTNINGD_CHANNEL_OBJS) gen_*
|
||||
|
||||
-include lightningd/channel/test/Makefile
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
# Shouldn't happen
|
||||
channel_bad_command,0x8000
|
||||
# Also shouldn't happen
|
||||
channel_hsm_failed,0x8001
|
||||
channel_crypto_failed,0x8002
|
||||
channel_internal_error,0x8003
|
||||
channel_gossip_bad_message,0x8004
|
||||
|
||||
# These are due to peer.
|
||||
channel_peer_write_failed,0x8010
|
||||
channel_peer_read_failed,0x8011
|
||||
|
||||
channel_peer_bad_message,0x8012
|
||||
channel_peer_bad_message,,len,u16
|
||||
channel_peer_bad_message,,msg,len*u8
|
||||
|
||||
# Received and sent funding_locked
|
||||
channel_normal_operation,1001
|
||||
|
||||
#include <common/cryptomsg.h>
|
||||
#include <common/channel_config.h>
|
||||
|
||||
# Begin! (passes gossipd-client fd)
|
||||
channel_init,1
|
||||
channel_init,,chain_hash,struct sha256_double
|
||||
channel_init,,funding_txid,struct sha256_double
|
||||
channel_init,,funding_txout,2
|
||||
channel_init,,funding_satoshi,8
|
||||
channel_init,,our_config,struct channel_config
|
||||
channel_init,,their_config,struct channel_config
|
||||
channel_init,,feerate_per_kw,4
|
||||
channel_init,,first_commit_sig,secp256k1_ecdsa_signature
|
||||
channel_init,,crypto_state,struct crypto_state
|
||||
channel_init,,remote_fundingkey,33
|
||||
channel_init,,revocation_basepoint,33
|
||||
channel_init,,payment_basepoint,33
|
||||
channel_init,,delayed_payment_basepoint,33
|
||||
channel_init,,remote_per_commit,33
|
||||
channel_init,,old_remote_per_commit,33
|
||||
channel_init,,funder,enum side
|
||||
channel_init,,fee_base,4
|
||||
channel_init,,fee_proportional,4
|
||||
channel_init,,local_msatoshi,8
|
||||
channel_init,,seed,struct privkey
|
||||
channel_init,,local_node_id,struct pubkey
|
||||
channel_init,,remote_node_id,struct pubkey
|
||||
channel_init,,commit_msec,4
|
||||
channel_init,,cltv_delta,u16
|
||||
channel_init,,last_was_revoke,bool
|
||||
channel_init,,num_last_sent_commit,u16
|
||||
channel_init,,last_sent_commit,num_last_sent_commit*struct changed_htlc
|
||||
channel_init,,next_index_local,u64
|
||||
channel_init,,next_index_remote,u64
|
||||
channel_init,,revocations_received,u64
|
||||
channel_init,,next_htlc_id,u64
|
||||
channel_init,,num_htlcs,u16
|
||||
channel_init,,htlcs,num_htlcs*struct added_htlc
|
||||
channel_init,,htlc_states,num_htlcs*enum htlc_state
|
||||
channel_init,,num_fulfilled,u16
|
||||
channel_init,,fulfilled,num_fulfilled*struct fulfilled_htlc
|
||||
channel_init,,fulfilled_sides,num_fulfilled*enum side
|
||||
channel_init,,num_failed,u16
|
||||
channel_init,,failed,num_failed*struct failed_htlc
|
||||
channel_init,,failed_sides,num_failed*enum side
|
||||
channel_init,,local_funding_locked,bool
|
||||
channel_init,,remote_funding_locked,bool
|
||||
channel_init,,funding_short_id,struct short_channel_id
|
||||
channel_init,,reestablish,bool
|
||||
channel_init,,shutdown_scriptpubkey_len,u16
|
||||
channel_init,,shutdown_scriptpubkey,shutdown_scriptpubkey_len*u8
|
||||
channel_init,,remote_shutdown_received,bool
|
||||
channel_init,,flags,u8
|
||||
channel_init,,init_peer_pkt_len,u16
|
||||
channel_init,,init_peer_pkt,init_peer_pkt_len*u8
|
||||
|
||||
# Tx is deep enough, go!
|
||||
channel_funding_locked,2
|
||||
channel_funding_locked,,short_channel_id,struct short_channel_id
|
||||
|
||||
# Tell the channel that we may announce the channel's existence
|
||||
channel_funding_announce_depth,3
|
||||
|
||||
# Tell channel to offer this htlc
|
||||
channel_offer_htlc,4
|
||||
channel_offer_htlc,,amount_msat,8
|
||||
channel_offer_htlc,,cltv_expiry,4
|
||||
channel_offer_htlc,,payment_hash,32
|
||||
channel_offer_htlc,,onion_routing_packet,1366*u8
|
||||
|
||||
# Reply; synchronous since IDs have to increment.
|
||||
channel_offer_htlc_reply,104
|
||||
channel_offer_htlc_reply,,id,8
|
||||
# Zero failure code means success.
|
||||
channel_offer_htlc_reply,,failure_code,2
|
||||
channel_offer_htlc_reply,,failurestrlen,2
|
||||
channel_offer_htlc_reply,,failurestr,failurestrlen*u8
|
||||
|
||||
# Main daemon found out the preimage for an htlc
|
||||
#include <bitcoin/preimage.h>
|
||||
channel_fulfill_htlc,5
|
||||
channel_fulfill_htlc,,id,8
|
||||
channel_fulfill_htlc,,payment_preimage,struct preimage
|
||||
|
||||
# Main daemon says HTLC failed
|
||||
channel_fail_htlc,6
|
||||
channel_fail_htlc,,id,8
|
||||
# If malformed is non-zero, it's a BADONION code
|
||||
channel_fail_htlc,,malformed,u16
|
||||
# Otherwise, error_pkt contains failreason.
|
||||
channel_fail_htlc,,len,2
|
||||
channel_fail_htlc,,error_pkt,len*u8
|
||||
|
||||
# Ping/pong test.
|
||||
channel_ping,11
|
||||
channel_ping,,num_pong_bytes,u16
|
||||
channel_ping,,len,u16
|
||||
|
||||
channel_ping_reply,111
|
||||
channel_ping_reply,,totlen,u16
|
||||
|
||||
# Channeld tells the master that the channel has been announced
|
||||
channel_announced,12
|
||||
|
||||
# When we receive funding_locked.
|
||||
channel_got_funding_locked,19
|
||||
channel_got_funding_locked,,next_per_commit_point,struct pubkey
|
||||
|
||||
# When we send a commitment_signed message, tell master.
|
||||
channel_sending_commitsig,20
|
||||
channel_sending_commitsig,,commitnum,u64
|
||||
# SENT_ADD_COMMIT, SENT_REMOVE_ACK_COMMIT, SENT_ADD_ACK_COMMIT, SENT_REMOVE_COMMIT
|
||||
channel_sending_commitsig,,num_changed,u16
|
||||
channel_sending_commitsig,,changed,num_changed*struct changed_htlc
|
||||
channel_sending_commitsig,,commit_sig,secp256k1_ecdsa_signature
|
||||
channel_sending_commitsig,,num_htlc_sigs,u16
|
||||
channel_sending_commitsig,,htlc_sigs,num_htlc_sigs*secp256k1_ecdsa_signature
|
||||
|
||||
# Wait for reply, to make sure it's on disk before we send commit.
|
||||
channel_sending_commitsig_reply,120
|
||||
|
||||
# When we have a commitment_signed message, tell master to remember.
|
||||
channel_got_commitsig,21
|
||||
channel_got_commitsig,,commitnum,u64
|
||||
channel_got_commitsig,,signature,secp256k1_ecdsa_signature
|
||||
channel_got_commitsig,,num_htlcs,u16
|
||||
channel_got_commitsig,,htlc_signature,num_htlcs*secp256k1_ecdsa_signature
|
||||
# RCVD_ADD_COMMIT: we're now committed to their new offered HTLCs.
|
||||
channel_got_commitsig,,num_added,u16
|
||||
channel_got_commitsig,,added,num_added*struct added_htlc
|
||||
channel_got_commitsig,,shared_secret,num_added*struct secret
|
||||
# RCVD_REMOVE_COMMIT: we're now no longer committed to these HTLCs.
|
||||
channel_got_commitsig,,num_fulfilled,u16
|
||||
channel_got_commitsig,,fulfilled,num_fulfilled*struct fulfilled_htlc
|
||||
channel_got_commitsig,,num_failed,u16
|
||||
channel_got_commitsig,,failed,num_failed*struct failed_htlc
|
||||
# RCVD_ADD_ACK_COMMIT, RCVD_REMOVE_ACK_COMMIT
|
||||
channel_got_commitsig,,num_changed,u16
|
||||
channel_got_commitsig,,changed,num_changed*struct changed_htlc
|
||||
channel_got_commitsig,,tx,struct bitcoin_tx
|
||||
|
||||
# Wait for reply, to make sure it's on disk before we send revocation.
|
||||
channel_got_commitsig_reply,121
|
||||
|
||||
#include <common/htlc_wire.h>
|
||||
|
||||
channel_got_revoke,22
|
||||
channel_got_revoke,,revokenum,u64
|
||||
channel_got_revoke,,per_commitment_secret,struct sha256
|
||||
channel_got_revoke,,next_per_commit_point,struct pubkey
|
||||
# RCVD_ADD_ACK_REVOCATION, RCVD_REMOVE_ACK_REVOCATION, RCVD_ADD_REVOCATION, RCVD_REMOVE_REVOCATION
|
||||
channel_got_revoke,,num_changed,u16
|
||||
channel_got_revoke,,changed,num_changed*struct changed_htlc
|
||||
# Wait for reply, to make sure it's on disk before we continue
|
||||
# (eg. if we sent another commitment_signed, that would implicitly ack).
|
||||
channel_got_revoke_reply,122
|
||||
|
||||
# Tell peer that channel is shutting down
|
||||
channel_send_shutdown,23
|
||||
channel_send_shutdown,,scriptpubkey_len,u16
|
||||
channel_send_shutdown,,scriptpubkey,scriptpubkey_len*u8
|
||||
|
||||
# Peer told us that channel is shutting down
|
||||
channel_got_shutdown,24
|
||||
channel_got_shutdown,,scriptpubkey_len,u16
|
||||
channel_got_shutdown,,scriptpubkey,scriptpubkey_len*u8
|
||||
|
||||
# Shutdown is complete, ready for closing negotiation. + peer_fd & gossip_fd.
|
||||
channel_shutdown_complete,25
|
||||
channel_shutdown_complete,,crypto_state,struct crypto_state
|
||||
|
@@ -1,79 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_CHANNELD_HTLC_H
|
||||
#define LIGHTNING_LIGHTNINGD_CHANNEL_CHANNELD_HTLC_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <wire/gen_onion_wire.h>
|
||||
|
||||
struct htlc {
|
||||
/* What's the status. */
|
||||
enum htlc_state state;
|
||||
/* The unique ID for this peer and this direction (LOCAL or REMOTE) */
|
||||
u64 id;
|
||||
/* The amount in millisatoshi. */
|
||||
u64 msatoshi;
|
||||
/* When the HTLC can no longer be redeemed. */
|
||||
struct abs_locktime expiry;
|
||||
/* The hash of the preimage which can redeem this HTLC */
|
||||
struct sha256 rhash;
|
||||
/* The preimage which hashes to rhash (if known) */
|
||||
struct preimage *r;
|
||||
|
||||
/* FIXME: We could union these together: */
|
||||
/* Routing information sent with this HTLC. */
|
||||
const u8 *routing;
|
||||
const u8 *fail;
|
||||
enum onion_type malformed;
|
||||
};
|
||||
|
||||
static inline bool htlc_has(const struct htlc *h, int flag)
|
||||
{
|
||||
return htlc_state_flags(h->state) & flag;
|
||||
}
|
||||
|
||||
static inline enum side htlc_owner(const struct htlc *h)
|
||||
{
|
||||
return htlc_state_owner(h->state);
|
||||
}
|
||||
|
||||
/* htlc_map: ID -> htlc mapping. */
|
||||
static inline u64 htlc_key(const struct htlc *h)
|
||||
{
|
||||
return h->id;
|
||||
}
|
||||
static inline bool htlc_cmp(const struct htlc *h, u64 id)
|
||||
{
|
||||
return h->id == id;
|
||||
}
|
||||
static inline size_t htlc_hash(u64 id)
|
||||
{
|
||||
return siphash24(siphash_seed(), &id, sizeof(id));
|
||||
}
|
||||
HTABLE_DEFINE_TYPE(struct htlc, htlc_key, htlc_hash, htlc_cmp, htlc_map);
|
||||
|
||||
static inline struct htlc *htlc_get(struct htlc_map *htlcs, u64 id, enum side owner)
|
||||
{
|
||||
struct htlc *h;
|
||||
struct htlc_map_iter it;
|
||||
|
||||
for (h = htlc_map_getfirst(htlcs, id, &it);
|
||||
h;
|
||||
h = htlc_map_getnext(htlcs, id, &it)) {
|
||||
if (h->id == id && htlc_has(h, HTLC_FLAG(owner,HTLC_F_OWNER)))
|
||||
return h;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline size_t htlc_map_count(const struct htlc_map *htlcs)
|
||||
{
|
||||
return htlcs->raw.elems;
|
||||
}
|
||||
|
||||
/* FIXME: Move these out of the hash! */
|
||||
static inline bool htlc_is_dead(const struct htlc *htlc)
|
||||
{
|
||||
return htlc->state == RCVD_REMOVE_ACK_REVOCATION
|
||||
|| htlc->state == SENT_REMOVE_ACK_REVOCATION;
|
||||
}
|
||||
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_CHANNELD_HTLC_H */
|
||||
@@ -1,292 +0,0 @@
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <common/htlc_tx.h>
|
||||
#include <common/keyset.h>
|
||||
#include <common/permute_tx.h>
|
||||
#include <common/utils.h>
|
||||
#include <lightningd/channel/commit_tx.h>
|
||||
|
||||
#ifndef SUPERVERBOSE
|
||||
#define SUPERVERBOSE(...)
|
||||
#endif
|
||||
|
||||
static bool trim(const struct htlc *htlc,
|
||||
u64 feerate_per_kw, u64 dust_limit_satoshis,
|
||||
enum side side)
|
||||
{
|
||||
u64 htlc_fee;
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* For every offered HTLC, if the HTLC amount minus the HTLC-timeout
|
||||
* fee would be less than `dust_limit_satoshis` set by the transaction
|
||||
* owner, the commitment transaction MUST NOT contain that output,
|
||||
* otherwise it MUST be generated as specified in [Offered HTLC
|
||||
* Outputs](#offered-htlc-outputs).
|
||||
*/
|
||||
if (htlc_owner(htlc) == side)
|
||||
htlc_fee = htlc_timeout_fee(feerate_per_kw);
|
||||
/* BOLT #3:
|
||||
*
|
||||
* For every received HTLC, if the HTLC amount minus the HTLC-success
|
||||
* fee would be less than `dust_limit_satoshis` set by the transaction
|
||||
* owner, the commitment transaction MUST NOT contain that output,
|
||||
* otherwise it MUST be generated as specified in [Received HTLC
|
||||
* Outputs](#received-htlc-outputs).
|
||||
*/
|
||||
else
|
||||
htlc_fee = htlc_success_fee(feerate_per_kw);
|
||||
|
||||
return htlc->msatoshi / 1000 < dust_limit_satoshis + htlc_fee;
|
||||
}
|
||||
|
||||
size_t commit_tx_num_untrimmed(const struct htlc **htlcs,
|
||||
u64 feerate_per_kw, u64 dust_limit_satoshis,
|
||||
enum side side)
|
||||
{
|
||||
size_t i, n;
|
||||
|
||||
for (i = n = 0; i < tal_count(htlcs); i++)
|
||||
n += !trim(htlcs[i], feerate_per_kw, dust_limit_satoshis, side);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void add_offered_htlc_out(struct bitcoin_tx *tx, size_t n,
|
||||
const struct htlc *htlc,
|
||||
const struct keyset *keyset)
|
||||
{
|
||||
struct ripemd160 ripemd;
|
||||
u8 *wscript;
|
||||
|
||||
ripemd160(&ripemd, htlc->rhash.u.u8, sizeof(htlc->rhash.u.u8));
|
||||
wscript = htlc_offered_wscript(tx->output, &ripemd, keyset);
|
||||
tx->output[n].amount = htlc->msatoshi / 1000;
|
||||
tx->output[n].script = scriptpubkey_p2wsh(tx, wscript);
|
||||
SUPERVERBOSE("# HTLC %"PRIu64" offered amount %"PRIu64" wscript %s\n",
|
||||
htlc->id, tx->output[n].amount, tal_hex(wscript, wscript));
|
||||
tal_free(wscript);
|
||||
}
|
||||
|
||||
static void add_received_htlc_out(struct bitcoin_tx *tx, size_t n,
|
||||
const struct htlc *htlc,
|
||||
const struct keyset *keyset)
|
||||
{
|
||||
struct ripemd160 ripemd;
|
||||
u8 *wscript;
|
||||
|
||||
ripemd160(&ripemd, htlc->rhash.u.u8, sizeof(htlc->rhash.u.u8));
|
||||
wscript = htlc_received_wscript(tx, &ripemd, &htlc->expiry, keyset);
|
||||
tx->output[n].amount = htlc->msatoshi / 1000;
|
||||
tx->output[n].script = scriptpubkey_p2wsh(tx->output, wscript);
|
||||
SUPERVERBOSE("# HTLC %"PRIu64" received amount %"PRIu64" wscript %s\n",
|
||||
htlc->id, tx->output[n].amount, tal_hex(wscript, wscript));
|
||||
tal_free(wscript);
|
||||
}
|
||||
|
||||
struct bitcoin_tx *commit_tx(const tal_t *ctx,
|
||||
const struct sha256_double *funding_txid,
|
||||
unsigned int funding_txout,
|
||||
u64 funding_satoshis,
|
||||
enum side funder,
|
||||
u16 to_self_delay,
|
||||
const struct keyset *keyset,
|
||||
u64 feerate_per_kw,
|
||||
u64 dust_limit_satoshis,
|
||||
u64 self_pay_msat,
|
||||
u64 other_pay_msat,
|
||||
const struct htlc **htlcs,
|
||||
const struct htlc ***htlcmap,
|
||||
u64 obscured_commitment_number,
|
||||
enum side side)
|
||||
{
|
||||
const tal_t *tmpctx = tal_tmpctx(ctx);
|
||||
u64 base_fee_msat;
|
||||
struct bitcoin_tx *tx;
|
||||
size_t i, n, untrimmed;
|
||||
|
||||
assert(self_pay_msat + other_pay_msat <= funding_satoshis * 1000);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 1. Calculate which committed HTLCs need to be trimmed (see
|
||||
* [Trimmed Outputs](#trimmed-outputs)).
|
||||
*/
|
||||
untrimmed = commit_tx_num_untrimmed(htlcs,
|
||||
feerate_per_kw,
|
||||
dust_limit_satoshis, side);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 2. Calculate the base [commitment transaction
|
||||
* fee](#fee-calculation).
|
||||
*/
|
||||
base_fee_msat = commit_tx_base_fee(feerate_per_kw, untrimmed) * 1000;
|
||||
|
||||
SUPERVERBOSE("# base commitment transaction fee = %"PRIu64"\n",
|
||||
base_fee_msat / 1000);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 3. Subtract this base fee from the funder (either `to_local` or
|
||||
* `to_remote`), with a floor of zero (see [Fee Payment](#fee-payment)).
|
||||
*/
|
||||
try_subtract_fee(funder, side, base_fee_msat,
|
||||
&self_pay_msat, &other_pay_msat);
|
||||
|
||||
#ifdef PRINT_ACTUAL_FEE
|
||||
{
|
||||
u64 satoshis_out = 0;
|
||||
for (i = n = 0; i < tal_count(htlcs); i++) {
|
||||
if (!trim(htlcs[i], feerate_per_kw, dust_limit_satoshis,
|
||||
side))
|
||||
satoshis_out += htlcs[i]->msatoshi / 1000;
|
||||
}
|
||||
if (self_pay_msat / 1000 >= dust_limit_satoshis)
|
||||
satoshis_out += self_pay_msat / 1000;
|
||||
if (other_pay_msat / 1000 >= dust_limit_satoshis)
|
||||
satoshis_out += other_pay_msat / 1000;
|
||||
SUPERVERBOSE("# actual commitment transaction fee = %"PRIu64"\n",
|
||||
funding_satoshis - satoshis_out);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Worst-case sizing: both to-local and to-remote outputs. */
|
||||
tx = bitcoin_tx(ctx, 1, untrimmed + 2);
|
||||
|
||||
/* We keep track of which outputs have which HTLCs */
|
||||
if (htlcmap)
|
||||
*htlcmap = tal_arr(tx, const struct htlc *,
|
||||
tal_count(tx->output));
|
||||
|
||||
/* This could be done in a single loop, but we follow the BOLT
|
||||
* literally to make comments in test vectors clearer. */
|
||||
|
||||
n = 0;
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 3. For every offered HTLC, if it is not trimmed, add an
|
||||
* [offered HTLC output](#offered-htlc-outputs).
|
||||
*/
|
||||
for (i = 0; i < tal_count(htlcs); i++) {
|
||||
if (htlc_owner(htlcs[i]) != side)
|
||||
continue;
|
||||
if (trim(htlcs[i], feerate_per_kw, dust_limit_satoshis, side))
|
||||
continue;
|
||||
add_offered_htlc_out(tx, n, htlcs[i], keyset);
|
||||
if (htlcmap)
|
||||
(*htlcmap)[n++] = htlcs[i];
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 4. For every received HTLC, if it is not trimmed, add an
|
||||
* [received HTLC output](#received-htlc-outputs).
|
||||
*/
|
||||
for (i = 0; i < tal_count(htlcs); i++) {
|
||||
if (htlc_owner(htlcs[i]) == side)
|
||||
continue;
|
||||
if (trim(htlcs[i], feerate_per_kw, dust_limit_satoshis, side))
|
||||
continue;
|
||||
add_received_htlc_out(tx, n, htlcs[i], keyset);
|
||||
if (htlcmap)
|
||||
(*htlcmap)[n++] = htlcs[i];
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 5. If the `to_local` amount is greater or equal to
|
||||
* `dust_limit_satoshis`, add a [`to_local`
|
||||
* Output](#to-local-output).
|
||||
*/
|
||||
if (self_pay_msat / 1000 >= dust_limit_satoshis) {
|
||||
u8 *wscript = to_self_wscript(tmpctx, to_self_delay,keyset);
|
||||
tx->output[n].amount = self_pay_msat / 1000;
|
||||
tx->output[n].script = scriptpubkey_p2wsh(tx, wscript);
|
||||
if (htlcmap)
|
||||
(*htlcmap)[n] = NULL;
|
||||
SUPERVERBOSE("# to-local amount %"PRIu64" wscript %s\n",
|
||||
tx->output[n].amount,
|
||||
tal_hex(tmpctx, wscript));
|
||||
n++;
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 6. If the `to_remote` amount is greater or equal to
|
||||
* `dust_limit_satoshis`, add a [`to_remote`
|
||||
* Output](#to-remote-output).
|
||||
*/
|
||||
if (other_pay_msat / 1000 >= dust_limit_satoshis) {
|
||||
/* BOLT #3:
|
||||
*
|
||||
* #### `to_remote` Output
|
||||
*
|
||||
* This output sends funds to the other peer, thus is a simple
|
||||
* P2WPKH to `remotekey`.
|
||||
*/
|
||||
tx->output[n].amount = other_pay_msat / 1000;
|
||||
tx->output[n].script = scriptpubkey_p2wpkh(tx,
|
||||
&keyset->other_payment_key);
|
||||
if (htlcmap)
|
||||
(*htlcmap)[n] = NULL;
|
||||
SUPERVERBOSE("# to-remote amount %"PRIu64" P2WPKH(%s)\n",
|
||||
tx->output[n].amount,
|
||||
type_to_string(tmpctx, struct pubkey,
|
||||
&keyset->other_payment_key));
|
||||
n++;
|
||||
}
|
||||
|
||||
assert(n <= tal_count(tx->output));
|
||||
tal_resize(&tx->output, n);
|
||||
if (htlcmap)
|
||||
tal_resize(htlcmap, n);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* 7. Sort the outputs into [BIP 69
|
||||
* order](#transaction-input-and-output-ordering)
|
||||
*/
|
||||
permute_outputs(tx->output, tal_count(tx->output),
|
||||
htlcmap ? (const void **)*htlcmap : NULL);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* ## Commitment Transaction
|
||||
*
|
||||
* * version: 2
|
||||
*/
|
||||
assert(tx->version == 2);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* * locktime: upper 8 bits are 0x20, lower 24 bits are the lower
|
||||
* 24 bits of the obscured commitment transaction number.
|
||||
*/
|
||||
tx->lock_time
|
||||
= (0x20000000 | (obscured_commitment_number & 0xFFFFFF));
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* * txin count: 1
|
||||
* * `txin[0]` outpoint: `txid` and `output_index` from
|
||||
* `funding_created` message
|
||||
*/
|
||||
tx->input[0].txid = *funding_txid;
|
||||
tx->input[0].index = funding_txout;
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* * `txin[0]` sequence: upper 8 bits are 0x80, lower 24 bits are
|
||||
* upper 24 bits of the obscured commitment transaction number.
|
||||
*/
|
||||
tx->input[0].sequence_number
|
||||
= (0x80000000 | ((obscured_commitment_number>>24) & 0xFFFFFF));
|
||||
|
||||
/* Input amount needed for signature code. */
|
||||
tx->input[0].amount = tal_dup(tx->input, u64, &funding_satoshis);
|
||||
|
||||
tal_free(tmpctx);
|
||||
return tx;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_COMMIT_TX_H
|
||||
#define LIGHTNING_LIGHTNINGD_CHANNEL_COMMIT_TX_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <common/htlc.h>
|
||||
#include <common/initial_commit_tx.h>
|
||||
#include <lightningd/channel/channeld_htlc.h>
|
||||
|
||||
struct keyset;
|
||||
struct sha256_double;
|
||||
|
||||
/**
|
||||
* commit_tx_num_untrimmed: how many of these htlc outputs will commit tx have?
|
||||
* @htlcs: tal_arr of HTLCs
|
||||
* @feerate_per_kw: feerate to use
|
||||
* @dust_limit_satoshis: dust limit below which to trim outputs.
|
||||
* @side: from which side's point of view
|
||||
*
|
||||
* We need @side because HTLC fees are different for offered and
|
||||
* received HTLCs.
|
||||
*/
|
||||
size_t commit_tx_num_untrimmed(const struct htlc **htlcs,
|
||||
u64 feerate_per_kw, u64 dust_limit_satoshis,
|
||||
enum side side);
|
||||
|
||||
/**
|
||||
* 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_satoshis: funding outpoint.
|
||||
* @funder: is the LOCAL or REMOTE paying the fee?
|
||||
* @keyset: keys derived for this commit tx.
|
||||
* @feerate_per_kw: feerate to use
|
||||
* @dust_limit_satoshis: dust limit below which to trim outputs.
|
||||
* @self_pay_msat: amount to pay directly to self
|
||||
* @other_pay_msat: amount to pay directly to the other side
|
||||
* @htlcs: tal_arr of htlcs committed by transaction (some may be trimmed)
|
||||
* @htlc_map: outputed map of outnum->HTLC (NULL for direct outputs), or NULL.
|
||||
* @obscured_commitment_number: number to encode in commitment transaction
|
||||
* @side: side to generate commitment transaction for.
|
||||
*
|
||||
* We need to be able to generate the remote side's tx to create signatures,
|
||||
* but the BOLT is expressed in terms of generating our local commitment
|
||||
* transaction, so we carefully use the terms "self" and "other" here.
|
||||
*/
|
||||
struct bitcoin_tx *commit_tx(const tal_t *ctx,
|
||||
const struct sha256_double *funding_txid,
|
||||
unsigned int funding_txout,
|
||||
u64 funding_satoshis,
|
||||
enum side funder,
|
||||
u16 to_self_delay,
|
||||
const struct keyset *keyset,
|
||||
u64 feerate_per_kw,
|
||||
u64 dust_limit_satoshis,
|
||||
u64 self_pay_msat,
|
||||
u64 other_pay_msat,
|
||||
const struct htlc **htlcs,
|
||||
const struct htlc ***htlcmap,
|
||||
u64 obscured_commitment_number,
|
||||
enum side side);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_COMMIT_TX_H */
|
||||
@@ -1,932 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/channel_config.h>
|
||||
#include <common/htlc.h>
|
||||
#include <common/htlc_tx.h>
|
||||
#include <common/htlc_wire.h>
|
||||
#include <common/key_derive.h>
|
||||
#include <common/keyset.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/channel/commit_tx.h>
|
||||
#include <lightningd/channel/full_channel.h>
|
||||
#include <string.h>
|
||||
|
||||
struct channel *new_channel(const tal_t *ctx,
|
||||
const struct sha256_double *funding_txid,
|
||||
unsigned int funding_txout,
|
||||
u64 funding_satoshis,
|
||||
u64 local_msatoshi,
|
||||
u32 feerate_per_kw,
|
||||
const struct channel_config *local,
|
||||
const struct channel_config *remote,
|
||||
const struct basepoints *local_basepoints,
|
||||
const struct basepoints *remote_basepoints,
|
||||
const struct pubkey *local_funding_pubkey,
|
||||
const struct pubkey *remote_funding_pubkey,
|
||||
enum side funder)
|
||||
{
|
||||
struct channel *channel = new_initial_channel(ctx, funding_txid,
|
||||
funding_txout,
|
||||
funding_satoshis,
|
||||
local_msatoshi,
|
||||
feerate_per_kw,
|
||||
local, remote,
|
||||
local_basepoints,
|
||||
remote_basepoints,
|
||||
local_funding_pubkey,
|
||||
remote_funding_pubkey,
|
||||
funder);
|
||||
if (channel) {
|
||||
channel->htlcs = tal(channel, struct htlc_map);
|
||||
htlc_map_init(channel->htlcs);
|
||||
tal_add_destructor(channel->htlcs, htlc_map_clear);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
static void htlc_arr_append(const struct htlc ***arr, const struct htlc *htlc)
|
||||
{
|
||||
size_t n;
|
||||
if (!arr)
|
||||
return;
|
||||
n = tal_count(*arr);
|
||||
tal_resize(arr, n+1);
|
||||
(*arr)[n] = htlc;
|
||||
}
|
||||
|
||||
/* What does adding the HTLC do to the balance for this side */
|
||||
static s64 balance_adding_htlc(const struct htlc *htlc, enum side side)
|
||||
{
|
||||
if (htlc_owner(htlc) == side)
|
||||
return -htlc->msatoshi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* What does removing the HTLC do to the balance for this side */
|
||||
static s64 balance_removing_htlc(const struct htlc *htlc, enum side side)
|
||||
{
|
||||
enum side paid_to;
|
||||
|
||||
/* Fulfilled HTLCs are paid to recipient, otherwise returns to owner */
|
||||
if (htlc->r)
|
||||
paid_to = !htlc_owner(htlc);
|
||||
else
|
||||
paid_to = htlc_owner(htlc);
|
||||
|
||||
if (side == paid_to)
|
||||
return htlc->msatoshi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_htlc(const struct htlc *htlc, const char *prefix)
|
||||
{
|
||||
enum htlc_state remote_state;
|
||||
|
||||
if (htlc->state <= RCVD_REMOVE_ACK_REVOCATION)
|
||||
remote_state = htlc->state + 10;
|
||||
else
|
||||
remote_state = htlc->state - 10;
|
||||
|
||||
status_trace("%s: HTLC %s %"PRIu64" = %s/%s %s",
|
||||
prefix,
|
||||
htlc_owner(htlc) == LOCAL ? "LOCAL" : "REMOTE",
|
||||
htlc->id,
|
||||
htlc_state_name(htlc->state),
|
||||
htlc_state_name(remote_state),
|
||||
htlc->r ? "FULFILLED" : htlc->fail ? "FAILED" :
|
||||
htlc->malformed ? "MALFORMED" : "");
|
||||
}
|
||||
|
||||
void dump_htlcs(const struct channel *channel, const char *prefix)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
const struct htlc *htlc;
|
||||
|
||||
for (htlc = htlc_map_first(channel->htlcs, &it);
|
||||
htlc;
|
||||
htlc = htlc_map_next(channel->htlcs, &it)) {
|
||||
dump_htlc(htlc, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns up to three arrays:
|
||||
* committed: HTLCs currently committed.
|
||||
* pending_removal: HTLCs pending removal (subset of committed)
|
||||
* pending_addition: HTLCs pending addition (no overlap with committed)
|
||||
*/
|
||||
static void gather_htlcs(const tal_t *ctx,
|
||||
const struct channel *channel,
|
||||
enum side side,
|
||||
const struct htlc ***committed,
|
||||
const struct htlc ***pending_removal,
|
||||
const struct htlc ***pending_addition)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
const struct htlc *htlc;
|
||||
const int committed_flag = HTLC_FLAG(side, HTLC_F_COMMITTED);
|
||||
const int pending_flag = HTLC_FLAG(side, HTLC_F_PENDING);
|
||||
|
||||
*committed = tal_arr(ctx, const struct htlc *, 0);
|
||||
if (pending_removal)
|
||||
*pending_removal = tal_arr(ctx, const struct htlc *, 0);
|
||||
if (pending_addition)
|
||||
*pending_addition = tal_arr(ctx, const struct htlc *, 0);
|
||||
|
||||
if (!channel->htlcs)
|
||||
return;
|
||||
|
||||
for (htlc = htlc_map_first(channel->htlcs, &it);
|
||||
htlc;
|
||||
htlc = htlc_map_next(channel->htlcs, &it)) {
|
||||
if (htlc_has(htlc, committed_flag)) {
|
||||
htlc_arr_append(committed, htlc);
|
||||
if (htlc_has(htlc, pending_flag))
|
||||
htlc_arr_append(pending_removal, htlc);
|
||||
} else if (htlc_has(htlc, pending_flag))
|
||||
htlc_arr_append(pending_addition, htlc);
|
||||
}
|
||||
}
|
||||
|
||||
static u64 total_offered_msatoshis(const struct htlc **htlcs, enum side side)
|
||||
{
|
||||
size_t i;
|
||||
u64 total = 0;
|
||||
|
||||
for (i = 0; i < tal_count(htlcs); i++) {
|
||||
if (htlc_owner(htlcs[i]) == side)
|
||||
total += htlcs[i]->msatoshi;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static void add_htlcs(struct bitcoin_tx ***txs,
|
||||
const u8 ***wscripts,
|
||||
const struct htlc **htlcmap,
|
||||
const struct channel *channel,
|
||||
const struct keyset *keyset,
|
||||
enum side side)
|
||||
{
|
||||
size_t i, n;
|
||||
struct sha256_double txid;
|
||||
u32 feerate_per_kw = channel->view[side].feerate_per_kw;
|
||||
|
||||
/* Get txid of commitment transaction */
|
||||
bitcoin_txid((*txs)[0], &txid);
|
||||
|
||||
for (i = 0; i < tal_count(htlcmap); i++) {
|
||||
const struct htlc *htlc = htlcmap[i];
|
||||
struct bitcoin_tx *tx;
|
||||
u8 *wscript;
|
||||
|
||||
if (!htlc)
|
||||
continue;
|
||||
|
||||
if (htlc_owner(htlc) == side) {
|
||||
tx = htlc_timeout_tx(*txs, &txid, i,
|
||||
htlc->msatoshi,
|
||||
htlc->expiry.locktime,
|
||||
to_self_delay(channel, side),
|
||||
feerate_per_kw,
|
||||
keyset);
|
||||
wscript = bitcoin_wscript_htlc_offer(*wscripts,
|
||||
&keyset->self_payment_key,
|
||||
&keyset->other_payment_key,
|
||||
&htlc->rhash,
|
||||
&keyset->self_revocation_key);
|
||||
} else {
|
||||
tx = htlc_success_tx(*txs, &txid, i,
|
||||
htlc->msatoshi,
|
||||
to_self_delay(channel, side),
|
||||
feerate_per_kw,
|
||||
keyset);
|
||||
wscript = bitcoin_wscript_htlc_receive(*wscripts,
|
||||
&htlc->expiry,
|
||||
&keyset->self_payment_key,
|
||||
&keyset->other_payment_key,
|
||||
&htlc->rhash,
|
||||
&keyset->self_revocation_key);
|
||||
}
|
||||
|
||||
/* Append to array. */
|
||||
n = tal_count(*txs);
|
||||
assert(n == tal_count(*wscripts));
|
||||
|
||||
tal_resize(wscripts, n+1);
|
||||
tal_resize(txs, n+1);
|
||||
(*wscripts)[n] = wscript;
|
||||
(*txs)[n] = tx;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: We could cache these. */
|
||||
struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
||||
const struct htlc ***htlcmap,
|
||||
const u8 ***wscripts,
|
||||
const struct channel *channel,
|
||||
const struct pubkey *per_commitment_point,
|
||||
u64 commitment_number,
|
||||
enum side side)
|
||||
{
|
||||
struct bitcoin_tx **txs;
|
||||
const struct htlc **committed;
|
||||
struct keyset keyset;
|
||||
|
||||
if (!derive_keyset(per_commitment_point,
|
||||
&channel->basepoints[side].payment,
|
||||
&channel->basepoints[!side].payment,
|
||||
&channel->basepoints[side].delayed_payment,
|
||||
&channel->basepoints[!side].revocation,
|
||||
&keyset))
|
||||
return NULL;
|
||||
|
||||
/* Figure out what @side will already be committed to. */
|
||||
gather_htlcs(ctx, channel, side, &committed, NULL, NULL);
|
||||
|
||||
/* NULL map only allowed at beginning, when we know no HTLCs */
|
||||
if (!htlcmap)
|
||||
assert(tal_count(committed) == 0);
|
||||
|
||||
txs = tal_arr(ctx, struct bitcoin_tx *, 1);
|
||||
txs[0] = commit_tx(ctx, &channel->funding_txid,
|
||||
channel->funding_txout,
|
||||
channel->funding_msat / 1000,
|
||||
channel->funder,
|
||||
to_self_delay(channel, side),
|
||||
&keyset,
|
||||
channel->view[side].feerate_per_kw,
|
||||
dust_limit_satoshis(channel, side),
|
||||
channel->view[side].owed_msat[side],
|
||||
channel->view[side].owed_msat[!side],
|
||||
committed,
|
||||
htlcmap,
|
||||
commitment_number ^ channel->commitment_number_obscurer,
|
||||
side);
|
||||
|
||||
*wscripts = tal_arr(ctx, const u8 *, 1);
|
||||
(*wscripts)[0] = bitcoin_redeem_2of2(*wscripts,
|
||||
&channel->funding_pubkey[side],
|
||||
&channel->funding_pubkey[!side]);
|
||||
|
||||
if (htlcmap)
|
||||
add_htlcs(&txs, wscripts, *htlcmap, channel, &keyset, side);
|
||||
|
||||
tal_free(committed);
|
||||
return txs;
|
||||
}
|
||||
|
||||
static enum channel_add_err add_htlc(struct channel *channel,
|
||||
enum side sender,
|
||||
u64 id, u64 msatoshi, u32 cltv_expiry,
|
||||
const struct sha256 *payment_hash,
|
||||
const u8 routing[TOTAL_PACKET_SIZE],
|
||||
struct htlc **htlcp,
|
||||
bool enforce_aggregate_limits)
|
||||
{
|
||||
const tal_t *tmpctx = tal_tmpctx(channel);
|
||||
struct htlc *htlc, *old;
|
||||
s64 msat_in_htlcs, fee_msat, balance_msat;
|
||||
enum side recipient = !sender;
|
||||
const struct htlc **committed, **adding, **removing;
|
||||
enum channel_add_err e;
|
||||
const struct channel_view *view;
|
||||
size_t i;
|
||||
|
||||
htlc = tal(tmpctx, struct htlc);
|
||||
|
||||
if (sender == LOCAL)
|
||||
htlc->state = SENT_ADD_HTLC;
|
||||
else
|
||||
htlc->state = RCVD_ADD_HTLC;
|
||||
|
||||
htlc->id = id;
|
||||
htlc->msatoshi = msatoshi;
|
||||
/* FIXME: Change expiry to simple u32 */
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node SHOULD fail the channel if a sending node... sets
|
||||
* `cltv_expiry` to greater or equal to 500000000.
|
||||
*/
|
||||
if (!blocks_to_abs_locktime(cltv_expiry, &htlc->expiry)) {
|
||||
e = CHANNEL_ERR_INVALID_EXPIRY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
htlc->rhash = *payment_hash;
|
||||
htlc->fail = NULL;
|
||||
htlc->malformed = 0;
|
||||
htlc->r = NULL;
|
||||
htlc->routing = tal_dup_arr(htlc, u8, routing, TOTAL_PACKET_SIZE, 0);
|
||||
|
||||
old = htlc_get(channel->htlcs, htlc->id, htlc_owner(htlc));
|
||||
if (old) {
|
||||
if (old->state != htlc->state
|
||||
|| old->msatoshi != htlc->msatoshi
|
||||
|| old->expiry.locktime != htlc->expiry.locktime
|
||||
|| !structeq(&old->rhash, &htlc->rhash))
|
||||
e = CHANNEL_ERR_DUPLICATE_ID_DIFFERENT;
|
||||
else
|
||||
e = CHANNEL_ERR_DUPLICATE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We're always considering the recipient's view of the channel here */
|
||||
view = &channel->view[recipient];
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node SHOULD fail the channel if it receives an
|
||||
* `amount_msat` equal to zero, below its own `htlc_minimum_msat`,
|
||||
* or...
|
||||
*/
|
||||
if (htlc->msatoshi == 0) {
|
||||
e = CHANNEL_ERR_HTLC_BELOW_MINIMUM;
|
||||
goto out;
|
||||
}
|
||||
if (htlc->msatoshi < htlc_minimum_msat(channel, recipient)) {
|
||||
e = CHANNEL_ERR_HTLC_BELOW_MINIMUM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* For channels with `chain_hash` identifying the Bitcoin blockchain,
|
||||
* the sending node MUST set the 4 most significant bytes of
|
||||
* `amount_msat` to zero.
|
||||
*/
|
||||
if (htlc->msatoshi & 0xFFFFFFFF00000000ULL) {
|
||||
e = CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Figure out what receiver will already be committed to. */
|
||||
gather_htlcs(tmpctx, channel, recipient, &committed, &removing, &adding);
|
||||
htlc_arr_append(&adding, htlc);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node SHOULD fail the channel if a sending node
|
||||
* adds more than its `max_accepted_htlcs` HTLCs to its local
|
||||
* commitment transaction */
|
||||
if (enforce_aggregate_limits
|
||||
&& tal_count(committed) - tal_count(removing) + tal_count(adding)
|
||||
> max_accepted_htlcs(channel, recipient)) {
|
||||
e = CHANNEL_ERR_TOO_MANY_HTLCS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
msat_in_htlcs = total_offered_msatoshis(committed, htlc_owner(htlc))
|
||||
- total_offered_msatoshis(removing, htlc_owner(htlc))
|
||||
+ total_offered_msatoshis(adding, htlc_owner(htlc));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node SHOULD fail the channel if a sending node ... or
|
||||
* adds more than its `max_htlc_value_in_flight_msat` worth of offered
|
||||
* HTLCs to its local commitment transaction */
|
||||
if (enforce_aggregate_limits
|
||||
&& msat_in_htlcs > max_htlc_value_in_flight_msat(channel, recipient)) {
|
||||
e = CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* or which the sending node cannot afford at the current
|
||||
* `feerate_per_kw` while maintaining its channel reserve.
|
||||
*/
|
||||
if (channel->funder == htlc_owner(htlc)) {
|
||||
u64 feerate = view->feerate_per_kw;
|
||||
u64 dust = dust_limit_satoshis(channel, recipient);
|
||||
size_t untrimmed;
|
||||
|
||||
assert(feerate >= 1);
|
||||
assert(dust >= 1);
|
||||
untrimmed = commit_tx_num_untrimmed(committed, feerate, dust,
|
||||
recipient)
|
||||
+ commit_tx_num_untrimmed(adding, feerate, dust,
|
||||
recipient)
|
||||
- commit_tx_num_untrimmed(removing, feerate, dust,
|
||||
recipient);
|
||||
|
||||
fee_msat = commit_tx_base_fee(feerate, untrimmed);
|
||||
} else
|
||||
fee_msat = 0;
|
||||
|
||||
assert(fee_msat >= 0);
|
||||
|
||||
/* Figure out what balance sender would have after applying all
|
||||
* pending changes. */
|
||||
balance_msat = view->owed_msat[sender];
|
||||
|
||||
assert(balance_msat >= 0);
|
||||
for (i = 0; i < tal_count(removing); i++)
|
||||
balance_msat += balance_removing_htlc(removing[i], sender);
|
||||
assert(balance_msat >= 0);
|
||||
for (i = 0; i < tal_count(adding); i++)
|
||||
balance_msat += balance_adding_htlc(adding[i], sender);
|
||||
|
||||
/* This is a little subtle:
|
||||
*
|
||||
* The change is being applied to the receiver but it will
|
||||
* come back to the sender after revoke_and_ack. So the check
|
||||
* here is that the balance to the sender doesn't go below the
|
||||
* sender's reserve. */
|
||||
if (enforce_aggregate_limits
|
||||
&& balance_msat - fee_msat < (s64)channel_reserve_msat(channel, sender)) {
|
||||
e = CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dump_htlc(htlc, "NEW:");
|
||||
htlc_map_add(channel->htlcs, tal_steal(channel, htlc));
|
||||
e = CHANNEL_ERR_ADD_OK;
|
||||
if (htlcp)
|
||||
*htlcp = htlc;
|
||||
|
||||
out:
|
||||
tal_free(tmpctx);
|
||||
return e;
|
||||
}
|
||||
|
||||
enum channel_add_err channel_add_htlc(struct channel *channel,
|
||||
enum side sender,
|
||||
u64 id,
|
||||
u64 msatoshi,
|
||||
u32 cltv_expiry,
|
||||
const struct sha256 *payment_hash,
|
||||
const u8 routing[TOTAL_PACKET_SIZE])
|
||||
{
|
||||
/* FIXME: check expiry etc. against config. */
|
||||
return add_htlc(channel, sender, id, msatoshi, cltv_expiry, payment_hash,
|
||||
routing, NULL, true);
|
||||
}
|
||||
|
||||
struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id)
|
||||
{
|
||||
return htlc_get(channel->htlcs, id, sender);
|
||||
}
|
||||
|
||||
enum channel_remove_err channel_fulfill_htlc(struct channel *channel,
|
||||
enum side owner,
|
||||
u64 id,
|
||||
const struct preimage *preimage)
|
||||
{
|
||||
struct sha256 hash;
|
||||
struct htlc *htlc;
|
||||
|
||||
htlc = channel_get_htlc(channel, owner, id);
|
||||
if (!htlc)
|
||||
return CHANNEL_ERR_NO_SUCH_ID;
|
||||
|
||||
if (htlc->r)
|
||||
return CHANNEL_ERR_ALREADY_FULFILLED;
|
||||
|
||||
sha256(&hash, preimage, sizeof(*preimage));
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST check that the `payment_preimage` value in
|
||||
* `update_fulfill_htlc` SHA256 hashes to the corresponding HTLC
|
||||
* `payment_hash`, and MUST fail the channel if it does not.
|
||||
*/
|
||||
if (!structeq(&hash, &htlc->rhash))
|
||||
return CHANNEL_ERR_BAD_PREIMAGE;
|
||||
|
||||
htlc->r = tal_dup(htlc, struct preimage, preimage);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST check that `id` corresponds to an HTLC in its
|
||||
* current commitment transaction, and MUST fail the channel if it
|
||||
* does not.
|
||||
*/
|
||||
if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) {
|
||||
status_trace("channel_fulfill_htlc: %"PRIu64" in state %s",
|
||||
htlc->id, htlc_state_name(htlc->state));
|
||||
return CHANNEL_ERR_HTLC_UNCOMMITTED;
|
||||
}
|
||||
|
||||
/* We enforce a stricter check, forcing state machine to be linear,
|
||||
* based on: */
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send `update_fulfill_htlc` until an HTLC is
|
||||
* irrevocably committed in both sides' commitment transactions.
|
||||
*/
|
||||
if (htlc->state == SENT_ADD_ACK_REVOCATION)
|
||||
htlc->state = RCVD_REMOVE_HTLC;
|
||||
else if (htlc->state == RCVD_ADD_ACK_REVOCATION)
|
||||
htlc->state = SENT_REMOVE_HTLC;
|
||||
else {
|
||||
status_trace("channel_fulfill_htlc: %"PRIu64" in state %s",
|
||||
htlc->id, htlc_state_name(htlc->state));
|
||||
return CHANNEL_ERR_HTLC_NOT_IRREVOCABLE;
|
||||
}
|
||||
dump_htlc(htlc, "FULFILL:");
|
||||
|
||||
return CHANNEL_ERR_REMOVE_OK;
|
||||
}
|
||||
|
||||
enum channel_remove_err channel_fail_htlc(struct channel *channel,
|
||||
enum side owner, u64 id)
|
||||
{
|
||||
struct htlc *htlc;
|
||||
|
||||
htlc = channel_get_htlc(channel, owner, id);
|
||||
if (!htlc)
|
||||
return CHANNEL_ERR_NO_SUCH_ID;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A receiving node MUST check that `id` corresponds to an HTLC in its
|
||||
* current commitment transaction, and MUST fail the channel if it
|
||||
* does not.
|
||||
*/
|
||||
if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) {
|
||||
status_trace("channel_fail_htlc: %"PRIu64" in state %s",
|
||||
htlc->id, htlc_state_name(htlc->state));
|
||||
return CHANNEL_ERR_HTLC_UNCOMMITTED;
|
||||
}
|
||||
|
||||
/* FIXME: Technically, they can fail this before we're committed to
|
||||
* it. This implies a non-linear state machine. */
|
||||
if (htlc->state == SENT_ADD_ACK_REVOCATION)
|
||||
htlc->state = RCVD_REMOVE_HTLC;
|
||||
else if (htlc->state == RCVD_ADD_ACK_REVOCATION)
|
||||
htlc->state = SENT_REMOVE_HTLC;
|
||||
else {
|
||||
status_trace("channel_fail_htlc: %"PRIu64" in state %s",
|
||||
htlc->id, htlc_state_name(htlc->state));
|
||||
return CHANNEL_ERR_HTLC_NOT_IRREVOCABLE;
|
||||
}
|
||||
dump_htlc(htlc, "FAIL:");
|
||||
|
||||
return CHANNEL_ERR_REMOVE_OK;
|
||||
}
|
||||
|
||||
static void htlc_incstate(struct channel *channel,
|
||||
struct htlc *htlc,
|
||||
enum side sidechanged)
|
||||
{
|
||||
int preflags, postflags;
|
||||
const int committed_f = HTLC_FLAG(sidechanged, HTLC_F_COMMITTED);
|
||||
|
||||
status_trace("htlc %"PRIu64": %s->%s", htlc->id,
|
||||
htlc_state_name(htlc->state),
|
||||
htlc_state_name(htlc->state+1));
|
||||
|
||||
preflags = htlc_state_flags(htlc->state);
|
||||
postflags = htlc_state_flags(htlc->state + 1);
|
||||
/* You can't change sides. */
|
||||
assert((preflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))
|
||||
== (postflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)));
|
||||
|
||||
htlc->state++;
|
||||
|
||||
/* If we've added or removed, adjust balances. */
|
||||
if (!(preflags & committed_f) && (postflags & committed_f)) {
|
||||
status_trace("htlc added %s: local %+"PRIi64" remote %+"PRIi64,
|
||||
side_to_str(sidechanged),
|
||||
balance_adding_htlc(htlc, LOCAL),
|
||||
balance_adding_htlc(htlc, REMOTE));
|
||||
channel->view[sidechanged].owed_msat[LOCAL]
|
||||
+= balance_adding_htlc(htlc, LOCAL);
|
||||
channel->view[sidechanged].owed_msat[REMOTE]
|
||||
+= balance_adding_htlc(htlc, REMOTE);
|
||||
} else if ((preflags & committed_f) && !(postflags & committed_f)) {
|
||||
status_trace("htlc removed %s: local %+"PRIi64" remote %+"PRIi64,
|
||||
side_to_str(sidechanged),
|
||||
balance_removing_htlc(htlc, LOCAL),
|
||||
balance_removing_htlc(htlc, REMOTE));
|
||||
channel->view[sidechanged].owed_msat[LOCAL]
|
||||
+= balance_removing_htlc(htlc, LOCAL);
|
||||
channel->view[sidechanged].owed_msat[REMOTE]
|
||||
+= balance_removing_htlc(htlc, REMOTE);
|
||||
}
|
||||
}
|
||||
|
||||
static void append_htlc(const struct htlc ***htlcs, const struct htlc *h)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
if (!htlcs)
|
||||
return;
|
||||
|
||||
n = tal_count(*htlcs);
|
||||
tal_resize(htlcs, n+1);
|
||||
(*htlcs)[n] = h;
|
||||
}
|
||||
|
||||
/* Returns flags which were changed. */
|
||||
static int change_htlcs(struct channel *channel,
|
||||
enum side sidechanged,
|
||||
const enum htlc_state *htlc_states,
|
||||
size_t n_hstates,
|
||||
const struct htlc ***htlcs,
|
||||
const char *prefix)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
int cflags = 0;
|
||||
size_t i;
|
||||
|
||||
for (h = htlc_map_first(channel->htlcs, &it);
|
||||
h;
|
||||
h = htlc_map_next(channel->htlcs, &it)) {
|
||||
for (i = 0; i < n_hstates; i++) {
|
||||
if (h->state == htlc_states[i]) {
|
||||
htlc_incstate(channel, h, sidechanged);
|
||||
dump_htlc(h, prefix);
|
||||
append_htlc(htlcs, h);
|
||||
cflags |= (htlc_state_flags(htlc_states[i])
|
||||
^ htlc_state_flags(h->state));
|
||||
}
|
||||
}
|
||||
}
|
||||
return cflags;
|
||||
}
|
||||
|
||||
/* FIXME: Handle fee changes too. */
|
||||
bool channel_sending_commit(struct channel *channel,
|
||||
const struct htlc ***htlcs)
|
||||
{
|
||||
int change;
|
||||
const enum htlc_state states[] = { SENT_ADD_HTLC,
|
||||
SENT_REMOVE_REVOCATION,
|
||||
SENT_ADD_REVOCATION,
|
||||
SENT_REMOVE_HTLC };
|
||||
status_trace("Trying commit");
|
||||
change = change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states),
|
||||
htlcs, "sending_commit");
|
||||
return change & HTLC_REMOTE_F_COMMITTED;
|
||||
}
|
||||
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel,
|
||||
const struct htlc ***htlcs)
|
||||
{
|
||||
int change;
|
||||
const enum htlc_state states[] = { SENT_ADD_COMMIT,
|
||||
SENT_REMOVE_ACK_COMMIT,
|
||||
SENT_ADD_ACK_COMMIT,
|
||||
SENT_REMOVE_COMMIT };
|
||||
|
||||
status_trace("Received revoke_and_ack");
|
||||
change = change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states),
|
||||
htlcs, "rcvd_revoke_and_ack");
|
||||
return change & HTLC_LOCAL_F_COMMITTED;
|
||||
}
|
||||
|
||||
/* FIXME: We can actually merge these two... */
|
||||
bool channel_rcvd_commit(struct channel *channel, const struct htlc ***htlcs)
|
||||
{
|
||||
int change;
|
||||
const enum htlc_state states[] = { RCVD_ADD_REVOCATION,
|
||||
RCVD_REMOVE_HTLC,
|
||||
RCVD_ADD_HTLC,
|
||||
RCVD_REMOVE_REVOCATION };
|
||||
|
||||
status_trace("Received commit");
|
||||
change = change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states), htlcs,
|
||||
"rcvd_commit");
|
||||
return change & HTLC_LOCAL_F_COMMITTED;
|
||||
}
|
||||
|
||||
bool channel_sending_revoke_and_ack(struct channel *channel)
|
||||
{
|
||||
int change;
|
||||
const enum htlc_state states[] = { RCVD_ADD_ACK_COMMIT,
|
||||
RCVD_REMOVE_COMMIT,
|
||||
RCVD_ADD_COMMIT,
|
||||
RCVD_REMOVE_ACK_COMMIT };
|
||||
status_trace("Sending revoke_and_ack");
|
||||
change = change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states), NULL,
|
||||
"sending_revoke_and_ack");
|
||||
return change & HTLC_REMOTE_F_PENDING;
|
||||
}
|
||||
|
||||
/* FIXME: Trivial to optimize: set flag on channel_sending_commit,
|
||||
* clear in channel_rcvd_revoke_and_ack. */
|
||||
bool channel_awaiting_revoke_and_ack(const struct channel *channel)
|
||||
{
|
||||
const enum htlc_state states[] = { SENT_ADD_COMMIT,
|
||||
SENT_REMOVE_ACK_COMMIT,
|
||||
SENT_ADD_ACK_COMMIT,
|
||||
SENT_REMOVE_COMMIT };
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
size_t i;
|
||||
|
||||
for (h = htlc_map_first(channel->htlcs, &it);
|
||||
h;
|
||||
h = htlc_map_next(channel->htlcs, &it)) {
|
||||
for (i = 0; i < ARRAY_SIZE(states); i++)
|
||||
if (h->state == states[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool channel_has_htlcs(const struct channel *channel)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
const struct htlc *htlc;
|
||||
|
||||
for (htlc = htlc_map_first(channel->htlcs, &it);
|
||||
htlc;
|
||||
htlc = htlc_map_next(channel->htlcs, &it)) {
|
||||
/* FIXME: Clean these out! */
|
||||
if (!htlc_is_dead(htlc))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool adjust_balance(struct channel *channel, struct htlc *htlc)
|
||||
{
|
||||
enum side side;
|
||||
|
||||
for (side = 0; side < NUM_SIDES; side++) {
|
||||
/* Did it ever add it? */
|
||||
if (!htlc_has(htlc, HTLC_FLAG(side, HTLC_F_WAS_COMMITTED)))
|
||||
continue;
|
||||
|
||||
/* Add it. */
|
||||
channel->view[side].owed_msat[LOCAL]
|
||||
+= balance_adding_htlc(htlc, LOCAL);
|
||||
channel->view[side].owed_msat[REMOTE]
|
||||
+= balance_adding_htlc(htlc, REMOTE);
|
||||
|
||||
/* If it is no longer committed, remove it (depending
|
||||
* on fail || fulfill). */
|
||||
if (htlc_has(htlc, HTLC_FLAG(side, HTLC_F_COMMITTED)))
|
||||
continue;
|
||||
|
||||
if (!htlc->fail && !htlc->malformed && !htlc->r) {
|
||||
status_trace("%s HTLC %"PRIu64
|
||||
" %s neither fail nor fulfull?",
|
||||
htlc_state_owner(htlc->state) == LOCAL
|
||||
? "out" : "in",
|
||||
htlc->id,
|
||||
htlc_state_name(htlc->state));
|
||||
return false;
|
||||
}
|
||||
channel->view[side].owed_msat[LOCAL]
|
||||
+= balance_removing_htlc(htlc, LOCAL);
|
||||
channel->view[side].owed_msat[REMOTE]
|
||||
+= balance_removing_htlc(htlc, REMOTE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool channel_force_htlcs(struct channel *channel,
|
||||
const struct added_htlc *htlcs,
|
||||
const enum htlc_state *hstates,
|
||||
const struct fulfilled_htlc *fulfilled,
|
||||
const enum side *fulfilled_sides,
|
||||
const struct failed_htlc *failed,
|
||||
const enum side *failed_sides)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (tal_count(hstates) != tal_count(htlcs)) {
|
||||
status_trace("#hstates %zu != #htlcs %zu",
|
||||
tal_count(hstates), tal_count(htlcs));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tal_count(fulfilled) != tal_count(fulfilled_sides)) {
|
||||
status_trace("#fulfilled sides %zu != #fulfilled %zu",
|
||||
tal_count(fulfilled_sides), tal_count(fulfilled));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tal_count(failed) != tal_count(failed_sides)) {
|
||||
status_trace("#failed sides %zu != #failed %zu",
|
||||
tal_count(failed_sides), tal_count(failed));
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < tal_count(htlcs); i++) {
|
||||
enum channel_add_err e;
|
||||
struct htlc *htlc;
|
||||
|
||||
status_trace("Restoring HTLC %zu/%zu:"
|
||||
" id=%"PRIu64" msat=%"PRIu64" ctlv=%u"
|
||||
" payment_hash=%s",
|
||||
i, tal_count(htlcs),
|
||||
htlcs[i].id, htlcs[i].amount_msat,
|
||||
htlcs[i].cltv_expiry,
|
||||
type_to_string(trc, struct sha256,
|
||||
&htlcs[i].payment_hash));
|
||||
|
||||
e = add_htlc(channel, htlc_state_owner(hstates[i]),
|
||||
htlcs[i].id, htlcs[i].amount_msat,
|
||||
htlcs[i].cltv_expiry,
|
||||
&htlcs[i].payment_hash,
|
||||
htlcs[i].onion_routing_packet, &htlc, false);
|
||||
if (e != CHANNEL_ERR_ADD_OK) {
|
||||
status_trace("%s HTLC %"PRIu64" failed error %u",
|
||||
htlc_state_owner(hstates[i]) == LOCAL
|
||||
? "out" : "in", htlcs[i].id, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Override state. */
|
||||
htlc->state = hstates[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < tal_count(fulfilled); i++) {
|
||||
struct htlc *htlc = channel_get_htlc(channel,
|
||||
fulfilled_sides[i],
|
||||
fulfilled[i].id);
|
||||
if (!htlc) {
|
||||
status_trace("Fulfill %s HTLC %"PRIu64" not found",
|
||||
fulfilled_sides[i] == LOCAL ? "out" : "in",
|
||||
fulfilled[i].id);
|
||||
return false;
|
||||
}
|
||||
if (htlc->r) {
|
||||
status_trace("Fulfill %s HTLC %"PRIu64" already fulfilled",
|
||||
fulfilled_sides[i] == LOCAL ? "out" : "in",
|
||||
fulfilled[i].id);
|
||||
return false;
|
||||
}
|
||||
if (htlc->fail) {
|
||||
status_trace("Fulfill %s HTLC %"PRIu64" already failed",
|
||||
fulfilled_sides[i] == LOCAL ? "out" : "in",
|
||||
fulfilled[i].id);
|
||||
return false;
|
||||
}
|
||||
if (!htlc_has(htlc, HTLC_REMOVING)) {
|
||||
status_trace("Fulfill %s HTLC %"PRIu64" state %s",
|
||||
fulfilled_sides[i] == LOCAL ? "out" : "in",
|
||||
fulfilled[i].id,
|
||||
htlc_state_name(htlc->state));
|
||||
return false;
|
||||
}
|
||||
htlc->r = tal_dup(htlc, struct preimage,
|
||||
&fulfilled[i].payment_preimage);
|
||||
}
|
||||
|
||||
for (i = 0; i < tal_count(failed); i++) {
|
||||
struct htlc *htlc;
|
||||
htlc = channel_get_htlc(channel, failed_sides[i],
|
||||
failed[i].id);
|
||||
if (!htlc) {
|
||||
status_trace("Fail %s HTLC %"PRIu64" not found",
|
||||
failed_sides[i] == LOCAL ? "out" : "in",
|
||||
failed[i].id);
|
||||
return false;
|
||||
}
|
||||
if (htlc->r) {
|
||||
status_trace("Fail %s HTLC %"PRIu64" already fulfilled",
|
||||
failed_sides[i] == LOCAL ? "out" : "in",
|
||||
failed[i].id);
|
||||
return false;
|
||||
}
|
||||
if (htlc->fail) {
|
||||
status_trace("Fail %s HTLC %"PRIu64" already failed",
|
||||
failed_sides[i] == LOCAL ? "out" : "in",
|
||||
failed[i].id);
|
||||
return false;
|
||||
}
|
||||
if (htlc->malformed) {
|
||||
status_trace("Fail %s HTLC %"PRIu64" already malformed",
|
||||
failed_sides[i] == LOCAL ? "out" : "in",
|
||||
failed[i].id);
|
||||
return false;
|
||||
}
|
||||
if (!htlc_has(htlc, HTLC_REMOVING)) {
|
||||
status_trace("Fail %s HTLC %"PRIu64" state %s",
|
||||
failed_sides[i] == LOCAL ? "out" : "in",
|
||||
fulfilled[i].id,
|
||||
htlc_state_name(htlc->state));
|
||||
return false;
|
||||
}
|
||||
if (failed[i].malformed)
|
||||
htlc->malformed = failed[i].malformed;
|
||||
else
|
||||
htlc->fail = tal_dup_arr(htlc, u8, failed[i].failreason,
|
||||
tal_len(failed[i].failreason),
|
||||
0);
|
||||
}
|
||||
|
||||
for (i = 0; i < tal_count(htlcs); i++) {
|
||||
struct htlc *htlc;
|
||||
htlc = channel_get_htlc(channel,
|
||||
htlc_state_owner(hstates[i]),
|
||||
htlcs[i].id);
|
||||
|
||||
if (!adjust_balance(channel, htlc))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/* This is the full channel routines, with HTLC support. */
|
||||
#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_FULL_CHANNEL_H
|
||||
#define LIGHTNING_LIGHTNINGD_CHANNEL_FULL_CHANNEL_H
|
||||
#include "config.h"
|
||||
#include <common/initial_channel.h>
|
||||
#include <common/sphinx.h>
|
||||
#include <lightningd/channel/channeld_htlc.h>
|
||||
|
||||
/**
|
||||
* new_channel: Given initial fees and funding, what is initial state?
|
||||
* @ctx: tal context to allocate return value from.
|
||||
* @funding_txid: The commitment transaction id.
|
||||
* @funding_txout: The commitment transaction output number.
|
||||
* @funding_satoshis: The commitment transaction amount.
|
||||
* @local_msatoshi: The amount for the local side (remainder goes to remote)
|
||||
* @feerate_per_kw: feerate per kiloweight (satoshis) for the commitment
|
||||
* transaction and HTLCS
|
||||
* @local: local channel configuration
|
||||
* @remote: remote channel configuration
|
||||
* @local_basepoints: local basepoints.
|
||||
* @remote_basepoints: remote basepoints.
|
||||
* @local_fundingkey: local funding key
|
||||
* @remote_fundingkey: remote funding key
|
||||
* @funder: which side initiated it.
|
||||
*
|
||||
* Returns state, or NULL if malformed.
|
||||
*/
|
||||
struct channel *new_channel(const tal_t *ctx,
|
||||
const struct sha256_double *funding_txid,
|
||||
unsigned int funding_txout,
|
||||
u64 funding_satoshis,
|
||||
u64 local_msatoshi,
|
||||
u32 feerate_per_kw,
|
||||
const struct channel_config *local,
|
||||
const struct channel_config *remote,
|
||||
const struct basepoints *local_basepoints,
|
||||
const struct basepoints *remote_basepoints,
|
||||
const struct pubkey *local_funding_pubkey,
|
||||
const struct pubkey *remote_funding_pubkey,
|
||||
enum side funder);
|
||||
|
||||
/**
|
||||
* channel_txs: Get the current commitment and htlc txs for the channel.
|
||||
* @ctx: tal context to allocate return value from.
|
||||
* @channel: The channel to evaluate
|
||||
* @htlc_map: Pointer to htlcs for each tx output (allocated off @ctx) or NULL.
|
||||
* @wscripts: Pointer to array of wscript for each tx returned (alloced off @ctx)
|
||||
* @per_commitment_point: Per-commitment point to determine keys
|
||||
* @commitment_number: The index of this commitment.
|
||||
* @side: which side to get the commitment transaction for
|
||||
*
|
||||
* Returns the unsigned commitment transaction for the committed state
|
||||
* for @side, followed by the htlc transactions in output order, and
|
||||
* fills in @htlc_map (if not NULL), or NULL on key derivation
|
||||
* failure.
|
||||
*/
|
||||
struct bitcoin_tx **channel_txs(const tal_t *ctx,
|
||||
const struct htlc ***htlcmap,
|
||||
const u8 ***wscripts,
|
||||
const struct channel *channel,
|
||||
const struct pubkey *per_commitment_point,
|
||||
u64 commitment_number,
|
||||
enum side side);
|
||||
|
||||
/**
|
||||
* actual_feerate: what is the actual feerate for the local side.
|
||||
* @channel: The channel state
|
||||
* @theirsig: The other side's signature
|
||||
*
|
||||
* The fee calculated on a commitment transaction is a worst-case
|
||||
* approximation. It's also possible that the desired feerate is not
|
||||
* met, because the initiator sets it while the other side is adding many
|
||||
* htlcs.
|
||||
*
|
||||
* This is the fee rate we actually care about, if we're going to check
|
||||
* whether it's actually too low.
|
||||
*/
|
||||
uint32_t actual_feerate(const struct channel *channel,
|
||||
const struct signature *theirsig);
|
||||
|
||||
enum channel_add_err {
|
||||
/* All OK! */
|
||||
CHANNEL_ERR_ADD_OK,
|
||||
/* Bad expiry value */
|
||||
CHANNEL_ERR_INVALID_EXPIRY,
|
||||
/* Not really a failure, if expected: it's an exact duplicate. */
|
||||
CHANNEL_ERR_DUPLICATE,
|
||||
/* Same ID, but otherwise different. */
|
||||
CHANNEL_ERR_DUPLICATE_ID_DIFFERENT,
|
||||
/* Would exceed the specified max_htlc_value_in_flight_msat */
|
||||
CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED,
|
||||
/* Can't afford it */
|
||||
CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED,
|
||||
/* HTLC is below htlc_minimum_msat */
|
||||
CHANNEL_ERR_HTLC_BELOW_MINIMUM,
|
||||
/* HTLC would push past max_accepted_htlcs */
|
||||
CHANNEL_ERR_TOO_MANY_HTLCS,
|
||||
};
|
||||
|
||||
/**
|
||||
* channel_add_htlc: append an HTLC to channel if it can afford it
|
||||
* @channel: The channel
|
||||
* @offerer: the side offering the HTLC (to the other side).
|
||||
* @id: unique HTLC id.
|
||||
* @msatoshi: amount in millisatoshi.
|
||||
* @cltv_expiry: block number when HTLC can no longer be redeemed.
|
||||
* @payment_hash: hash whose preimage can redeem HTLC.
|
||||
* @routing: routing information (copied)
|
||||
*
|
||||
* If this returns CHANNEL_ERR_NONE, the fee htlc was added and
|
||||
* the output amounts adjusted accordingly. Otherwise nothing
|
||||
* is changed.
|
||||
*/
|
||||
enum channel_add_err channel_add_htlc(struct channel *channel,
|
||||
enum side sender,
|
||||
u64 id,
|
||||
u64 msatoshi,
|
||||
u32 cltv_expiry,
|
||||
const struct sha256 *payment_hash,
|
||||
const u8 routing[TOTAL_PACKET_SIZE]);
|
||||
|
||||
/**
|
||||
* channel_get_htlc: find an HTLC
|
||||
* @channel: The channel
|
||||
* @offerer: the side offering the HTLC.
|
||||
* @id: unique HTLC id.
|
||||
*/
|
||||
struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id);
|
||||
|
||||
enum channel_remove_err {
|
||||
/* All OK! */
|
||||
CHANNEL_ERR_REMOVE_OK,
|
||||
/* No such HTLC. */
|
||||
CHANNEL_ERR_NO_SUCH_ID,
|
||||
/* Already have fulfilled it */
|
||||
CHANNEL_ERR_ALREADY_FULFILLED,
|
||||
/* Preimage doesn't hash to value. */
|
||||
CHANNEL_ERR_BAD_PREIMAGE,
|
||||
/* HTLC is not committed */
|
||||
CHANNEL_ERR_HTLC_UNCOMMITTED,
|
||||
/* HTLC is not committed and prior revoked on both sides */
|
||||
CHANNEL_ERR_HTLC_NOT_IRREVOCABLE
|
||||
};
|
||||
|
||||
/**
|
||||
* channel_fail_htlc: remove an HTLC, funds to the side which offered it.
|
||||
* @channel: The channel state
|
||||
* @owner: the side who offered the HTLC (opposite to that failing it)
|
||||
* @id: unique HTLC id.
|
||||
*
|
||||
* This will remove the htlc and credit the value of the HTLC (back)
|
||||
* to its offerer.
|
||||
*/
|
||||
enum channel_remove_err channel_fail_htlc(struct channel *channel,
|
||||
enum side owner, u64 id);
|
||||
|
||||
/**
|
||||
* channel_fulfill_htlc: remove an HTLC, funds to side which accepted it.
|
||||
* @channel: The channel state
|
||||
* @owner: the side who offered the HTLC (opposite to that fulfilling it)
|
||||
* @id: unique HTLC id.
|
||||
*
|
||||
* If the htlc exists, is not already fulfilled, the preimage is correct and
|
||||
* HTLC committed at the recipient, this will add a pending change to
|
||||
* remove the htlc and give the value of the HTLC to its recipient,
|
||||
* and return CHANNEL_ERR_FULFILL_OK. Otherwise, it will return another error.
|
||||
*/
|
||||
enum channel_remove_err channel_fulfill_htlc(struct channel *channel,
|
||||
enum side owner,
|
||||
u64 id,
|
||||
const struct preimage *preimage);
|
||||
|
||||
/**
|
||||
* approx_max_feerate: what's the we (initiator) could raise fee rate to?
|
||||
* @channel: The channel state
|
||||
*
|
||||
* This is not exact! To check if their offer is valid, use can_afford_feerate.
|
||||
*/
|
||||
u64 approx_max_feerate(const struct channel *channel);
|
||||
|
||||
/**
|
||||
* can_afford_feerate: could the initiator pay for the fee at fee_rate?
|
||||
* @channel: The channel state
|
||||
* @feerate_per_kw: the new fee rate proposed
|
||||
*/
|
||||
bool can_afford_feerate(const struct channel *channel, u64 feerate_per_kw);
|
||||
|
||||
/**
|
||||
* adjust_fee: Change fee rate.
|
||||
* @channel: The channel state
|
||||
* @feerate_per_kw: fee in satoshi per 1000 bytes.
|
||||
* @side: which side to adjust.
|
||||
*/
|
||||
void adjust_fee(struct channel *channel, u64 feerate_per_kw, enum side side);
|
||||
|
||||
/**
|
||||
* channel_sending_commit: commit all remote outstanding changes.
|
||||
* @channel: the channel
|
||||
* @htlcs: initially-empty tal_arr() for htlcs which changed state.
|
||||
*
|
||||
* This is where we commit to pending changes we've added; returns true if
|
||||
* anything changed for the remote side (if not, don't send!) */
|
||||
bool channel_sending_commit(struct channel *channel,
|
||||
const struct htlc ***htlcs);
|
||||
|
||||
/**
|
||||
* channel_rcvd_revoke_and_ack: accept ack on remote committed changes.
|
||||
* @channel: the channel
|
||||
* @htlcs: initially-empty tal_arr() for htlcs which changed state.
|
||||
*
|
||||
* This is where we commit to pending changes we've added; returns true if
|
||||
* anything changed for our local commitment (ie. we have pending changes).
|
||||
*/
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel,
|
||||
const struct htlc ***htlcs);
|
||||
|
||||
/**
|
||||
* channel_rcvd_commit: commit all local outstanding changes.
|
||||
* @channel: the channel
|
||||
* @htlcs: initially-empty tal_arr() for htlcs which changed state.
|
||||
*
|
||||
* This is where we commit to pending changes we've added; returns true if
|
||||
* anything changed for our local commitment (ie. we had pending changes).
|
||||
*/
|
||||
bool channel_rcvd_commit(struct channel *channel,
|
||||
const struct htlc ***htlcs);
|
||||
|
||||
/**
|
||||
* channel_sending_revoke_and_ack: sending ack on local committed changes.
|
||||
* @channel: the channel
|
||||
*
|
||||
* This is where we commit to pending changes we've added. Returns true if
|
||||
* anything changed for the remote commitment (ie. send a new commit).*/
|
||||
bool channel_sending_revoke_and_ack(struct channel *channel);
|
||||
|
||||
/**
|
||||
* channel_awaiting_revoke_and_ack: are we waiting for revoke_and_ack?
|
||||
* @channel: the channel
|
||||
*
|
||||
* If true, we can't send a new commit message.
|
||||
*/
|
||||
bool channel_awaiting_revoke_and_ack(const struct channel *channel);
|
||||
|
||||
/**
|
||||
* channel_has_htlcs: are there any (live) HTLCs at all in channel?
|
||||
* @channel: the channel
|
||||
*/
|
||||
bool channel_has_htlcs(const struct channel *channel);
|
||||
|
||||
/**
|
||||
* channel_force_htlcs: force these htlcs into the (new) channel
|
||||
* @channel: the channel
|
||||
* @htlcs: the htlcs to add (tal_arr)
|
||||
* @hstates: the states for the htlcs (tal_arr of same size)
|
||||
* @fulfilled: htlcs of those which are fulfilled
|
||||
* @fulfilled_sides: sides for ids in @fulfilled
|
||||
* @failed: htlcs of those which are failed
|
||||
* @failed_sides: sides for ids in @failed
|
||||
*
|
||||
* This is used for restoring a channel state.
|
||||
*/
|
||||
bool channel_force_htlcs(struct channel *channel,
|
||||
const struct added_htlc *htlcs,
|
||||
const enum htlc_state *hstates,
|
||||
const struct fulfilled_htlc *fulfilled,
|
||||
const enum side *fulfilled_sides,
|
||||
const struct failed_htlc *failed,
|
||||
const enum side *failed_sides);
|
||||
|
||||
/**
|
||||
* dump_htlcs: debugging dump of all HTLCs
|
||||
* @channel: the channel
|
||||
* @prefix: the prefix to prepend to each line.
|
||||
*
|
||||
* Uses status_trace() on every HTLC.
|
||||
*/
|
||||
void dump_htlcs(const struct channel *channel, const char *prefix);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_FULL_CHANNEL_H */
|
||||
@@ -1,78 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/closing-wrongdir:
|
||||
$(MAKE) -C ../.. lightningd/closing-all
|
||||
|
||||
default: lightningd/closing-all
|
||||
|
||||
lightningd/closing-all: lightningd/lightningd_closing
|
||||
|
||||
# lightningd/closing needs these:
|
||||
LIGHTNINGD_CLOSING_HEADERS_GEN := \
|
||||
lightningd/closing/gen_closing_wire.h
|
||||
|
||||
LIGHTNINGD_CLOSING_HEADERS_NOGEN :=
|
||||
|
||||
LIGHTNINGD_CLOSING_HEADERS := $(LIGHTNINGD_CLOSING_HEADERS_GEN) $(LIGHTNINGD_CLOSING_HEADERS_NOGEN)
|
||||
|
||||
LIGHTNINGD_CLOSING_SRC := lightningd/closing/closing.c \
|
||||
$(LIGHTNINGD_CLOSING_HEADERS:.h=.c)
|
||||
LIGHTNINGD_CLOSING_OBJS := $(LIGHTNINGD_CLOSING_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_CLOSING_OBJS)
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_CLOSING_CONTROL_HEADERS := $(LIGHTNINGD_CLOSING_HEADERS)
|
||||
LIGHTNINGD_CLOSING_CONTROL_SRC := $(LIGHTNINGD_CLOSING_HEADERS:.h=.c)
|
||||
LIGHTNINGD_CLOSING_CONTROL_OBJS := $(LIGHTNINGD_CLOSING_CONTROL_SRC:.c=.o)
|
||||
|
||||
LIGHTNINGD_CLOSING_GEN_SRC := $(filter lightningd/closing/gen_%, $(LIGHTNINGD_CLOSING_SRC) $(LIGHTNINGD_CLOSING_CONTROL_SRC))
|
||||
|
||||
LIGHTNINGD_CLOSING_SRC_NOGEN := $(filter-out lightningd/closing/gen_%, $(LIGHTNINGD_CLOSING_SRC))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_CLOSING_HEADERS_GEN)
|
||||
LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_CLOSING_HEADERS_NOGEN)
|
||||
|
||||
$(LIGHTNINGD_CLOSING_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
# Common source we use.
|
||||
CLOSINGD_COMMON_OBJS := \
|
||||
common/close_tx.o \
|
||||
common/crypto_sync.o \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/dev_disconnect.o \
|
||||
common/derive_basepoints.o \
|
||||
common/htlc_wire.o \
|
||||
common/msg_queue.o \
|
||||
common/permute_tx.o \
|
||||
common/status.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o
|
||||
|
||||
lightningd/closing/gen_closing_wire.h: $(WIRE_GEN) lightningd/closing/closing_wire.csv
|
||||
$(WIRE_GEN) --header $@ closing_wire_type < lightningd/closing/closing_wire.csv > $@
|
||||
|
||||
lightningd/closing/gen_closing_wire.c: $(WIRE_GEN) lightningd/closing/closing_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} closing_wire_type < lightningd/closing/closing_wire.csv > $@
|
||||
|
||||
LIGHTNINGD_CLOSING_OBJS := $(LIGHTNINGD_CLOSING_SRC:.c=.o) $(LIGHTNINGD_CLOSING_GEN_SRC:.c=.o)
|
||||
|
||||
lightningd/lightningd_closing: $(LIGHTNINGD_CLOSING_OBJS) $(WIRE_ONION_OBJS) $(CLOSINGD_COMMON_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS)
|
||||
|
||||
check-source: $(LIGHTNINGD_CLOSING_SRC_NOGEN:%=check-src-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_CLOSING_SRC:%=bolt-check/%) $(LIGHTNINGD_CLOSING_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-whitespace: $(LIGHTNINGD_CLOSING_SRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_CLOSING_HEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/closing-clean
|
||||
|
||||
lightningd/closing-clean:
|
||||
$(RM) $(LIGHTNINGD_CLOSING_OBJS) gen_*
|
||||
|
||||
-include lightningd/closing/test/Makefile
|
||||
@@ -1,476 +0,0 @@
|
||||
#include <bitcoin/script.h>
|
||||
#include <common/close_tx.h>
|
||||
#include <common/crypto_sync.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/derive_basepoints.h>
|
||||
#include <common/htlc.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <common/version.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/closing/gen_closing_wire.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <wire/peer_wire.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
/* stdin == requests, 3 == peer, 4 = gossip */
|
||||
#define REQ_FD STDIN_FILENO
|
||||
#define PEER_FD 3
|
||||
#define GOSSIP_FD 4
|
||||
|
||||
static struct bitcoin_tx *close_tx(const tal_t *ctx,
|
||||
u8 *scriptpubkey[NUM_SIDES],
|
||||
const struct sha256_double *funding_txid,
|
||||
unsigned int funding_txout,
|
||||
u64 funding_satoshi,
|
||||
const u64 satoshi_out[NUM_SIDES],
|
||||
enum side funder,
|
||||
uint64_t fee,
|
||||
uint64_t dust_limit)
|
||||
{
|
||||
struct bitcoin_tx *tx;
|
||||
|
||||
if (satoshi_out[funder] < fee)
|
||||
status_failed(WIRE_CLOSING_NEGOTIATION_ERROR,
|
||||
"Funder cannot afford fee %"PRIu64
|
||||
" (%"PRIu64" and %"PRIu64")",
|
||||
fee, satoshi_out[LOCAL],
|
||||
satoshi_out[REMOTE]);
|
||||
|
||||
status_trace("Making close tx at = %"PRIu64"/%"PRIu64" fee %"PRIu64,
|
||||
satoshi_out[LOCAL], satoshi_out[REMOTE], fee);
|
||||
|
||||
tx = create_close_tx(ctx, scriptpubkey[LOCAL], scriptpubkey[REMOTE],
|
||||
funding_txid,
|
||||
funding_txout,
|
||||
funding_satoshi,
|
||||
satoshi_out[LOCAL] - (funder == LOCAL ? fee : 0),
|
||||
satoshi_out[REMOTE] - (funder == REMOTE ? fee : 0),
|
||||
dust_limit);
|
||||
if (!tx)
|
||||
status_failed(WIRE_CLOSING_NEGOTIATION_ERROR,
|
||||
"Both outputs below dust limit:"
|
||||
" funding = %"PRIu64
|
||||
" fee = %"PRIu64
|
||||
" dust_limit = %"PRIu64
|
||||
" LOCAL = %"PRIu64
|
||||
" REMOTE = %"PRIu64,
|
||||
funding_satoshi,
|
||||
fee,
|
||||
dust_limit,
|
||||
satoshi_out[LOCAL],
|
||||
satoshi_out[REMOTE]);
|
||||
return tx;
|
||||
}
|
||||
|
||||
static u64 one_towards(u64 target, u64 value)
|
||||
{
|
||||
if (value > target)
|
||||
return value-1;
|
||||
else if (value < target)
|
||||
return value+1;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void do_reconnect(struct crypto_state *cs,
|
||||
const struct channel_id *channel_id,
|
||||
const u64 next_index[NUM_SIDES],
|
||||
u64 revocations_received)
|
||||
{
|
||||
u8 *msg;
|
||||
struct channel_id their_channel_id;
|
||||
const tal_t *tmpctx = tal_tmpctx(NULL);
|
||||
u64 next_local_commitment_number, next_remote_revocation_number;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* On reconnection, a node MUST transmit `channel_reestablish` for
|
||||
* each channel, and MUST wait for to receive the other node's
|
||||
* `channel_reestablish` message before sending any other messages for
|
||||
* that channel. The sending node MUST set
|
||||
* `next_local_commitment_number` to the commitment number of the next
|
||||
* `commitment_signed` it expects to receive, and MUST set
|
||||
* `next_remote_revocation_number` to the commitment number of the
|
||||
* next `revoke_and_ack` message it expects to receive.
|
||||
*/
|
||||
msg = towire_channel_reestablish(tmpctx, channel_id,
|
||||
next_index[LOCAL],
|
||||
revocations_received);
|
||||
if (!sync_crypto_write(cs, PEER_FD, take(msg)))
|
||||
status_failed(WIRE_CLOSING_PEER_WRITE_FAILED,
|
||||
"Failed writing reestablish: %s", strerror(errno));
|
||||
|
||||
again:
|
||||
msg = sync_crypto_read(tmpctx, cs, PEER_FD);
|
||||
if (!msg)
|
||||
status_failed(WIRE_CLOSING_PEER_READ_FAILED,
|
||||
"Failed reading reestablish: %s", strerror(errno));
|
||||
|
||||
if (is_gossip_msg(msg)) {
|
||||
if (!wire_sync_write(GOSSIP_FD, take(msg)))
|
||||
status_failed(WIRE_CLOSING_GOSSIP_FAILED,
|
||||
"Writing gossip");
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!fromwire_channel_reestablish(msg, NULL, &their_channel_id,
|
||||
&next_local_commitment_number,
|
||||
&next_remote_revocation_number)) {
|
||||
status_failed(WIRE_CLOSING_PEER_READ_FAILED,
|
||||
"bad reestablish msg: %s %s",
|
||||
wire_type_name(fromwire_peektype(msg)),
|
||||
tal_hex(tmpctx, msg));
|
||||
}
|
||||
status_trace("Got reestablish commit=%"PRIu64" revoke=%"PRIu64,
|
||||
next_local_commitment_number,
|
||||
next_remote_revocation_number);
|
||||
|
||||
/* FIXME: Spec says to re-xmit funding_locked here if we haven't
|
||||
* done any updates. */
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* On reconnection if the node has sent a previous `closing_signed` it
|
||||
* MUST send another `closing_signed`
|
||||
*/
|
||||
|
||||
/* Since we always transmit closing_signed immediately, if
|
||||
* we're reconnecting we consider ourselves to have transmitted once,
|
||||
* and we'll immediately do the retransmit now anyway. */
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct crypto_state cs;
|
||||
const tal_t *ctx = tal_tmpctx(NULL);
|
||||
u8 *msg;
|
||||
struct privkey seed;
|
||||
struct pubkey funding_pubkey[NUM_SIDES];
|
||||
struct sha256_double funding_txid;
|
||||
u16 funding_txout;
|
||||
u64 funding_satoshi, satoshi_out[NUM_SIDES];
|
||||
u64 our_dust_limit;
|
||||
u64 minfee, maxfee, sent_fee;
|
||||
s64 last_received_fee = -1;
|
||||
enum side funder;
|
||||
u8 *scriptpubkey[NUM_SIDES], *funding_wscript;
|
||||
struct channel_id channel_id;
|
||||
struct secrets secrets;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
bool reconnected;
|
||||
u64 next_index[NUM_SIDES], revocations_received;
|
||||
|
||||
if (argc == 2 && streq(argv[1], "--version")) {
|
||||
printf("%s\n", version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
subdaemon_debug(argc, argv);
|
||||
|
||||
/* We handle write returning errors! */
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
status_setup_sync(REQ_FD);
|
||||
|
||||
msg = wire_sync_read(ctx, REQ_FD);
|
||||
if (!fromwire_closing_init(ctx, msg, NULL,
|
||||
&cs, &seed,
|
||||
&funding_txid, &funding_txout,
|
||||
&funding_satoshi,
|
||||
&funding_pubkey[REMOTE],
|
||||
&funder,
|
||||
&satoshi_out[LOCAL],
|
||||
&satoshi_out[REMOTE],
|
||||
&our_dust_limit,
|
||||
&minfee, &maxfee, &sent_fee,
|
||||
&scriptpubkey[LOCAL],
|
||||
&scriptpubkey[REMOTE],
|
||||
&reconnected,
|
||||
&next_index[LOCAL],
|
||||
&next_index[REMOTE],
|
||||
&revocations_received)) {
|
||||
status_failed(WIRE_CLOSING_PEER_BAD_MESSAGE,
|
||||
"Bad init message %s", tal_hex(ctx, msg));
|
||||
}
|
||||
status_trace("satoshi_out = %"PRIu64"/%"PRIu64,
|
||||
satoshi_out[LOCAL], satoshi_out[REMOTE]);
|
||||
status_trace("dustlimit = %"PRIu64, our_dust_limit);
|
||||
status_trace("fee = %"PRIu64, sent_fee);
|
||||
derive_channel_id(&channel_id, &funding_txid, funding_txout);
|
||||
derive_basepoints(&seed, &funding_pubkey[LOCAL], NULL,
|
||||
&secrets, NULL);
|
||||
|
||||
funding_wscript = bitcoin_redeem_2of2(ctx,
|
||||
&funding_pubkey[LOCAL],
|
||||
&funding_pubkey[REMOTE]);
|
||||
|
||||
if (reconnected)
|
||||
do_reconnect(&cs, &channel_id, next_index, revocations_received);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* Nodes SHOULD send a `closing_signed` message after `shutdown` has
|
||||
* been received and no HTLCs remain in either commitment transaction.
|
||||
*/
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* On reconnection, ... if the node has sent a previous
|
||||
* `closing_signed` it MUST send another `closing_signed`, otherwise
|
||||
* if the node has sent a previous `shutdown` it MUST retransmit it.
|
||||
*/
|
||||
for (;;) {
|
||||
const tal_t *tmpctx = tal_tmpctx(ctx);
|
||||
struct bitcoin_tx *tx;
|
||||
u64 received_fee, limit_fee, new_fee;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sender MUST set `signature` to the Bitcoin signature of
|
||||
* the close transaction as specified in [BOLT
|
||||
* #3](03-transactions.md#closing-transaction).
|
||||
*/
|
||||
tx = close_tx(tmpctx, scriptpubkey,
|
||||
&funding_txid,
|
||||
funding_txout,
|
||||
funding_satoshi,
|
||||
satoshi_out, funder, sent_fee, our_dust_limit);
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* ## Closing Transaction
|
||||
*...
|
||||
* Each node offering a signature... MAY also eliminate its
|
||||
* own output.
|
||||
*/
|
||||
/* (We don't do this). */
|
||||
sign_tx_input(tx, 0, NULL, funding_wscript,
|
||||
&secrets.funding_privkey,
|
||||
&funding_pubkey[LOCAL],
|
||||
&sig);
|
||||
|
||||
status_trace("sending fee offer %"PRIu64, sent_fee);
|
||||
|
||||
/* Now send closing offer */
|
||||
msg = towire_closing_signed(tmpctx, &channel_id, sent_fee, &sig);
|
||||
if (!sync_crypto_write(&cs, PEER_FD, take(msg)))
|
||||
status_failed(WIRE_CLOSING_PEER_WRITE_FAILED,
|
||||
"Writing closing_signed");
|
||||
|
||||
/* Did we just agree with them? If so, we're done. */
|
||||
if (sent_fee == last_received_fee)
|
||||
break;
|
||||
|
||||
again:
|
||||
msg = sync_crypto_read(tmpctx, &cs, PEER_FD);
|
||||
if (!msg)
|
||||
status_failed(WIRE_CLOSING_PEER_READ_FAILED,
|
||||
"Reading input");
|
||||
|
||||
/* We don't send gossip at this stage, but we can recv it */
|
||||
if (is_gossip_msg(msg)) {
|
||||
if (!wire_sync_write(GOSSIP_FD, take(msg)))
|
||||
status_failed(WIRE_CLOSING_GOSSIP_FAILED,
|
||||
"Writing gossip");
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* On reconnection, a node MUST ignore a redundant
|
||||
* `funding_locked` if it receives one.
|
||||
*/
|
||||
/* This should only happen if we've made no commitments, but
|
||||
* we don't have to check that: it's their problem. */
|
||||
if (fromwire_peektype(msg) == WIRE_FUNDING_LOCKED) {
|
||||
tal_free(msg);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ...if the node has sent a previous `shutdown` it MUST
|
||||
* retransmit it.
|
||||
*/
|
||||
if (fromwire_peektype(msg) == WIRE_SHUTDOWN) {
|
||||
tal_free(msg);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!fromwire_closing_signed(msg, NULL, &channel_id,
|
||||
&received_fee, &sig))
|
||||
status_failed(WIRE_CLOSING_PEER_BAD_MESSAGE,
|
||||
"Expected closing_signed: %s",
|
||||
tal_hex(trc, msg));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver MUST check `signature` is valid for either
|
||||
* variant of close transaction specified in [BOLT
|
||||
* #3](03-transactions.md#closing-transaction), and MUST fail
|
||||
* the connection if it is not.
|
||||
*/
|
||||
tx = close_tx(tmpctx, scriptpubkey,
|
||||
&funding_txid,
|
||||
funding_txout,
|
||||
funding_satoshi,
|
||||
satoshi_out, funder, received_fee, our_dust_limit);
|
||||
|
||||
if (!check_tx_sig(tx, 0, NULL, funding_wscript,
|
||||
&funding_pubkey[REMOTE], &sig)) {
|
||||
/* Trim it by reducing their output to minimum */
|
||||
struct bitcoin_tx *trimmed;
|
||||
u64 trimming_satoshi_out[NUM_SIDES];
|
||||
|
||||
if (funder == REMOTE)
|
||||
trimming_satoshi_out[REMOTE] = received_fee;
|
||||
else
|
||||
trimming_satoshi_out[REMOTE] = 0;
|
||||
trimming_satoshi_out[LOCAL] = satoshi_out[LOCAL];
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* Each node offering a signature MUST subtract the
|
||||
* fee given by `fee_satoshis` from the output to the
|
||||
* funder; it MUST then remove any output below its
|
||||
* own `dust_limit_satoshis`, and MAY also eliminate
|
||||
* its own output.
|
||||
*/
|
||||
trimmed = close_tx(tmpctx, scriptpubkey,
|
||||
&funding_txid,
|
||||
funding_txout,
|
||||
funding_satoshi,
|
||||
trimming_satoshi_out,
|
||||
funder, received_fee, our_dust_limit);
|
||||
if (!trimmed
|
||||
|| !check_tx_sig(trimmed, 0, NULL, funding_wscript,
|
||||
&funding_pubkey[REMOTE], &sig)) {
|
||||
status_failed(WIRE_CLOSING_PEER_BAD_MESSAGE,
|
||||
"Bad closing_signed signature for"
|
||||
" %s (and trimmed version %s)",
|
||||
type_to_string(tmpctx,
|
||||
struct bitcoin_tx,
|
||||
tx),
|
||||
trimmed ?
|
||||
type_to_string(tmpctx,
|
||||
struct bitcoin_tx,
|
||||
trimmed)
|
||||
: "NONE");
|
||||
}
|
||||
tx = trimmed;
|
||||
}
|
||||
|
||||
status_trace("Received fee offer %"PRIu64, received_fee);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* Otherwise, the recipient MUST fail the connection if
|
||||
* `fee_satoshis` is greater than the base fee of the final
|
||||
* commitment transaction as calculated in [BOLT #3] */
|
||||
if (received_fee > maxfee)
|
||||
status_failed(WIRE_CLOSING_PEER_BAD_MESSAGE,
|
||||
"Bad closing_signed fee %"PRIu64
|
||||
" > %"PRIu64,
|
||||
received_fee, maxfee);
|
||||
|
||||
/* Is fee reasonable? Tell master. */
|
||||
if (received_fee < minfee) {
|
||||
status_trace("Fee too low, below %"PRIu64, minfee);
|
||||
limit_fee = minfee;
|
||||
} else {
|
||||
status_trace("Fee accepted.");
|
||||
msg = towire_closing_received_signature(tmpctx,
|
||||
&sig, tx);
|
||||
if (!wire_sync_write(REQ_FD, take(msg)))
|
||||
status_failed(WIRE_CLOSING_INTERNAL_ERROR,
|
||||
"Writing received to master: %s",
|
||||
strerror(errno));
|
||||
msg = wire_sync_read(tmpctx, REQ_FD);
|
||||
if (!fromwire_closing_received_signature_reply(msg,NULL))
|
||||
status_failed(WIRE_CLOSING_INTERNAL_ERROR,
|
||||
"Bad received reply from master");
|
||||
limit_fee = received_fee;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* If `fee_satoshis` is equal to its previously sent
|
||||
* `fee_satoshis`, the receiver SHOULD sign and broadcast the
|
||||
* final closing transaction and MAY close the connection.
|
||||
*/
|
||||
if (received_fee == sent_fee)
|
||||
break;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* the recipient SHOULD fail the connection if `fee_satoshis`
|
||||
* is not strictly between its last-sent `fee_satoshis` and
|
||||
* its previously-received `fee_satoshis`, unless it has
|
||||
* reconnected since then. */
|
||||
if (last_received_fee != -1) {
|
||||
bool previous_dir = sent_fee < last_received_fee;
|
||||
bool dir = received_fee < last_received_fee;
|
||||
bool next_dir = sent_fee < received_fee;
|
||||
|
||||
/* They went away from our offer? */
|
||||
if (dir != previous_dir)
|
||||
status_failed(WIRE_CLOSING_NEGOTIATION_ERROR,
|
||||
"Their fee went %"
|
||||
PRIu64" to %"PRIu64
|
||||
" when ours was %"PRIu64,
|
||||
last_received_fee,
|
||||
received_fee,
|
||||
sent_fee);
|
||||
|
||||
/* They jumped over our offer? */
|
||||
if (next_dir != previous_dir)
|
||||
status_failed(WIRE_CLOSING_NEGOTIATION_ERROR,
|
||||
"Their fee jumped %"
|
||||
PRIu64" to %"PRIu64
|
||||
" when ours was %"PRIu64,
|
||||
last_received_fee,
|
||||
received_fee,
|
||||
sent_fee);
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* ...otherwise it MUST propose a value strictly between the
|
||||
* received `fee_satoshis` and its previously-sent
|
||||
* `fee_satoshis`.
|
||||
*/
|
||||
|
||||
/* We do it by bisection, with twists:
|
||||
* 1. Don't go outside limits, or reach them immediately:
|
||||
* treat out-of-limit offers as on-limit offers.
|
||||
* 2. Round towards the target, otherwise we can't close
|
||||
* a final 1-satoshi gap.
|
||||
*
|
||||
* Note: Overflow impossible here, since fee <= funder amount */
|
||||
new_fee = one_towards(limit_fee, limit_fee + sent_fee) / 2;
|
||||
|
||||
/* If we didn't move, give up (we're ~ at min/max). */
|
||||
if (new_fee == sent_fee)
|
||||
status_failed(WIRE_CLOSING_NEGOTIATION_ERROR,
|
||||
"Final fee %"PRIu64" vs %"PRIu64
|
||||
" at limits %"PRIu64"-%"PRIu64,
|
||||
sent_fee, received_fee,
|
||||
minfee, maxfee);
|
||||
|
||||
last_received_fee = received_fee;
|
||||
sent_fee = new_fee;
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
/* We're done! */
|
||||
wire_sync_write(REQ_FD, take(towire_closing_complete(ctx)));
|
||||
tal_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
# Shouldn't happen
|
||||
closing_bad_command,0x8000
|
||||
# Also shouldn't happen
|
||||
closing_gossip_failed,0x8001
|
||||
closing_internal_error,0x8003
|
||||
|
||||
# These are due to peer.
|
||||
closing_peer_write_failed,0x8010
|
||||
closing_peer_read_failed,0x8011
|
||||
closing_peer_bad_message,0x8012
|
||||
closing_peer_bad_message,,len,u16
|
||||
closing_peer_bad_message,,msg,len*u8
|
||||
closing_negotiation_error,0x8013
|
||||
closing_negotiation_error,,len,u16
|
||||
closing_negotiation_error,,msg,len*u8
|
||||
|
||||
#include <common/cryptomsg.h>
|
||||
#include <common/htlc_wire.h>
|
||||
# Begin! (passes peer fd, gossipd-client fd)
|
||||
closing_init,1
|
||||
closing_init,,crypto_state,struct crypto_state
|
||||
closing_init,,seed,struct privkey
|
||||
closing_init,,funding_txid,struct sha256_double
|
||||
closing_init,,funding_txout,u16
|
||||
closing_init,,funding_satoshi,u64
|
||||
closing_init,,remote_fundingkey,struct pubkey
|
||||
closing_init,,funder,enum side
|
||||
closing_init,,local_msatoshi,u64
|
||||
closing_init,,remote_msatoshi,u64
|
||||
closing_init,,our_dust_limit,u64
|
||||
closing_init,,min_fee_satoshi,u64
|
||||
closing_init,,max_fee_satoshi,u64
|
||||
closing_init,,initial_fee_satoshi,u64
|
||||
closing_init,,local_scriptpubkey_len,u16
|
||||
closing_init,,local_scriptpubkey,local_scriptpubkey_len*u8
|
||||
closing_init,,remote_scriptpubkey_len,u16
|
||||
closing_init,,remote_scriptpubkey,remote_scriptpubkey_len*u8
|
||||
closing_init,,reconnected,bool
|
||||
closing_init,,next_index_local,u64
|
||||
closing_init,,next_index_remote,u64
|
||||
closing_init,,revocations_received,u64
|
||||
|
||||
# We received an offer, save signature.
|
||||
closing_received_signature,2
|
||||
closing_received_signature,,signature,secp256k1_ecdsa_signature
|
||||
closing_received_signature,,tx,struct bitcoin_tx
|
||||
|
||||
closing_received_signature_reply,102
|
||||
|
||||
# Negotiations complete, we're exiting.
|
||||
closing_complete,4
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <common/sphinx.h>
|
||||
#include <common/utils.h>
|
||||
#include <lightningd/channel/gen_channel_wire.h>
|
||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/htlc_end.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
@@ -16,7 +16,7 @@ static bool ping_reply(struct subd *subd, const u8 *msg, const int *fds,
|
||||
bool ok;
|
||||
|
||||
log_debug(subd->ld->log, "Got ping reply!");
|
||||
if (streq(subd->name, "lightningd_channel"))
|
||||
if (streq(subd->name, "lightning_channeld"))
|
||||
ok = fromwire_channel_ping_reply(msg, NULL, &totlen);
|
||||
else
|
||||
ok = fromwire_gossip_ping_reply(msg, NULL, &totlen);
|
||||
@@ -59,8 +59,8 @@ static void json_dev_ping(struct command *cmd,
|
||||
|
||||
/* FIXME: These checks are horrible, use a peer flag to say it's
|
||||
* ready to forward! */
|
||||
if (peer->owner && !streq(peer->owner->name, "lightningd_channel")
|
||||
&& !streq(peer->owner->name, "lightningd_gossip")) {
|
||||
if (peer->owner && !streq(peer->owner->name, "lightning_channeld")
|
||||
&& !streq(peer->owner->name, "lightning_gossipd")) {
|
||||
command_fail(cmd, "Peer in %s",
|
||||
peer->owner ? peer->owner->name : "unattached");
|
||||
return;
|
||||
@@ -80,7 +80,7 @@ static void json_dev_ping(struct command *cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
if (streq(peer->owner->name, "lightningd_channel"))
|
||||
if (streq(peer->owner->name, "lightning_channeld"))
|
||||
msg = towire_channel_ping(cmd, pongbytes, len);
|
||||
else
|
||||
msg = towire_gossip_ping(cmd, peer->unique_id, pongbytes, len);
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/gossip-wrongdir:
|
||||
$(MAKE) -C .. lightningd/gossip-all
|
||||
|
||||
default: lightningd/gossip-all
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_GOSSIP_CONTROL_HEADERS := lightningd/gossip/gen_gossip_wire.h
|
||||
LIGHTNINGD_GOSSIP_CONTROL_SRC := lightningd/gossip/gen_gossip_wire.c
|
||||
LIGHTNINGD_GOSSIP_CONTROL_OBJS := $(LIGHTNINGD_GOSSIP_CONTROL_SRC:.c=.o)
|
||||
|
||||
# lightningd/gossip needs these:
|
||||
LIGHTNINGD_GOSSIP_HEADERS := lightningd/gossip/gen_gossip_wire.h \
|
||||
lightningd/gossip/routing.h \
|
||||
lightningd/gossip/broadcast.h
|
||||
LIGHTNINGD_GOSSIP_SRC := lightningd/gossip/gossip.c \
|
||||
$(LIGHTNINGD_GOSSIP_HEADERS:.h=.c)
|
||||
LIGHTNINGD_GOSSIP_OBJS := $(LIGHTNINGD_GOSSIP_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_GOSSIP_OBJS)
|
||||
|
||||
# For checking
|
||||
LIGHTNINGD_GOSSIP_ALLSRC_NOGEN := $(filter-out lightningd/gossip/gen_%, $(LIGHTNINGD_GOSSIP_CLIENT_SRC) $(LIGHTNINGD_GOSSIP_SRC))
|
||||
LIGHTNINGD_GOSSIP_ALLHEADERS_NOGEN := $(filter-out lightningd/gossip/gen_%, $(LIGHTNINGD_GOSSIP_CLIENT_HEADERS) $(LIGHTNINGD_GOSSIP_HEADERS))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_GOSSIP_HEADERS)
|
||||
|
||||
# Common source we use.
|
||||
GOSSIPD_COMMON_OBJS := \
|
||||
common/crypto_sync.o \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/dev_disconnect.o \
|
||||
common/msg_queue.o \
|
||||
common/ping.o \
|
||||
common/pseudorand.o \
|
||||
common/status.o \
|
||||
common/timeout.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o \
|
||||
lightningd/gossip_msg.o
|
||||
|
||||
$(LIGHTNINGD_GOSSIP_OBJS) $(LIGHTNINGD_GOSSIP_CLIENT_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
$(LIGHTNINGD_GOSSIP_CONTROL_OBJS) : $(LIGHTNINGD_GOSSIP_CONTROL_HEADERS)
|
||||
|
||||
lightningd/gossip-all: lightningd/lightningd_gossip $(LIGHTNINGD_GOSSIP_CLIENT_OBJS)
|
||||
|
||||
lightningd/lightningd_gossip: $(LIGHTNINGD_GOSSIP_OBJS) $(GOSSIPD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS)
|
||||
|
||||
lightningd/gossip/gen_gossip_wire.h: $(WIRE_GEN) lightningd/gossip/gossip_wire.csv
|
||||
$(WIRE_GEN) --header $@ gossip_wire_type < lightningd/gossip/gossip_wire.csv > $@
|
||||
|
||||
lightningd/gossip/gen_gossip_wire.c: $(WIRE_GEN) lightningd/gossip/gossip_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} gossip_wire_type < lightningd/gossip/gossip_wire.csv > $@
|
||||
|
||||
check-source: $(LIGHTNINGD_GOSSIP_ALLSRC_NOGEN:%=check-src-include-order/%) $(LIGHTNINGD_GOSSIP_ALLHEADERS_NOGEN:%=check-hdr-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_GOSSIP_SRC:%=bolt-check/%) $(LIGHTNINGD_GOSSIP_HEADERS:%=bolt-check/%)
|
||||
check-whitespace: $(LIGHTNINGD_GOSSIP_ALLSRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_GOSSIP_ALLHEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/gossip-clean
|
||||
|
||||
lightningd/gossip-clean:
|
||||
$(RM) $(LIGHTNINGD_GOSSIP_OBJS) gen_*
|
||||
|
||||
-include lightningd/gossip/test/Makefile
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <lightningd/gossip/broadcast.h>
|
||||
|
||||
struct broadcast_state *new_broadcast_state(tal_t *ctx)
|
||||
{
|
||||
struct broadcast_state *bstate = tal(ctx, struct broadcast_state);
|
||||
uintmap_init(&bstate->broadcasts);
|
||||
/* Skip 0 because we initialize peers with 0 */
|
||||
bstate->next_index = 1;
|
||||
return bstate;
|
||||
}
|
||||
|
||||
static struct queued_message *new_queued_message(tal_t *ctx,
|
||||
const int type,
|
||||
const u8 *tag,
|
||||
const u8 *payload)
|
||||
{
|
||||
struct queued_message *msg = tal(ctx, struct queued_message);
|
||||
msg->type = type;
|
||||
msg->tag = tal_dup_arr(msg, u8, tag, tal_count(tag), 0);
|
||||
msg->payload = tal_dup_arr(msg, u8, payload, tal_count(payload), 0);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void queue_broadcast(struct broadcast_state *bstate,
|
||||
const int type,
|
||||
const u8 *tag,
|
||||
const u8 *payload)
|
||||
{
|
||||
struct queued_message *msg;
|
||||
u64 index = 0;
|
||||
/* Remove any tag&type collisions */
|
||||
while (true) {
|
||||
msg = next_broadcast_message(bstate, &index);
|
||||
if (msg == NULL)
|
||||
break;
|
||||
else if (msg->type == type && memcmp(msg->tag, tag, tal_count(tag)) == 0) {
|
||||
uintmap_del(&bstate->broadcasts, index);
|
||||
tal_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now add the message to the queue */
|
||||
msg = new_queued_message(bstate, type, tag, payload);
|
||||
uintmap_add(&bstate->broadcasts, bstate->next_index, msg);
|
||||
bstate->next_index += 1;
|
||||
}
|
||||
|
||||
struct queued_message *next_broadcast_message(struct broadcast_state *bstate, u64 *last_index)
|
||||
{
|
||||
return uintmap_after(&bstate->broadcasts, last_index);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_BROADCAST_H
|
||||
#define LIGHTNING_LIGHTNINGD_GOSSIP_BROADCAST_H
|
||||
#include "config.h"
|
||||
|
||||
#include <ccan/intmap/intmap.h>
|
||||
#include <ccan/list/list.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
/* Common functionality to implement staggered broadcasts with replacement. */
|
||||
|
||||
struct queued_message {
|
||||
int type;
|
||||
|
||||
/* Unique tag specifying the msg origin */
|
||||
void *tag;
|
||||
|
||||
/* Serialized payload */
|
||||
u8 *payload;
|
||||
};
|
||||
|
||||
struct broadcast_state {
|
||||
u32 next_index;
|
||||
UINTMAP(struct queued_message *) broadcasts;
|
||||
};
|
||||
|
||||
struct broadcast_state *new_broadcast_state(tal_t *ctx);
|
||||
|
||||
/* Queue a new message to be broadcast and replace any outdated
|
||||
* broadcast. Replacement is done by comparing the `type` and the
|
||||
* `tag`, if both match the old message is dropped from the queue. The
|
||||
* new message is added to the top of the broadcast queue. */
|
||||
void queue_broadcast(struct broadcast_state *bstate,
|
||||
const int type,
|
||||
const u8 *tag,
|
||||
const u8 *payload);
|
||||
|
||||
struct queued_message *next_broadcast_message(struct broadcast_state *bstate, u64 *last_index);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_BROADCAST_H */
|
||||
@@ -1,817 +0,0 @@
|
||||
#include <ccan/container_of/container_of.h>
|
||||
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/fdpass/fdpass.h>
|
||||
#include <ccan/io/fdpass/fdpass.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/list/list.h>
|
||||
#include <ccan/noerr/noerr.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/take/take.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/timer/timer.h>
|
||||
#include <common/cryptomsg.h>
|
||||
#include <common/daemon_conn.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/ping.h>
|
||||
#include <common/status.h>
|
||||
#include <common/timeout.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <common/version.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/gossip/broadcast.h>
|
||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||
#include <lightningd/gossip/routing.h>
|
||||
#include <lightningd/gossip_msg.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
#include <wire/wire_io.h>
|
||||
|
||||
struct daemon {
|
||||
struct list_head peers;
|
||||
|
||||
/* Connection to main daemon. */
|
||||
struct daemon_conn master;
|
||||
|
||||
/* Routing information */
|
||||
struct routing_state *rstate;
|
||||
|
||||
struct timers timers;
|
||||
|
||||
u32 broadcast_interval;
|
||||
};
|
||||
|
||||
struct peer {
|
||||
struct daemon *daemon;
|
||||
/* daemon->peers */
|
||||
struct list_node list;
|
||||
|
||||
u64 unique_id;
|
||||
struct peer_crypto_state pcs;
|
||||
|
||||
/* File descriptor corresponding to conn. */
|
||||
int fd;
|
||||
|
||||
/* Our connection (and owner) */
|
||||
struct io_conn *conn;
|
||||
|
||||
/* If this is non-NULL, it means we failed. */
|
||||
const char *error;
|
||||
|
||||
/* High water mark for the staggered broadcast */
|
||||
u64 broadcast_index;
|
||||
|
||||
/* Message queue for outgoing. */
|
||||
struct msg_queue peer_out;
|
||||
|
||||
/* Is it time to continue the staggered broadcast? */
|
||||
bool gossip_sync;
|
||||
|
||||
/* The peer owner will use this to talk to gossipd */
|
||||
struct daemon_conn owner_conn;
|
||||
|
||||
/* How many pongs are we expecting? */
|
||||
size_t num_pings_outstanding;
|
||||
|
||||
/* Are we the owner of the peer? */
|
||||
bool local;
|
||||
};
|
||||
|
||||
static void wake_pkt_out(struct peer *peer);
|
||||
|
||||
static void destroy_peer(struct peer *peer)
|
||||
{
|
||||
list_del_from(&peer->daemon->peers, &peer->list);
|
||||
if (peer->error) {
|
||||
u8 *msg = towire_gossipstatus_peer_bad_msg(peer,
|
||||
peer->unique_id,
|
||||
(u8 *)peer->error);
|
||||
daemon_conn_send(&peer->daemon->master, take(msg));
|
||||
}
|
||||
}
|
||||
|
||||
static struct peer *setup_new_peer(struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
struct peer *peer = tal(daemon, struct peer);
|
||||
|
||||
init_peer_crypto_state(peer, &peer->pcs);
|
||||
if (!fromwire_gossipctl_new_peer(msg, NULL, &peer->unique_id,
|
||||
&peer->pcs.cs))
|
||||
return tal_free(peer);
|
||||
peer->daemon = daemon;
|
||||
peer->error = NULL;
|
||||
peer->local = true;
|
||||
peer->num_pings_outstanding = 0;
|
||||
peer->broadcast_index = 0;
|
||||
msg_queue_init(&peer->peer_out, peer);
|
||||
list_add_tail(&daemon->peers, &peer->list);
|
||||
tal_add_destructor(peer, destroy_peer);
|
||||
wake_pkt_out(peer);
|
||||
return peer;
|
||||
}
|
||||
|
||||
static struct peer *setup_new_remote_peer(struct daemon *daemon,
|
||||
u64 unique_id, bool sync)
|
||||
{
|
||||
struct peer *peer = tal(daemon, struct peer);
|
||||
|
||||
peer->daemon = daemon;
|
||||
peer->error = NULL;
|
||||
peer->local = false;
|
||||
peer->num_pings_outstanding = 0;
|
||||
peer->fd = -1;
|
||||
peer->unique_id = unique_id;
|
||||
if (sync)
|
||||
peer->broadcast_index = 0;
|
||||
else
|
||||
peer->broadcast_index = daemon->rstate->broadcasts->next_index;
|
||||
|
||||
msg_queue_init(&peer->peer_out, peer);
|
||||
list_add_tail(&daemon->peers, &peer->list);
|
||||
tal_add_destructor(peer, destroy_peer);
|
||||
wake_pkt_out(peer);
|
||||
return peer;
|
||||
}
|
||||
|
||||
static struct io_plan *owner_msg_in(struct io_conn *conn,
|
||||
struct daemon_conn *dc);
|
||||
static struct io_plan *nonlocal_dump_gossip(struct io_conn *conn,
|
||||
struct daemon_conn *dc);
|
||||
|
||||
/* When a peer is to be owned by another daemon, we create a socket
|
||||
* pair to send/receive gossip from it */
|
||||
static void send_peer_with_fds(struct peer *peer, const u8 *msg)
|
||||
{
|
||||
int fds[2];
|
||||
u8 *out;
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
|
||||
out = towire_gossipstatus_peer_failed(msg,
|
||||
peer->unique_id,
|
||||
(u8 *)tal_fmt(msg,
|
||||
"Failed to create socketpair: %s",
|
||||
strerror(errno)));
|
||||
daemon_conn_send(&peer->daemon->master, take(out));
|
||||
|
||||
/* FIXME: Send error to peer? */
|
||||
/* Peer will be freed when caller closes conn. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we talk to socket to get to peer's owner daemon. */
|
||||
peer->local = false;
|
||||
/* FIXME: Forget peer if other end is closed. */
|
||||
daemon_conn_init(peer, &peer->owner_conn, fds[0], owner_msg_in, NULL);
|
||||
peer->owner_conn.msg_queue_cleared_cb = nonlocal_dump_gossip;
|
||||
|
||||
/* Peer stays around, even though we're going to free conn. */
|
||||
tal_steal(peer->daemon, peer);
|
||||
|
||||
daemon_conn_send(&peer->daemon->master, msg);
|
||||
daemon_conn_send_fd(&peer->daemon->master, peer->fd);
|
||||
daemon_conn_send_fd(&peer->daemon->master, fds[1]);
|
||||
|
||||
/* Don't get confused: we can't use this any more. */
|
||||
peer->fd = -1;
|
||||
}
|
||||
|
||||
static void handle_gossip_msg(struct routing_state *rstate, u8 *msg)
|
||||
{
|
||||
int t = fromwire_peektype(msg);
|
||||
switch(t) {
|
||||
case WIRE_CHANNEL_ANNOUNCEMENT:
|
||||
handle_channel_announcement(rstate, msg, tal_count(msg));
|
||||
break;
|
||||
|
||||
case WIRE_NODE_ANNOUNCEMENT:
|
||||
handle_node_announcement(rstate, msg, tal_count(msg));
|
||||
break;
|
||||
|
||||
case WIRE_CHANNEL_UPDATE:
|
||||
handle_channel_update(rstate, msg, tal_count(msg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool handle_ping(struct peer *peer, u8 *ping)
|
||||
{
|
||||
u8 *pong;
|
||||
|
||||
if (!check_ping_make_pong(peer, ping, &pong)) {
|
||||
peer->error = "Bad ping";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pong)
|
||||
msg_enqueue(&peer->peer_out, take(pong));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_pong(struct peer *peer, const u8 *pong)
|
||||
{
|
||||
u8 *ignored;
|
||||
|
||||
status_trace("Got pong!");
|
||||
if (!fromwire_pong(pong, pong, NULL, &ignored)) {
|
||||
peer->error = "pad pong";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!peer->num_pings_outstanding) {
|
||||
peer->error = "unexpected pong";
|
||||
return false;
|
||||
}
|
||||
|
||||
peer->num_pings_outstanding--;
|
||||
daemon_conn_send(&peer->daemon->master,
|
||||
take(towire_gossip_ping_reply(pong, tal_len(pong))));
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct io_plan *peer_msgin(struct io_conn *conn,
|
||||
struct peer *peer, u8 *msg)
|
||||
{
|
||||
u8 *s;
|
||||
enum wire_type t = fromwire_peektype(msg);
|
||||
|
||||
switch (t) {
|
||||
case WIRE_ERROR:
|
||||
/* FIXME: Report error from msg. */
|
||||
peer->error = "ERROR message received";
|
||||
return io_close(conn);
|
||||
|
||||
case WIRE_CHANNEL_ANNOUNCEMENT:
|
||||
case WIRE_NODE_ANNOUNCEMENT:
|
||||
case WIRE_CHANNEL_UPDATE:
|
||||
handle_gossip_msg(peer->daemon->rstate, msg);
|
||||
return peer_read_message(conn, &peer->pcs, peer_msgin);
|
||||
|
||||
case WIRE_PING:
|
||||
if (!handle_ping(peer, msg))
|
||||
return io_close(conn);
|
||||
return peer_read_message(conn, &peer->pcs, peer_msgin);
|
||||
|
||||
case WIRE_PONG:
|
||||
if (!handle_pong(peer, msg))
|
||||
return io_close(conn);
|
||||
return peer_read_message(conn, &peer->pcs, peer_msgin);
|
||||
|
||||
case WIRE_OPEN_CHANNEL:
|
||||
case WIRE_CHANNEL_REESTABLISH:
|
||||
case WIRE_ACCEPT_CHANNEL:
|
||||
case WIRE_FUNDING_CREATED:
|
||||
case WIRE_FUNDING_SIGNED:
|
||||
case WIRE_FUNDING_LOCKED:
|
||||
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
||||
case WIRE_UPDATE_FEE:
|
||||
case WIRE_SHUTDOWN:
|
||||
case WIRE_CLOSING_SIGNED:
|
||||
case WIRE_UPDATE_ADD_HTLC:
|
||||
case WIRE_UPDATE_FULFILL_HTLC:
|
||||
case WIRE_UPDATE_FAIL_HTLC:
|
||||
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
|
||||
case WIRE_COMMITMENT_SIGNED:
|
||||
case WIRE_REVOKE_AND_ACK:
|
||||
case WIRE_INIT:
|
||||
/* Not our place to handle this, so we punt */
|
||||
s = towire_gossipstatus_peer_nongossip(msg, peer->unique_id,
|
||||
&peer->pcs.cs, msg);
|
||||
send_peer_with_fds(peer, take(s));
|
||||
return io_close_taken_fd(conn);
|
||||
}
|
||||
|
||||
/* BOLT #1:
|
||||
*
|
||||
* The type follows the _it's ok to be odd_ rule, so nodes MAY send
|
||||
* odd-numbered types without ascertaining that the recipient
|
||||
* understands it. */
|
||||
if (t & 1) {
|
||||
status_trace("Peer %"PRIu64" sent unknown packet %u, ignoring",
|
||||
peer->unique_id, t);
|
||||
return peer_read_message(conn, &peer->pcs, peer_msgin);
|
||||
}
|
||||
peer->error = tal_fmt(peer, "Unknown packet %u", t);
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
/* Wake up the outgoing direction of the connection and write any
|
||||
* queued messages. Needed since the `io_wake` method signature does
|
||||
* not allow us to specify it as the callback for `new_reltimer`, but
|
||||
* it allows us to set an additional flag for the routing dump..
|
||||
*/
|
||||
static void wake_pkt_out(struct peer *peer)
|
||||
{
|
||||
peer->gossip_sync = true;
|
||||
new_reltimer(&peer->daemon->timers, peer,
|
||||
time_from_msec(peer->daemon->broadcast_interval),
|
||||
wake_pkt_out, peer);
|
||||
/* Notify the peer-write loop */
|
||||
msg_wake(&peer->peer_out);
|
||||
/* Notify the daemon_conn-write loop */
|
||||
msg_wake(&peer->owner_conn.out);
|
||||
}
|
||||
|
||||
static struct io_plan *peer_pkt_out(struct io_conn *conn, struct peer *peer)
|
||||
{
|
||||
/* First priority is queued packets, if any */
|
||||
const u8 *out = msg_dequeue(&peer->peer_out);
|
||||
if (out)
|
||||
return peer_write_message(conn, &peer->pcs, take(out),
|
||||
peer_pkt_out);
|
||||
|
||||
/* If we're supposed to be sending gossip, do so now. */
|
||||
if (peer->gossip_sync) {
|
||||
struct queued_message *next;
|
||||
|
||||
next = next_broadcast_message(peer->daemon->rstate->broadcasts,
|
||||
&peer->broadcast_index);
|
||||
|
||||
if (next)
|
||||
return peer_write_message(conn, &peer->pcs,
|
||||
next->payload, peer_pkt_out);
|
||||
|
||||
/* Gossip is drained. Wait for next timer. */
|
||||
peer->gossip_sync = false;
|
||||
}
|
||||
|
||||
return msg_queue_wait(conn, &peer->peer_out, peer_pkt_out, peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* owner_msg_in - Called by the `peer->owner_conn` upon receiving a
|
||||
* message
|
||||
*/
|
||||
static struct io_plan *owner_msg_in(struct io_conn *conn,
|
||||
struct daemon_conn *dc)
|
||||
{
|
||||
struct peer *peer = container_of(dc, struct peer, owner_conn);
|
||||
u8 *msg = dc->msg_in;
|
||||
|
||||
int type = fromwire_peektype(msg);
|
||||
if (type == WIRE_CHANNEL_ANNOUNCEMENT || type == WIRE_CHANNEL_UPDATE ||
|
||||
type == WIRE_NODE_ANNOUNCEMENT) {
|
||||
handle_gossip_msg(peer->daemon->rstate, dc->msg_in);
|
||||
}
|
||||
return daemon_conn_read_next(conn, dc);
|
||||
}
|
||||
|
||||
/**
|
||||
* nonlocal_dump_gossip - catch the nonlocal peer up with the latest gossip.
|
||||
*
|
||||
* Registered as `msg_queue_cleared_cb` by the `peer->owner_conn`.
|
||||
*/
|
||||
static struct io_plan *nonlocal_dump_gossip(struct io_conn *conn, struct daemon_conn *dc)
|
||||
{
|
||||
struct queued_message *next;
|
||||
struct peer *peer = container_of(dc, struct peer, owner_conn);
|
||||
|
||||
|
||||
/* Make sure we are not connected directly */
|
||||
if (peer->local)
|
||||
return msg_queue_wait(conn, &peer->owner_conn.out,
|
||||
daemon_conn_write_next, dc);
|
||||
|
||||
next = next_broadcast_message(peer->daemon->rstate->broadcasts,
|
||||
&peer->broadcast_index);
|
||||
|
||||
if (!next) {
|
||||
return msg_queue_wait(conn, &peer->owner_conn.out,
|
||||
daemon_conn_write_next, dc);
|
||||
} else {
|
||||
return io_write_wire(conn, next->payload, nonlocal_dump_gossip, dc);
|
||||
}
|
||||
}
|
||||
|
||||
static struct io_plan *peer_start_gossip(struct io_conn *conn, struct peer *peer)
|
||||
{
|
||||
/* Need to go duplex here, otherwise backpressure would mean
|
||||
* we both wait indefinitely */
|
||||
return io_duplex(conn,
|
||||
peer_read_message(conn, &peer->pcs, peer_msgin),
|
||||
peer_pkt_out(conn, peer));
|
||||
}
|
||||
|
||||
static struct io_plan *new_peer_got_fd(struct io_conn *conn, struct peer *peer)
|
||||
{
|
||||
peer->conn = io_new_conn(conn, peer->fd, peer_start_gossip, peer);
|
||||
if (!peer->conn) {
|
||||
peer->error = "Could not create connection";
|
||||
tal_free(peer);
|
||||
} else {
|
||||
/* If conn dies, we forget peer. */
|
||||
tal_steal(peer->conn, peer);
|
||||
}
|
||||
return daemon_conn_read_next(conn,&peer->daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *new_peer(struct io_conn *conn, struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
struct peer *peer = setup_new_peer(daemon, msg);
|
||||
if (!peer)
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_NEW_PEER_REQUEST,
|
||||
"%s", tal_hex(trc, msg));
|
||||
return io_recv_fd(conn, &peer->fd, new_peer_got_fd, peer);
|
||||
}
|
||||
|
||||
static struct peer *find_peer(struct daemon *daemon, u64 unique_id)
|
||||
{
|
||||
struct peer *peer;
|
||||
|
||||
list_for_each(&daemon->peers, peer, list)
|
||||
if (peer->unique_id == unique_id)
|
||||
return peer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct io_plan *release_peer(struct io_conn *conn, struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
u64 unique_id;
|
||||
struct peer *peer;
|
||||
|
||||
if (!fromwire_gossipctl_release_peer(msg, NULL, &unique_id))
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST,
|
||||
"%s", tal_hex(trc, msg));
|
||||
|
||||
peer = find_peer(daemon, unique_id);
|
||||
if (!peer || !peer->local) {
|
||||
/* This can happen with a reconnect vs connect race.
|
||||
* See gossip_peer_released in master daemon. It may
|
||||
* also happen if we asked to release just before
|
||||
* failing the peer*/
|
||||
daemon_conn_send(&daemon->master,
|
||||
take(towire_gossipctl_release_peer_replyfail(msg)));
|
||||
} else {
|
||||
send_peer_with_fds(peer,
|
||||
take(towire_gossipctl_release_peer_reply(msg,
|
||||
&peer->pcs.cs)));
|
||||
io_close_taken_fd(peer->conn);
|
||||
}
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *fail_peer(struct io_conn *conn, struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
u64 unique_id;
|
||||
struct peer *peer;
|
||||
|
||||
if (!fromwire_gossipctl_fail_peer(msg, NULL, &unique_id))
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_FAIL_REQUEST,
|
||||
"%s", tal_hex(trc, msg));
|
||||
|
||||
/* This may not find the peer, if we fail beforehand. */
|
||||
peer = find_peer(daemon, unique_id);
|
||||
if (!peer)
|
||||
status_trace("Unknown fail_peer %"PRIu64, unique_id);
|
||||
else if (peer->local) {
|
||||
status_trace("fail_peer %"PRIu64, unique_id);
|
||||
/* This owns the peer, so we can free it */
|
||||
io_close(peer->conn);
|
||||
} else {
|
||||
status_trace("Could not fail_peer %"PRIu64", it's not local",
|
||||
unique_id);
|
||||
}
|
||||
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static void forget_peer(struct io_conn *conn, struct daemon_conn *dc)
|
||||
{
|
||||
/* Free peer. */
|
||||
tal_free(dc->ctx);
|
||||
}
|
||||
|
||||
static struct io_plan *new_peer_fd(struct io_conn *conn, struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
int fds[2];
|
||||
u8 *out;
|
||||
u64 unique_id;
|
||||
bool sync;
|
||||
struct peer *peer;
|
||||
|
||||
if (!fromwire_gossipctl_get_peer_gossipfd(msg, NULL,
|
||||
&unique_id, &sync))
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_FAIL_REQUEST,
|
||||
"%s", tal_hex(trc, msg));
|
||||
|
||||
peer = setup_new_remote_peer(daemon, unique_id, sync);
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
|
||||
status_trace("Failed to create socketpair: %s",
|
||||
strerror(errno));
|
||||
out = towire_gossipctl_get_peer_gossipfd_replyfail(msg);
|
||||
daemon_conn_send(&peer->daemon->master, take(out));
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
daemon_conn_init(peer, &peer->owner_conn, fds[0], owner_msg_in,
|
||||
forget_peer);
|
||||
peer->owner_conn.msg_queue_cleared_cb = nonlocal_dump_gossip;
|
||||
|
||||
out = towire_gossipctl_get_peer_gossipfd_reply(msg);
|
||||
daemon_conn_send(&peer->daemon->master, out);
|
||||
daemon_conn_send_fd(&peer->daemon->master, fds[1]);
|
||||
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon,
|
||||
u8 *msg)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(msg);
|
||||
struct pubkey source, destination;
|
||||
u32 msatoshi;
|
||||
u16 riskfactor;
|
||||
u8 *out;
|
||||
struct route_hop *hops;
|
||||
|
||||
fromwire_gossip_getroute_request(msg, NULL, &source, &destination,
|
||||
&msatoshi, &riskfactor);
|
||||
status_trace("Trying to find a route from %s to %s for %d msatoshi",
|
||||
pubkey_to_hexstr(tmpctx, &source),
|
||||
pubkey_to_hexstr(tmpctx, &destination), msatoshi);
|
||||
|
||||
hops = get_route(tmpctx, daemon->rstate, &source, &destination,
|
||||
msatoshi, 1);
|
||||
|
||||
out = towire_gossip_getroute_reply(msg, hops);
|
||||
tal_free(tmpctx);
|
||||
daemon_conn_send(&daemon->master, out);
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *getchannels_req(struct io_conn *conn, struct daemon *daemon,
|
||||
u8 *msg)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(daemon);
|
||||
u8 *out;
|
||||
size_t j, num_chans = 0;
|
||||
struct gossip_getchannels_entry *entries;
|
||||
struct node *n;
|
||||
struct node_map_iter i;
|
||||
|
||||
entries = tal_arr(tmpctx, struct gossip_getchannels_entry, num_chans);
|
||||
n = node_map_first(daemon->rstate->nodes, &i);
|
||||
while (n != NULL) {
|
||||
for (j=0; j<tal_count(n->out); j++){
|
||||
tal_resize(&entries, num_chans + 1);
|
||||
entries[num_chans].source = n->out[j]->src->id;
|
||||
entries[num_chans].destination = n->out[j]->dst->id;
|
||||
entries[num_chans].active = n->out[j]->active;
|
||||
entries[num_chans].delay = n->out[j]->delay;
|
||||
entries[num_chans].fee_per_kw = n->out[j]->proportional_fee;
|
||||
entries[num_chans].last_update_timestamp = n->out[j]->last_timestamp;
|
||||
entries[num_chans].flags = n->out[j]->flags;
|
||||
entries[num_chans].short_channel_id = n->out[j]->short_channel_id;
|
||||
num_chans++;
|
||||
}
|
||||
n = node_map_next(daemon->rstate->nodes, &i);
|
||||
}
|
||||
|
||||
out = towire_gossip_getchannels_reply(daemon, entries);
|
||||
daemon_conn_send(&daemon->master, take(out));
|
||||
tal_free(tmpctx);
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *getnodes(struct io_conn *conn, struct daemon *daemon)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(daemon);
|
||||
u8 *out;
|
||||
struct node *n;
|
||||
struct node_map_iter i;
|
||||
struct gossip_getnodes_entry *nodes;
|
||||
size_t node_count = 0;
|
||||
|
||||
nodes = tal_arr(tmpctx, struct gossip_getnodes_entry, node_count);
|
||||
n = node_map_first(daemon->rstate->nodes, &i);
|
||||
while (n != NULL) {
|
||||
tal_resize(&nodes, node_count + 1);
|
||||
nodes[node_count].nodeid = n->id;
|
||||
nodes[node_count].addresses = n->addresses;
|
||||
node_count++;
|
||||
n = node_map_next(daemon->rstate->nodes, &i);
|
||||
}
|
||||
out = towire_gossip_getnodes_reply(daemon, nodes);
|
||||
daemon_conn_send(&daemon->master, take(out));
|
||||
tal_free(tmpctx);
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static struct io_plan *ping_req(struct io_conn *conn, struct daemon *daemon,
|
||||
const u8 *msg)
|
||||
{
|
||||
u64 unique_id;
|
||||
u16 num_pong_bytes, len;
|
||||
struct peer *peer;
|
||||
u8 *ping;
|
||||
|
||||
if (!fromwire_gossip_ping(msg, NULL, &unique_id, &num_pong_bytes, &len))
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST,
|
||||
"%s", tal_hex(trc, msg));
|
||||
|
||||
peer = find_peer(daemon, unique_id);
|
||||
if (!peer)
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST,
|
||||
"Unknown peer %"PRIu64, unique_id);
|
||||
|
||||
ping = make_ping(peer, num_pong_bytes, len);
|
||||
if (tal_len(ping) > 65535)
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST, "Oversize ping");
|
||||
|
||||
msg_enqueue(&peer->peer_out, take(ping));
|
||||
status_trace("sending ping expecting %sresponse",
|
||||
num_pong_bytes >= 65532 ? "no " : "");
|
||||
|
||||
/* BOLT #1:
|
||||
*
|
||||
* if `num_pong_bytes` is less than 65532 it MUST respond by sending a
|
||||
* `pong` message with `byteslen` equal to `num_pong_bytes`, otherwise
|
||||
* it MUST ignore the `ping`.
|
||||
*/
|
||||
if (num_pong_bytes >= 65532)
|
||||
daemon_conn_send(&daemon->master,
|
||||
take(towire_gossip_ping_reply(peer, 0)));
|
||||
else
|
||||
peer->num_pings_outstanding++;
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
/* Parse an incoming gossip init message and assign config variables
|
||||
* to the daemon.
|
||||
*/
|
||||
static struct io_plan *gossip_init(struct daemon_conn *master,
|
||||
struct daemon *daemon, u8 *msg)
|
||||
{
|
||||
struct sha256_double chain_hash;
|
||||
|
||||
if (!fromwire_gossipctl_init(msg, NULL, &daemon->broadcast_interval,
|
||||
&chain_hash)) {
|
||||
status_failed(WIRE_GOSSIPSTATUS_INIT_FAILED,
|
||||
"Unable to parse init message");
|
||||
}
|
||||
daemon->rstate = new_routing_state(daemon, &chain_hash);
|
||||
return daemon_conn_read_next(master->conn, master);
|
||||
}
|
||||
|
||||
static struct io_plan *resolve_channel_req(struct io_conn *conn,
|
||||
struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
struct node_connection *nc;
|
||||
struct pubkey *keys;
|
||||
|
||||
if (!fromwire_gossip_resolve_channel_request(msg, NULL, &scid))
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST,
|
||||
"Unable to parse resolver request");
|
||||
|
||||
nc = get_connection_by_scid(daemon->rstate, &scid, 0);
|
||||
if (!nc) {
|
||||
status_trace("Failed to resolve channel %s",
|
||||
type_to_string(trc, struct short_channel_id, &scid));
|
||||
keys = NULL;
|
||||
} else {
|
||||
keys = tal_arr(msg, struct pubkey, 2);
|
||||
keys[0] = nc->src->id;
|
||||
keys[1] = nc->dst->id;
|
||||
status_trace("Resolved channel %s %s<->%s",
|
||||
type_to_string(trc, struct short_channel_id, &scid),
|
||||
type_to_string(trc, struct pubkey, &keys[0]),
|
||||
type_to_string(trc, struct pubkey, &keys[1]));
|
||||
}
|
||||
daemon_conn_send(&daemon->master,
|
||||
take(towire_gossip_resolve_channel_reply(msg, keys)));
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
}
|
||||
|
||||
static void handle_forwarded_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
u8 *payload;
|
||||
if (!fromwire_gossip_forwarded_msg(msg, msg, NULL, &payload)) {
|
||||
status_trace("Malformed forwarded message: %s", tal_hex(trc, msg));
|
||||
return;
|
||||
}
|
||||
handle_gossip_msg(daemon->rstate, payload);
|
||||
}
|
||||
static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master)
|
||||
{
|
||||
struct daemon *daemon = container_of(master, struct daemon, master);
|
||||
enum gossip_wire_type t = fromwire_peektype(master->msg_in);
|
||||
|
||||
status_trace("req: type %s len %zu",
|
||||
gossip_wire_type_name(t), tal_count(master->msg_in));
|
||||
|
||||
switch (t) {
|
||||
case WIRE_GOSSIPCTL_INIT:
|
||||
return gossip_init(master, daemon, master->msg_in);
|
||||
|
||||
case WIRE_GOSSIPCTL_NEW_PEER:
|
||||
return new_peer(conn, daemon, master->msg_in);
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER:
|
||||
return release_peer(conn, daemon, master->msg_in);
|
||||
case WIRE_GOSSIPCTL_FAIL_PEER:
|
||||
return fail_peer(conn, daemon, master->msg_in);
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD:
|
||||
return new_peer_fd(conn, daemon, master->msg_in);
|
||||
|
||||
case WIRE_GOSSIP_GETNODES_REQUEST:
|
||||
return getnodes(conn, daemon);
|
||||
|
||||
case WIRE_GOSSIP_GETROUTE_REQUEST:
|
||||
return getroute_req(conn, daemon, daemon->master.msg_in);
|
||||
|
||||
case WIRE_GOSSIP_GETCHANNELS_REQUEST:
|
||||
return getchannels_req(conn, daemon, daemon->master.msg_in);
|
||||
|
||||
case WIRE_GOSSIP_PING:
|
||||
return ping_req(conn, daemon, daemon->master.msg_in);
|
||||
|
||||
case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST:
|
||||
return resolve_channel_req(conn, daemon, daemon->master.msg_in);
|
||||
|
||||
case WIRE_GOSSIP_FORWARDED_MSG:
|
||||
handle_forwarded_msg(conn, daemon, daemon->master.msg_in);
|
||||
return daemon_conn_read_next(conn, &daemon->master);
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
|
||||
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL:
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLY:
|
||||
case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLYFAIL:
|
||||
case WIRE_GOSSIP_GETNODES_REPLY:
|
||||
case WIRE_GOSSIP_GETROUTE_REPLY:
|
||||
case WIRE_GOSSIP_GETCHANNELS_REPLY:
|
||||
case WIRE_GOSSIP_PING_REPLY:
|
||||
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY:
|
||||
case WIRE_GOSSIPSTATUS_INIT_FAILED:
|
||||
case WIRE_GOSSIPSTATUS_BAD_NEW_PEER_REQUEST:
|
||||
case WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST:
|
||||
case WIRE_GOSSIPSTATUS_BAD_FAIL_REQUEST:
|
||||
case WIRE_GOSSIPSTATUS_BAD_REQUEST:
|
||||
case WIRE_GOSSIPSTATUS_FDPASS_FAILED:
|
||||
case WIRE_GOSSIPSTATUS_PEER_BAD_MSG:
|
||||
case WIRE_GOSSIPSTATUS_PEER_FAILED:
|
||||
case WIRE_GOSSIPSTATUS_PEER_NONGOSSIP:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Control shouldn't give bad requests. */
|
||||
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST, "%i", t);
|
||||
}
|
||||
|
||||
#ifndef TESTING
|
||||
static void master_gone(struct io_conn *unused, struct daemon_conn *dc)
|
||||
{
|
||||
/* Can't tell master, it's gone. */
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct daemon *daemon;
|
||||
|
||||
subdaemon_debug(argc, argv);
|
||||
|
||||
if (argc == 2 && streq(argv[1], "--version")) {
|
||||
printf("%s\n", version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
|
||||
SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
daemon = tal(NULL, struct daemon);
|
||||
list_head_init(&daemon->peers);
|
||||
timers_init(&daemon->timers, time_mono());
|
||||
daemon->broadcast_interval = 30000;
|
||||
|
||||
/* stdin == control */
|
||||
daemon_conn_init(daemon, &daemon->master, STDIN_FILENO, recv_req,
|
||||
master_gone);
|
||||
status_setup_async(&daemon->master);
|
||||
|
||||
/* When conn closes, everything is freed. */
|
||||
tal_steal(daemon->master.conn, daemon);
|
||||
|
||||
for (;;) {
|
||||
struct timer *expired = NULL;
|
||||
io_loop(&daemon->timers, &expired);
|
||||
|
||||
if (!expired) {
|
||||
break;
|
||||
} else {
|
||||
timer_expired(daemon, expired);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
# These are fatal.
|
||||
gossipstatus_init_failed,0x8000
|
||||
gossipstatus_bad_new_peer_request,0x8001
|
||||
gossipstatus_bad_release_request,0x8002
|
||||
gossipstatus_bad_fail_request,0x8003
|
||||
gossipstatus_bad_request,0x8004
|
||||
gossipstatus_fdpass_failed,0x8005
|
||||
|
||||
# Peers can give a bad message, we close their fd, but no harm done.
|
||||
gossipstatus_peer_bad_msg,1000
|
||||
gossipstatus_peer_bad_msg,,unique_id,8
|
||||
gossipstatus_peer_bad_msg,,len,2
|
||||
gossipstatus_peer_bad_msg,,err,len*u8
|
||||
|
||||
# Misc problems like opening control fd.
|
||||
gossipstatus_peer_failed,1001
|
||||
gossipstatus_peer_failed,,unique_id,8
|
||||
gossipstatus_peer_failed,,len,2
|
||||
gossipstatus_peer_failed,,err,len*u8
|
||||
|
||||
#include <common/cryptomsg.h>
|
||||
|
||||
# Initialize the gossip daemon
|
||||
gossipctl_init,0
|
||||
gossipctl_init,,broadcast_interval,4
|
||||
gossipctl_init,,chain_hash,struct sha256_double
|
||||
|
||||
# These take an fd, but have no response
|
||||
# (if it is to move onto a channel, we get a status msg).
|
||||
gossipctl_new_peer,1
|
||||
gossipctl_new_peer,,unique_id,8
|
||||
gossipctl_new_peer,,crypto_state,struct crypto_state
|
||||
|
||||
# Tell it to release a peer which has initialized.
|
||||
gossipctl_release_peer,2
|
||||
gossipctl_release_peer,,unique_id,8
|
||||
|
||||
# This releases the peer and returns the cryptostate (followed two fds: peer and gossip)
|
||||
gossipctl_release_peer_reply,102
|
||||
gossipctl_release_peer_reply,,crypto_state,struct crypto_state
|
||||
|
||||
# This is if we couldn't find the peer.
|
||||
gossipctl_release_peer_replyfail,202
|
||||
|
||||
# This is where we save a peer's features.
|
||||
#gossipstatus_peer_features,1
|
||||
#gossipstatus_peer_features,,unique_id,8
|
||||
#gossipstatus_peer_features,,gflen,2
|
||||
#gossipstatus_peer_features,,globalfeatures,gflen
|
||||
#gossipstatus_peer_features,,lflen,2
|
||||
#gossipstatus_peer_features,,localfeatures,lflen
|
||||
|
||||
# Peer can send non-gossip packet (usually an open_channel) (followed two fds: peer and gossip)
|
||||
gossipstatus_peer_nongossip,4
|
||||
gossipstatus_peer_nongossip,,unique_id,8
|
||||
gossipstatus_peer_nongossip,,crypto_state,struct crypto_state
|
||||
gossipstatus_peer_nongossip,,len,2
|
||||
gossipstatus_peer_nongossip,,msg,len*u8
|
||||
|
||||
# Pass JSON-RPC getnodes call through
|
||||
gossip_getnodes_request,5
|
||||
|
||||
#include <lightningd/gossip_msg.h>
|
||||
gossip_getnodes_reply,105
|
||||
gossip_getnodes_reply,,num_nodes,u16
|
||||
gossip_getnodes_reply,,nodes,num_nodes*struct gossip_getnodes_entry
|
||||
|
||||
# Pass JSON-RPC getroute call through
|
||||
gossip_getroute_request,6
|
||||
gossip_getroute_request,,source,struct pubkey
|
||||
gossip_getroute_request,,destination,struct pubkey
|
||||
gossip_getroute_request,,msatoshi,u32
|
||||
gossip_getroute_request,,riskfactor,u16
|
||||
|
||||
gossip_getroute_reply,106
|
||||
gossip_getroute_reply,,num_hops,u16
|
||||
gossip_getroute_reply,,hops,num_hops*struct route_hop
|
||||
|
||||
gossip_getchannels_request,7
|
||||
|
||||
gossip_getchannels_reply,107
|
||||
gossip_getchannels_reply,,num_channels,u16
|
||||
gossip_getchannels_reply,,nodes,num_channels*struct gossip_getchannels_entry
|
||||
|
||||
# Ping/pong test.
|
||||
gossip_ping,8
|
||||
gossip_ping,,unique_id,u64
|
||||
gossip_ping,,num_pong_bytes,u16
|
||||
gossip_ping,,len,u16
|
||||
|
||||
gossip_ping_reply,108
|
||||
gossip_ping_reply,,totlen,u16
|
||||
|
||||
# Given a short_channel_id, return the endpoints
|
||||
gossip_resolve_channel_request,9
|
||||
gossip_resolve_channel_request,,channel_id,struct short_channel_id
|
||||
|
||||
gossip_resolve_channel_reply,109
|
||||
gossip_resolve_channel_reply,,num_keys,u16
|
||||
gossip_resolve_channel_reply,,keys,num_keys*struct pubkey
|
||||
|
||||
# The main daemon forward some gossip message to gossipd, allows injecting
|
||||
# arbitrary gossip messages.
|
||||
gossip_forwarded_msg,10
|
||||
gossip_forwarded_msg,,msglen,2
|
||||
gossip_forwarded_msg,,msg,msglen
|
||||
|
||||
# If peer is still connected, fail it (master does this for reconnect)
|
||||
gossipctl_fail_peer,11
|
||||
gossipctl_fail_peer,,unique_id,8
|
||||
|
||||
# Get a gossip fd for this peer (it has reconnected)
|
||||
gossipctl_get_peer_gossipfd,12
|
||||
gossipctl_get_peer_gossipfd,,unique_id,u64
|
||||
# Does it want a full dump of gossip?
|
||||
gossipctl_get_peer_gossipfd,,sync,bool
|
||||
|
||||
# + fd.
|
||||
gossipctl_get_peer_gossipfd_reply,112
|
||||
|
||||
# Failure (can't make new socket)
|
||||
gossipctl_get_peer_gossipfd_replyfail,212
|
||||
|
@@ -1,929 +0,0 @@
|
||||
#include "routing.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <bitcoin/block.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/crypto/siphash24/siphash24.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/overflows.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <inttypes.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
|
||||
/* 365.25 * 24 * 60 / 10 */
|
||||
#define BLOCKS_PER_YEAR 52596
|
||||
|
||||
struct routing_state *new_routing_state(const tal_t *ctx,
|
||||
const struct sha256_double *chain_hash)
|
||||
{
|
||||
struct routing_state *rstate = tal(ctx, struct routing_state);
|
||||
rstate->nodes = empty_node_map(rstate);
|
||||
rstate->broadcasts = new_broadcast_state(rstate);
|
||||
rstate->chain_hash = *chain_hash;
|
||||
return rstate;
|
||||
}
|
||||
|
||||
|
||||
const secp256k1_pubkey *node_map_keyof_node(const struct node *n)
|
||||
{
|
||||
return &n->id.pubkey;
|
||||
}
|
||||
|
||||
size_t node_map_hash_key(const secp256k1_pubkey *key)
|
||||
{
|
||||
return siphash24(siphash_seed(), key, sizeof(*key));
|
||||
}
|
||||
|
||||
bool node_map_node_eq(const struct node *n, const secp256k1_pubkey *key)
|
||||
{
|
||||
return structeq(&n->id.pubkey, key);
|
||||
}
|
||||
|
||||
struct node_map *empty_node_map(const tal_t *ctx)
|
||||
{
|
||||
struct node_map *map = tal(ctx, struct node_map);
|
||||
node_map_init(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
struct node *get_node(struct routing_state *rstate,
|
||||
const struct pubkey *id)
|
||||
{
|
||||
return node_map_get(rstate->nodes, &id->pubkey);
|
||||
}
|
||||
|
||||
static void destroy_node(struct node *node)
|
||||
{
|
||||
/* These remove themselves from the array. */
|
||||
while (tal_count(node->in))
|
||||
tal_free(node->in[0]);
|
||||
while (tal_count(node->out))
|
||||
tal_free(node->out[0]);
|
||||
}
|
||||
|
||||
struct node *new_node(struct routing_state *rstate,
|
||||
const struct pubkey *id)
|
||||
{
|
||||
struct node *n;
|
||||
|
||||
assert(!get_node(rstate, id));
|
||||
|
||||
n = tal(rstate, struct node);
|
||||
n->id = *id;
|
||||
n->in = tal_arr(n, struct node_connection *, 0);
|
||||
n->out = tal_arr(n, struct node_connection *, 0);
|
||||
n->alias = NULL;
|
||||
n->node_announcement = NULL;
|
||||
n->last_timestamp = 0;
|
||||
n->addresses = tal_arr(n, struct ipaddr, 0);
|
||||
node_map_add(rstate->nodes, n);
|
||||
tal_add_destructor(n, destroy_node);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
struct node *add_node(
|
||||
struct routing_state *rstate,
|
||||
const struct pubkey *pk)
|
||||
{
|
||||
struct node *n = get_node(rstate, pk);
|
||||
if (!n) {
|
||||
n = new_node(rstate, pk);
|
||||
status_trace("Creating new node %s",
|
||||
type_to_string(trc, struct pubkey, pk));
|
||||
} else {
|
||||
status_trace("Update existing node %s",
|
||||
type_to_string(trc, struct pubkey, pk));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool remove_conn_from_array(struct node_connection ***conns,
|
||||
struct node_connection *nc)
|
||||
{
|
||||
size_t i, n;
|
||||
|
||||
n = tal_count(*conns);
|
||||
for (i = 0; i < n; i++) {
|
||||
if ((*conns)[i] != nc)
|
||||
continue;
|
||||
n--;
|
||||
memmove(*conns + i, *conns + i + 1, sizeof(**conns) * (n - i));
|
||||
tal_resize(conns, n);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void destroy_connection(struct node_connection *nc)
|
||||
{
|
||||
if (!remove_conn_from_array(&nc->dst->in, nc)
|
||||
|| !remove_conn_from_array(&nc->src->out, nc))
|
||||
/* FIXME! */
|
||||
abort();
|
||||
}
|
||||
|
||||
struct node_connection * get_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from_id,
|
||||
const struct pubkey *to_id)
|
||||
{
|
||||
int i, n;
|
||||
struct node *from, *to;
|
||||
from = get_node(rstate, from_id);
|
||||
to = get_node(rstate, to_id);
|
||||
if (!from || ! to)
|
||||
return NULL;
|
||||
|
||||
n = tal_count(to->in);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (to->in[i]->src == from)
|
||||
return to->in[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct node_connection *get_connection_by_scid(const struct routing_state *rstate,
|
||||
const struct short_channel_id *schanid,
|
||||
const u8 direction)
|
||||
{
|
||||
struct node *n;
|
||||
int i, num_conn;
|
||||
struct node_map *nodes = rstate->nodes;
|
||||
struct node_connection *c;
|
||||
struct node_map_iter it;
|
||||
|
||||
//FIXME(cdecker) We probably want to speed this up by indexing by chanid.
|
||||
for (n = node_map_first(nodes, &it); n; n = node_map_next(nodes, &it)) {
|
||||
num_conn = tal_count(n->out);
|
||||
for (i = 0; i < num_conn; i++){
|
||||
c = n->out[i];
|
||||
if (short_channel_id_eq(&c->short_channel_id, schanid) &&
|
||||
(c->flags&0x1) == direction)
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct node_connection *
|
||||
get_or_make_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from_id,
|
||||
const struct pubkey *to_id)
|
||||
{
|
||||
size_t i, n;
|
||||
struct node *from, *to;
|
||||
struct node_connection *nc;
|
||||
|
||||
from = get_node(rstate, from_id);
|
||||
if (!from)
|
||||
from = new_node(rstate, from_id);
|
||||
to = get_node(rstate, to_id);
|
||||
if (!to)
|
||||
to = new_node(rstate, to_id);
|
||||
|
||||
n = tal_count(to->in);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (to->in[i]->src == from) {
|
||||
status_trace("Updating existing route from %s to %s",
|
||||
type_to_string(trc, struct pubkey,
|
||||
&from->id),
|
||||
type_to_string(trc, struct pubkey,
|
||||
&to->id));
|
||||
return to->in[i];
|
||||
}
|
||||
}
|
||||
|
||||
status_trace("Creating new route from %s to %s",
|
||||
type_to_string(trc, struct pubkey, &from->id),
|
||||
type_to_string(trc, struct pubkey, &to->id));
|
||||
|
||||
nc = tal(rstate, struct node_connection);
|
||||
nc->src = from;
|
||||
nc->dst = to;
|
||||
nc->channel_announcement = NULL;
|
||||
nc->channel_update = NULL;
|
||||
|
||||
/* Hook it into in/out arrays. */
|
||||
i = tal_count(to->in);
|
||||
tal_resize(&to->in, i+1);
|
||||
to->in[i] = nc;
|
||||
i = tal_count(from->out);
|
||||
tal_resize(&from->out, i+1);
|
||||
from->out[i] = nc;
|
||||
|
||||
tal_add_destructor(nc, destroy_connection);
|
||||
return nc;
|
||||
}
|
||||
|
||||
struct node_connection *half_add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
const struct short_channel_id *schanid,
|
||||
const u16 flags
|
||||
)
|
||||
{
|
||||
struct node_connection *nc;
|
||||
nc = get_or_make_connection(rstate, from, to);
|
||||
nc->short_channel_id = *schanid;
|
||||
nc->active = false;
|
||||
nc->last_timestamp = 0;
|
||||
nc->flags = flags;
|
||||
nc->min_blocks = 0;
|
||||
nc->proportional_fee = 0;
|
||||
nc->base_fee = 0;
|
||||
nc->delay = 0;
|
||||
return nc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Updates existing route if required. */
|
||||
struct node_connection *add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
u32 base_fee, s32 proportional_fee,
|
||||
u32 delay, u32 min_blocks)
|
||||
{
|
||||
struct node_connection *c = get_or_make_connection(rstate, from, to);
|
||||
c->base_fee = base_fee;
|
||||
c->proportional_fee = proportional_fee;
|
||||
c->delay = delay;
|
||||
c->min_blocks = min_blocks;
|
||||
c->active = true;
|
||||
c->last_timestamp = 0;
|
||||
memset(&c->short_channel_id, 0, sizeof(c->short_channel_id));
|
||||
c->flags = get_channel_direction(from, to);
|
||||
return c;
|
||||
}
|
||||
|
||||
void remove_connection(struct routing_state *rstate,
|
||||
const struct pubkey *src, const struct pubkey *dst)
|
||||
{
|
||||
struct node *from, *to;
|
||||
size_t i, num_edges;
|
||||
|
||||
status_trace("Removing route from %s to %s",
|
||||
type_to_string(trc, struct pubkey, src),
|
||||
type_to_string(trc, struct pubkey, dst));
|
||||
|
||||
from = get_node(rstate, src);
|
||||
to = get_node(rstate, dst);
|
||||
if (!from || !to) {
|
||||
status_trace("Not found: src=%p dst=%p", from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
num_edges = tal_count(from->out);
|
||||
|
||||
for (i = 0; i < num_edges; i++) {
|
||||
if (from->out[i]->dst != to)
|
||||
continue;
|
||||
|
||||
status_trace("Matched route %zu of %zu", i, num_edges);
|
||||
/* Destructor makes it delete itself */
|
||||
tal_free(from->out[i]);
|
||||
return;
|
||||
}
|
||||
status_trace(" None of %zu routes matched", num_edges);
|
||||
}
|
||||
|
||||
/* Too big to reach, but don't overflow if added. */
|
||||
#define INFINITE 0x3FFFFFFFFFFFFFFFULL
|
||||
|
||||
static void clear_bfg(struct node_map *nodes)
|
||||
{
|
||||
struct node *n;
|
||||
struct node_map_iter it;
|
||||
|
||||
for (n = node_map_first(nodes, &it); n; n = node_map_next(nodes, &it)) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(n->bfg); i++) {
|
||||
n->bfg[i].total = INFINITE;
|
||||
n->bfg[i].risk = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s64 connection_fee(const struct node_connection *c, u64 msatoshi)
|
||||
{
|
||||
s64 fee;
|
||||
|
||||
if (mul_overflows_s64(c->proportional_fee, msatoshi))
|
||||
return INFINITE;
|
||||
fee = (c->proportional_fee * msatoshi) / 1000000;
|
||||
/* This can't overflow: c->base_fee is a u32 */
|
||||
return c->base_fee + fee;
|
||||
}
|
||||
|
||||
/* Risk of passing through this channel. We insert a tiny constant here
|
||||
* in order to prefer shorter routes, all things equal. */
|
||||
static u64 risk_fee(s64 amount, u32 delay, double riskfactor)
|
||||
{
|
||||
/* If fees are so negative we're making money, ignore risk. */
|
||||
if (amount < 0)
|
||||
return 1;
|
||||
|
||||
return 1 + amount * delay * riskfactor / BLOCKS_PER_YEAR / 10000;
|
||||
}
|
||||
|
||||
/* We track totals, rather than costs. That's because the fee depends
|
||||
* on the current amount passing through. */
|
||||
static void bfg_one_edge(struct node *node, size_t edgenum, double riskfactor)
|
||||
{
|
||||
struct node_connection *c = node->in[edgenum];
|
||||
size_t h;
|
||||
|
||||
assert(c->dst == node);
|
||||
for (h = 0; h < ROUTING_MAX_HOPS; h++) {
|
||||
/* FIXME: Bias against smaller channels. */
|
||||
s64 fee = connection_fee(c, node->bfg[h].total);
|
||||
u64 risk = node->bfg[h].risk + risk_fee(node->bfg[h].total + fee,
|
||||
c->delay, riskfactor);
|
||||
if (node->bfg[h].total + (s64)fee + (s64)risk
|
||||
< c->src->bfg[h+1].total + (s64)c->src->bfg[h+1].risk) {
|
||||
c->src->bfg[h+1].total = node->bfg[h].total + fee;
|
||||
c->src->bfg[h+1].risk = risk;
|
||||
c->src->bfg[h+1].prev = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct node_connection *
|
||||
find_route(const tal_t *ctx, struct routing_state *rstate,
|
||||
const struct pubkey *from, const struct pubkey *to, u64 msatoshi,
|
||||
double riskfactor, s64 *fee, struct node_connection ***route)
|
||||
{
|
||||
struct node *n, *src, *dst;
|
||||
struct node_map_iter it;
|
||||
struct node_connection *first_conn;
|
||||
int runs, i, best;
|
||||
|
||||
/* Note: we map backwards, since we know the amount of satoshi we want
|
||||
* at the end, and need to derive how much we need to send. */
|
||||
dst = get_node(rstate, from);
|
||||
src = get_node(rstate, to);
|
||||
|
||||
if (!src) {
|
||||
status_trace("find_route: cannot find %s",
|
||||
type_to_string(trc, struct pubkey, to));
|
||||
return NULL;
|
||||
} else if (!dst) {
|
||||
status_trace("find_route: cannot find myself (%s)",
|
||||
type_to_string(trc, struct pubkey, to));
|
||||
return NULL;
|
||||
} else if (dst == src) {
|
||||
status_trace("find_route: this is %s, refusing to create empty route",
|
||||
type_to_string(trc, struct pubkey, to));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reset all the information. */
|
||||
clear_bfg(rstate->nodes);
|
||||
|
||||
/* Bellman-Ford-Gibson: like Bellman-Ford, but keep values for
|
||||
* every path length. */
|
||||
src->bfg[0].total = msatoshi;
|
||||
src->bfg[0].risk = 0;
|
||||
|
||||
for (runs = 0; runs < ROUTING_MAX_HOPS; runs++) {
|
||||
status_trace("Run %i", runs);
|
||||
/* Run through every edge. */
|
||||
for (n = node_map_first(rstate->nodes, &it);
|
||||
n;
|
||||
n = node_map_next(rstate->nodes, &it)) {
|
||||
size_t num_edges = tal_count(n->in);
|
||||
for (i = 0; i < num_edges; i++) {
|
||||
if (!n->in[i]->active)
|
||||
continue;
|
||||
bfg_one_edge(n, i, riskfactor);
|
||||
status_trace("We seek %p->%p, this is %p -> %p",
|
||||
dst, src,
|
||||
n->in[i]->src, n->in[i]->dst);
|
||||
status_trace("Checking from %s to %s",
|
||||
type_to_string(trc,
|
||||
struct pubkey,
|
||||
&n->in[i]->src->id),
|
||||
type_to_string(trc,
|
||||
struct pubkey,
|
||||
&n->in[i]->dst->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best = 0;
|
||||
for (i = 1; i <= ROUTING_MAX_HOPS; i++) {
|
||||
if (dst->bfg[i].total < dst->bfg[best].total)
|
||||
best = i;
|
||||
}
|
||||
|
||||
/* No route? */
|
||||
if (dst->bfg[best].total >= INFINITE) {
|
||||
status_trace("find_route: No route to %s",
|
||||
type_to_string(trc, struct pubkey, to));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save route from *next* hop (we return first hop as peer).
|
||||
* Note that we take our own fees into account for routing, even
|
||||
* though we don't pay them: it presumably effects preference. */
|
||||
first_conn = dst->bfg[best].prev;
|
||||
dst = dst->bfg[best].prev->dst;
|
||||
best--;
|
||||
|
||||
*fee = dst->bfg[best].total - msatoshi;
|
||||
*route = tal_arr(ctx, struct node_connection *, best);
|
||||
for (i = 0, n = dst;
|
||||
i < best;
|
||||
n = n->bfg[best-i].prev->dst, i++) {
|
||||
(*route)[i] = n->bfg[best-i].prev;
|
||||
}
|
||||
assert(n == src);
|
||||
|
||||
msatoshi += *fee;
|
||||
status_trace("find_route: via %s",
|
||||
type_to_string(trc, struct pubkey, &first_conn->dst->id));
|
||||
/* If there are intermidiaries, dump them, and total fees. */
|
||||
if (best != 0) {
|
||||
for (i = 0; i < best; i++) {
|
||||
status_trace(" %s (%i+%i=%"PRIu64")",
|
||||
type_to_string(trc, struct pubkey,
|
||||
&(*route)[i]->dst->id),
|
||||
(*route)[i]->base_fee,
|
||||
(*route)[i]->proportional_fee,
|
||||
connection_fee((*route)[i], msatoshi));
|
||||
msatoshi -= connection_fee((*route)[i], msatoshi);
|
||||
}
|
||||
status_trace(" =%"PRIi64"(%+"PRIi64")",
|
||||
(*route)[best-1]->dst->bfg[best-1].total, *fee);
|
||||
}
|
||||
return first_conn;
|
||||
}
|
||||
|
||||
bool add_channel_direction(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
const struct short_channel_id *short_channel_id,
|
||||
const u8 *announcement)
|
||||
{
|
||||
struct node_connection *c = get_connection(rstate, from, to);
|
||||
u16 direction = get_channel_direction(from, to);
|
||||
if (c){
|
||||
/* Do not clobber connections added otherwise */
|
||||
memcpy(&c->short_channel_id, short_channel_id,
|
||||
sizeof(c->short_channel_id));
|
||||
c->flags = direction;
|
||||
return false;
|
||||
}else if(get_connection_by_scid(rstate, short_channel_id, direction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
c = half_add_connection(rstate, from, to, short_channel_id, direction);
|
||||
|
||||
/* Remember the announcement so we can forward it to new peers */
|
||||
tal_free(c->channel_announcement);
|
||||
c->channel_announcement = tal_dup_arr(c, u8, announcement,
|
||||
tal_count(announcement), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The following `address descriptor` types are defined:
|
||||
*
|
||||
* * `0`: padding. data = none (length 0).
|
||||
* * `1`: ipv4. data = `[4:ipv4_addr][2:port]` (length 6)
|
||||
* * `2`: ipv6. data = `[16:ipv6_addr][2:port]` (length 18)
|
||||
*/
|
||||
|
||||
/* FIXME: Don't just take first one, depends whether we have IPv6 ourselves */
|
||||
/* Returns false iff it was malformed */
|
||||
bool read_ip(const tal_t *ctx, const u8 *addresses, char **hostname,
|
||||
int *port)
|
||||
{
|
||||
size_t len = tal_count(addresses);
|
||||
const u8 *p = addresses;
|
||||
char tempaddr[INET6_ADDRSTRLEN];
|
||||
be16 portnum;
|
||||
|
||||
*hostname = NULL;
|
||||
while (len) {
|
||||
u8 type = *p;
|
||||
p++;
|
||||
len--;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The receiving node SHOULD fail the connection if
|
||||
* `addrlen` is insufficient to hold the address
|
||||
* descriptors of the known types.
|
||||
*/
|
||||
if (len < 6)
|
||||
return false;
|
||||
inet_ntop(AF_INET, p, tempaddr, sizeof(tempaddr));
|
||||
memcpy(&portnum, p + 4, sizeof(portnum));
|
||||
*hostname = tal_strdup(ctx, tempaddr);
|
||||
*port = be16_to_cpu(portnum);
|
||||
return true;
|
||||
case 2:
|
||||
if (len < 18)
|
||||
return false;
|
||||
inet_ntop(AF_INET6, p, tempaddr, sizeof(tempaddr));
|
||||
memcpy(&portnum, p + 16, sizeof(portnum));
|
||||
*hostname = tal_strdup(ctx, tempaddr);
|
||||
*port = be16_to_cpu(portnum);
|
||||
return true;
|
||||
default:
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The receiving node SHOULD ignore the first `address
|
||||
* descriptor` which does not match the types defined
|
||||
* above.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not a fatal error. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The creating node SHOULD fill `addresses` with an address descriptor for
|
||||
* each public network address which expects incoming connections, and MUST
|
||||
* set `addrlen` to the number of bytes in `addresses`. Non-zero typed
|
||||
* address descriptors MUST be placed in ascending order; any number of
|
||||
* zero-typed address descriptors MAY be placed anywhere, but SHOULD only be
|
||||
* used for aligning fields following `addresses`.
|
||||
*
|
||||
* The creating node MUST NOT create a type 1 or type 2 address descriptor
|
||||
* with `port` equal to zero, and SHOULD ensure `ipv4_addr` and `ipv6_addr`
|
||||
* are routable addresses. The creating node MUST NOT include more than one
|
||||
* `address descriptor` of the same type.
|
||||
*/
|
||||
/* FIXME: handle case where we have both ipv6 and ipv4 addresses! */
|
||||
u8 *write_ip(const tal_t *ctx, const char *srcip, int port)
|
||||
{
|
||||
u8 *address;
|
||||
be16 portnum = cpu_to_be16(port);
|
||||
|
||||
if (!port)
|
||||
return tal_arr(ctx, u8, 0);
|
||||
|
||||
if (!strchr(srcip, ':')) {
|
||||
address = tal_arr(ctx, u8, 7);
|
||||
address[0] = 1;
|
||||
inet_pton(AF_INET, srcip, address+1);
|
||||
memcpy(address + 5, &portnum, sizeof(portnum));
|
||||
return address;
|
||||
} else {
|
||||
address = tal_arr(ctx, u8, 18);
|
||||
address[0] = 2;
|
||||
inet_pton(AF_INET6, srcip, address+1);
|
||||
memcpy(address + 17, &portnum, sizeof(portnum));
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify the signature of a channel_update message */
|
||||
static bool check_channel_update(const struct pubkey *node_key,
|
||||
const secp256k1_ecdsa_signature *node_sig,
|
||||
const u8 *update)
|
||||
{
|
||||
/* 2 byte msg type + 64 byte signatures */
|
||||
int offset = 66;
|
||||
struct sha256_double hash;
|
||||
sha256_double(&hash, update + offset, tal_len(update) - offset);
|
||||
|
||||
return check_signed_hash(&hash, node_sig, node_key);
|
||||
}
|
||||
|
||||
static bool check_channel_announcement(
|
||||
const struct pubkey *node1_key, const struct pubkey *node2_key,
|
||||
const struct pubkey *bitcoin1_key, const struct pubkey *bitcoin2_key,
|
||||
const secp256k1_ecdsa_signature *node1_sig,
|
||||
const secp256k1_ecdsa_signature *node2_sig,
|
||||
const secp256k1_ecdsa_signature *bitcoin1_sig,
|
||||
const secp256k1_ecdsa_signature *bitcoin2_sig, const u8 *announcement)
|
||||
{
|
||||
/* 2 byte msg type + 256 byte signatures */
|
||||
int offset = 258;
|
||||
struct sha256_double hash;
|
||||
sha256_double(&hash, announcement + offset,
|
||||
tal_len(announcement) - offset);
|
||||
|
||||
return check_signed_hash(&hash, node1_sig, node1_key) &&
|
||||
check_signed_hash(&hash, node2_sig, node2_key) &&
|
||||
check_signed_hash(&hash, bitcoin1_sig, bitcoin1_key) &&
|
||||
check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key);
|
||||
}
|
||||
|
||||
void handle_channel_announcement(
|
||||
struct routing_state *rstate,
|
||||
const u8 *announce, size_t len)
|
||||
{
|
||||
u8 *serialized;
|
||||
bool forward = false;
|
||||
secp256k1_ecdsa_signature node_signature_1;
|
||||
secp256k1_ecdsa_signature node_signature_2;
|
||||
struct short_channel_id short_channel_id;
|
||||
secp256k1_ecdsa_signature bitcoin_signature_1;
|
||||
secp256k1_ecdsa_signature bitcoin_signature_2;
|
||||
struct pubkey node_id_1;
|
||||
struct pubkey node_id_2;
|
||||
struct pubkey bitcoin_key_1;
|
||||
struct pubkey bitcoin_key_2;
|
||||
struct sha256_double chain_hash;
|
||||
const tal_t *tmpctx = tal_tmpctx(rstate);
|
||||
u8 *features;
|
||||
|
||||
serialized = tal_dup_arr(tmpctx, u8, announce, len, 0);
|
||||
if (!fromwire_channel_announcement(tmpctx, serialized, NULL,
|
||||
&node_signature_1, &node_signature_2,
|
||||
&bitcoin_signature_1,
|
||||
&bitcoin_signature_2,
|
||||
&features,
|
||||
&chain_hash,
|
||||
&short_channel_id,
|
||||
&node_id_1, &node_id_2,
|
||||
&bitcoin_key_1, &bitcoin_key_2)) {
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The receiving node MUST ignore the message if the specified
|
||||
* `chain_hash` is unknown to the receiver.
|
||||
*/
|
||||
if (!structeq(&chain_hash, &rstate->chain_hash)) {
|
||||
status_trace("Received channel_announcement for unknown chain"
|
||||
" %s",
|
||||
type_to_string(tmpctx, struct sha256_double,
|
||||
&chain_hash));
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Check features!
|
||||
//FIXME(cdecker) Check chain topology for the anchor TX
|
||||
|
||||
status_trace("Received channel_announcement for channel %s",
|
||||
type_to_string(trc, struct short_channel_id,
|
||||
&short_channel_id));
|
||||
|
||||
if (!check_channel_announcement(&node_id_1, &node_id_2, &bitcoin_key_1,
|
||||
&bitcoin_key_2, &node_signature_1,
|
||||
&node_signature_2, &bitcoin_signature_1,
|
||||
&bitcoin_signature_2, serialized)) {
|
||||
status_trace(
|
||||
"Signature verification of channel announcement failed");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
forward |= add_channel_direction(rstate, &node_id_1, &node_id_2,
|
||||
&short_channel_id, serialized);
|
||||
forward |= add_channel_direction(rstate, &node_id_2, &node_id_1,
|
||||
&short_channel_id, serialized);
|
||||
if (!forward) {
|
||||
status_trace("Not forwarding channel_announcement");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *tag = tal_arr(tmpctx, u8, 0);
|
||||
towire_short_channel_id(&tag, &short_channel_id);
|
||||
queue_broadcast(rstate->broadcasts, WIRE_CHANNEL_ANNOUNCEMENT,
|
||||
tag, serialized);
|
||||
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
void handle_channel_update(struct routing_state *rstate, const u8 *update, size_t len)
|
||||
{
|
||||
u8 *serialized;
|
||||
struct node_connection *c;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
struct short_channel_id short_channel_id;
|
||||
u32 timestamp;
|
||||
u16 flags;
|
||||
u16 expiry;
|
||||
u64 htlc_minimum_msat;
|
||||
u32 fee_base_msat;
|
||||
u32 fee_proportional_millionths;
|
||||
const tal_t *tmpctx = tal_tmpctx(rstate);
|
||||
struct sha256_double chain_hash;
|
||||
|
||||
serialized = tal_dup_arr(tmpctx, u8, update, len, 0);
|
||||
if (!fromwire_channel_update(serialized, NULL, &signature,
|
||||
&chain_hash, &short_channel_id,
|
||||
×tamp, &flags, &expiry,
|
||||
&htlc_minimum_msat, &fee_base_msat,
|
||||
&fee_proportional_millionths)) {
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The receiving node MUST ignore the channel update if the specified
|
||||
* `chain_hash` value is unknown, meaning it isn't active on the
|
||||
* specified chain. */
|
||||
if (!structeq(&chain_hash, &rstate->chain_hash)) {
|
||||
status_trace("Received channel_update for unknown chain %s",
|
||||
type_to_string(tmpctx, struct sha256_double,
|
||||
&chain_hash));
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
status_trace("Received channel_update for channel %s(%d)",
|
||||
type_to_string(trc, struct short_channel_id,
|
||||
&short_channel_id),
|
||||
flags & 0x01);
|
||||
|
||||
c = get_connection_by_scid(rstate, &short_channel_id, flags & 0x1);
|
||||
|
||||
if (!c) {
|
||||
status_trace("Ignoring update for unknown channel %s",
|
||||
type_to_string(trc, struct short_channel_id,
|
||||
&short_channel_id));
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
} else if (c->last_timestamp >= timestamp) {
|
||||
status_trace("Ignoring outdated update.");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
} else if (!check_channel_update(&c->src->id, &signature, serialized)) {
|
||||
status_trace("Signature verification failed.");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
//FIXME(cdecker) Check signatures
|
||||
c->last_timestamp = timestamp;
|
||||
c->delay = expiry;
|
||||
c->htlc_minimum_msat = htlc_minimum_msat;
|
||||
c->base_fee = fee_base_msat;
|
||||
c->proportional_fee = fee_proportional_millionths;
|
||||
c->active = (flags & ROUTING_FLAGS_DISABLED) == 0;
|
||||
status_trace("Channel %s(%d) was updated.",
|
||||
type_to_string(trc, struct short_channel_id,
|
||||
&short_channel_id),
|
||||
flags);
|
||||
|
||||
u8 *tag = tal_arr(tmpctx, u8, 0);
|
||||
towire_short_channel_id(&tag, &short_channel_id);
|
||||
towire_u16(&tag, flags & 0x1);
|
||||
queue_broadcast(rstate->broadcasts,
|
||||
WIRE_CHANNEL_UPDATE,
|
||||
tag,
|
||||
serialized);
|
||||
|
||||
tal_free(c->channel_update);
|
||||
c->channel_update = tal_steal(c, serialized);
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
static struct ipaddr *read_addresses(const tal_t *ctx, u8 *ser)
|
||||
{
|
||||
const u8 *cursor = ser;
|
||||
size_t max = tal_len(ser);
|
||||
struct ipaddr *ipaddrs = tal_arr(ctx, struct ipaddr, 0);
|
||||
int numaddrs = 0;
|
||||
while (cursor < ser + max) {
|
||||
numaddrs++;
|
||||
tal_resize(&ipaddrs, numaddrs);
|
||||
fromwire_ipaddr(&cursor, &max, &ipaddrs[numaddrs-1]);
|
||||
if (cursor == NULL) {
|
||||
/* Parsing address failed */
|
||||
return tal_free(ipaddrs);
|
||||
}
|
||||
}
|
||||
return ipaddrs;
|
||||
}
|
||||
|
||||
void handle_node_announcement(
|
||||
struct routing_state *rstate, const u8 *node_ann, size_t len)
|
||||
{
|
||||
u8 *serialized;
|
||||
struct sha256_double hash;
|
||||
struct node *node;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
u32 timestamp;
|
||||
struct pubkey node_id;
|
||||
u8 rgb_color[3];
|
||||
u8 alias[32];
|
||||
u8 *features, *addresses;
|
||||
const tal_t *tmpctx = tal_tmpctx(rstate);
|
||||
struct ipaddr *ipaddrs;
|
||||
|
||||
serialized = tal_dup_arr(tmpctx, u8, node_ann, len, 0);
|
||||
if (!fromwire_node_announcement(tmpctx, serialized, NULL,
|
||||
&signature, &features, ×tamp,
|
||||
&node_id, rgb_color, alias,
|
||||
&addresses)) {
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Check features!
|
||||
status_trace("Received node_announcement for node %s",
|
||||
type_to_string(trc, struct pubkey, &node_id));
|
||||
|
||||
sha256_double(&hash, serialized + 66, tal_count(serialized) - 66);
|
||||
if (!check_signed_hash(&hash, &signature, &node_id)) {
|
||||
status_trace("Ignoring node announcement, signature verification failed.");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
node = get_node(rstate, &node_id);
|
||||
|
||||
if (!node) {
|
||||
status_trace("Node not found, was the node_announcement preceeded by at least channel_announcement?");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
} else if (node->last_timestamp >= timestamp) {
|
||||
status_trace("Ignoring node announcement, it's outdated.");
|
||||
tal_free(tmpctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ipaddrs = read_addresses(tmpctx, addresses);
|
||||
if (!ipaddrs) {
|
||||
status_trace("Unable to parse addresses.");
|
||||
tal_free(serialized);
|
||||
return;
|
||||
}
|
||||
tal_free(node->addresses);
|
||||
node->addresses = tal_steal(node, ipaddrs);
|
||||
|
||||
node->last_timestamp = timestamp;
|
||||
|
||||
memcpy(node->rgb_color, rgb_color, 3);
|
||||
|
||||
u8 *tag = tal_arr(tmpctx, u8, 0);
|
||||
towire_pubkey(&tag, &node_id);
|
||||
queue_broadcast(rstate->broadcasts,
|
||||
WIRE_NODE_ANNOUNCEMENT,
|
||||
tag,
|
||||
serialized);
|
||||
tal_free(node->node_announcement);
|
||||
node->node_announcement = tal_steal(node, serialized);
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
|
||||
const struct pubkey *source,
|
||||
const struct pubkey *destination,
|
||||
const u32 msatoshi, double riskfactor)
|
||||
{
|
||||
struct node_connection **route;
|
||||
u64 total_amount;
|
||||
unsigned int total_delay;
|
||||
s64 fee;
|
||||
struct route_hop *hops;
|
||||
int i;
|
||||
struct node_connection *first_conn;
|
||||
|
||||
first_conn = find_route(ctx, rstate, source, destination, msatoshi,
|
||||
riskfactor, &fee, &route);
|
||||
|
||||
if (!first_conn) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fees, delays need to be calculated backwards along route. */
|
||||
hops = tal_arr(ctx, struct route_hop, tal_count(route) + 1);
|
||||
total_amount = msatoshi;
|
||||
total_delay = 0;
|
||||
|
||||
for (i = tal_count(route) - 1; i >= 0; i--) {
|
||||
hops[i + 1].channel_id = route[i]->short_channel_id;
|
||||
hops[i + 1].nodeid = route[i]->dst->id;
|
||||
hops[i + 1].amount = total_amount;
|
||||
total_amount += connection_fee(route[i], total_amount);
|
||||
|
||||
total_delay += route[i]->delay;
|
||||
if (total_delay < route[i]->min_blocks)
|
||||
total_delay = route[i]->min_blocks;
|
||||
hops[i + 1].delay = total_delay;
|
||||
}
|
||||
/* Backfill the first hop manually */
|
||||
hops[0].channel_id = first_conn->short_channel_id;
|
||||
hops[0].nodeid = first_conn->dst->id;
|
||||
/* We don't charge ourselves any fees. */
|
||||
hops[0].amount = total_amount;
|
||||
/* We do require delay though. */
|
||||
total_delay += first_conn->delay;
|
||||
hops[0].delay = total_delay;
|
||||
return hops;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_ROUTING_H
|
||||
#define LIGHTNING_LIGHTNINGD_GOSSIP_ROUTING_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <lightningd/gossip/broadcast.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
#define ROUTING_MAX_HOPS 20
|
||||
#define ROUTING_FLAGS_DISABLED 2
|
||||
|
||||
struct node_connection {
|
||||
struct node *src, *dst;
|
||||
/* millisatoshi. */
|
||||
u32 base_fee;
|
||||
/* millionths */
|
||||
s32 proportional_fee;
|
||||
|
||||
/* Delay for HTLC in blocks.*/
|
||||
u32 delay;
|
||||
/* Minimum allowable HTLC expiry in blocks. */
|
||||
u32 min_blocks;
|
||||
|
||||
/* Is this connection active? */
|
||||
bool active;
|
||||
|
||||
u32 last_timestamp;
|
||||
|
||||
/* Minimum number of msatoshi in an HTLC */
|
||||
u32 htlc_minimum_msat;
|
||||
|
||||
/* The channel ID, as determined by the anchor transaction */
|
||||
struct short_channel_id short_channel_id;
|
||||
|
||||
/* Flags as specified by the `channel_update`s, among other
|
||||
* things indicated direction wrt the `channel_id` */
|
||||
u16 flags;
|
||||
|
||||
/* Cached `channel_announcement` and `channel_update` we might forward to new peers*/
|
||||
u8 *channel_announcement;
|
||||
u8 *channel_update;
|
||||
};
|
||||
|
||||
struct node {
|
||||
struct pubkey id;
|
||||
|
||||
/* IP/Hostname and port of this node (may be NULL) */
|
||||
struct ipaddr *addresses;
|
||||
|
||||
u32 last_timestamp;
|
||||
|
||||
/* Routes connecting to us, from us. */
|
||||
struct node_connection **in, **out;
|
||||
|
||||
/* Temporary data for routefinding. */
|
||||
struct {
|
||||
/* Total to get to here from target. */
|
||||
s64 total;
|
||||
/* Total risk premium of this route. */
|
||||
u64 risk;
|
||||
/* Where that came from. */
|
||||
struct node_connection *prev;
|
||||
} bfg[ROUTING_MAX_HOPS+1];
|
||||
|
||||
/* UTF-8 encoded alias as tal_arr, not zero terminated */
|
||||
u8 *alias;
|
||||
|
||||
/* Color to be used when displaying the name */
|
||||
u8 rgb_color[3];
|
||||
|
||||
/* Cached `node_announcement` we might forward to new peers. */
|
||||
u8 *node_announcement;
|
||||
};
|
||||
|
||||
const secp256k1_pubkey *node_map_keyof_node(const struct node *n);
|
||||
size_t node_map_hash_key(const secp256k1_pubkey *key);
|
||||
bool node_map_node_eq(const struct node *n, const secp256k1_pubkey *key);
|
||||
HTABLE_DEFINE_TYPE(struct node, node_map_keyof_node, node_map_hash_key, node_map_node_eq, node_map);
|
||||
|
||||
struct routing_state {
|
||||
/* All known nodes. */
|
||||
struct node_map *nodes;
|
||||
|
||||
struct broadcast_state *broadcasts;
|
||||
|
||||
struct sha256_double chain_hash;
|
||||
};
|
||||
|
||||
struct route_hop {
|
||||
struct short_channel_id channel_id;
|
||||
struct pubkey nodeid;
|
||||
u32 amount;
|
||||
u32 delay;
|
||||
};
|
||||
|
||||
struct routing_state *new_routing_state(const tal_t *ctx,
|
||||
const struct sha256_double *chain_hash);
|
||||
|
||||
struct node *new_node(struct routing_state *rstate,
|
||||
const struct pubkey *id);
|
||||
|
||||
struct node *get_node(struct routing_state *rstate,
|
||||
const struct pubkey *id);
|
||||
|
||||
/* msatoshi must be possible (< 21 million BTC), ie < 2^60.
|
||||
* If it returns more than msatoshi, it overflowed. */
|
||||
s64 connection_fee(const struct node_connection *c, u64 msatoshi);
|
||||
|
||||
/* Updates existing node, or creates a new one as required. */
|
||||
struct node *add_node(struct routing_state *rstate,
|
||||
const struct pubkey *pk);
|
||||
|
||||
/* Updates existing connection, or creates new one as required. */
|
||||
struct node_connection *add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
u32 base_fee, s32 proportional_fee,
|
||||
u32 delay, u32 min_blocks);
|
||||
|
||||
/* Add a connection to the routing table, but do not mark it as usable
|
||||
* yet. Used by channel_announcements before the channel_update comes
|
||||
* in. */
|
||||
|
||||
struct node_connection *half_add_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
const struct short_channel_id *schanid,
|
||||
const u16 flags);
|
||||
|
||||
/* Get an existing connection between `from` and `to`, NULL if no such
|
||||
* connection exists. */
|
||||
struct node_connection *get_connection(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to);
|
||||
|
||||
/* Given a short_channel_id, retrieve the matching connection, or NULL if it is
|
||||
* unknown. */
|
||||
struct node_connection *get_connection_by_scid(const struct routing_state *rstate,
|
||||
const struct short_channel_id *schanid,
|
||||
const u8 direction);
|
||||
|
||||
void remove_connection(struct routing_state *rstate,
|
||||
const struct pubkey *src, const struct pubkey *dst);
|
||||
|
||||
struct node_connection *
|
||||
find_route(const tal_t *ctx, struct routing_state *rstate,
|
||||
const struct pubkey *from, const struct pubkey *to, u64 msatoshi,
|
||||
double riskfactor, s64 *fee, struct node_connection ***route);
|
||||
|
||||
struct node_map *empty_node_map(const tal_t *ctx);
|
||||
|
||||
bool add_channel_direction(struct routing_state *rstate,
|
||||
const struct pubkey *from,
|
||||
const struct pubkey *to,
|
||||
const struct short_channel_id *short_channel_id,
|
||||
const u8 *announcement);
|
||||
|
||||
bool read_ip(const tal_t *ctx, const u8 *addresses, char **hostname, int *port);
|
||||
u8 *write_ip(const tal_t *ctx, const char *srcip, int port);
|
||||
|
||||
/* Handlers for incoming messages */
|
||||
void handle_channel_announcement(struct routing_state *rstate, const u8 *announce, size_t len);
|
||||
void handle_channel_update(struct routing_state *rstate, const u8 *update, size_t len);
|
||||
void handle_node_announcement(struct routing_state *rstate, const u8 *node, size_t len);
|
||||
|
||||
/* Compute a route to a destination, for a given amount and riskfactor. */
|
||||
struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
|
||||
const struct pubkey *source,
|
||||
const struct pubkey *destination,
|
||||
const u32 msatoshi, double riskfactor);
|
||||
|
||||
/* Utility function that, given a source and a destination, gives us
|
||||
* the direction bit the matching channel should get */
|
||||
#define get_channel_direction(from, to) (pubkey_cmp(from, to) > 0)
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_ROUTING_H */
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||
#include <lightningd/gossip_msg.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/log.h>
|
||||
@@ -144,7 +144,7 @@ void gossip_init(struct lightningd *ld)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(ld);
|
||||
u8 *init;
|
||||
ld->gossip = new_subd(ld, ld, "lightningd_gossip", NULL,
|
||||
ld->gossip = new_subd(ld, ld, "lightning_gossipd", NULL,
|
||||
gossip_wire_type_name,
|
||||
gossip_msg, gossip_finished, NULL);
|
||||
if (!ld->gossip)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define LIGHTNING_LIGHTNINGD_GOSSIP_MSG_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <lightningd/gossip/routing.h>
|
||||
#include <gossipd/routing.h>
|
||||
|
||||
struct gossip_getnodes_entry {
|
||||
struct pubkey nodeid;
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/handshake-wrongdir:
|
||||
$(MAKE) -C .. lightningd/handshake-all
|
||||
|
||||
default: lightningd/handshake-all
|
||||
|
||||
lightningd/handshake-all: lightningd/lightningd_handshake
|
||||
|
||||
# lightningd/handshake needs these:
|
||||
LIGHTNINGD_HANDSHAKE_HEADERS := \
|
||||
lightningd/handshake/gen_handshake_wire.h
|
||||
LIGHTNINGD_HANDSHAKE_SRC := lightningd/handshake/handshake.c \
|
||||
$(LIGHTNINGD_HANDSHAKE_HEADERS:.h=.c)
|
||||
LIGHTNINGD_HANDSHAKE_OBJS := $(LIGHTNINGD_HANDSHAKE_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_HANDSHAKE_OBJS)
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_HANDSHAKE_CONTROL_HEADERS := $(LIGHTNINGD_HANDSHAKE_HEADERS)
|
||||
LIGHTNINGD_HANDSHAKE_CONTROL_SRC := $(LIGHTNINGD_HANDSHAKE_HEADERS:.h=.c)
|
||||
LIGHTNINGD_HANDSHAKE_CONTROL_OBJS := $(LIGHTNINGD_HANDSHAKE_CONTROL_SRC:.c=.o)
|
||||
|
||||
LIGHTNINGD_HANDSHAKE_GEN_SRC := $(filter lightningd/handshake/gen_%, $(LIGHTNINGD_HANDSHAKE_SRC) $(LIGHTNINGD_HANDSHAKE_CONTROL_SRC))
|
||||
|
||||
LIGHTNINGD_HANDSHAKE_SRC_NOGEN := $(filter-out lightningd/handshake/gen_%, $(LIGHTNINGD_HANDSHAKE_SRC))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_HANDSHAKE_HEADERS)
|
||||
|
||||
$(LIGHTNINGD_HANDSHAKE_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
# Common source we use.
|
||||
HANDSHAKED_COMMON_OBJS := \
|
||||
common/crypto_sync.o \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/dev_disconnect.o \
|
||||
common/msg_queue.o \
|
||||
common/status.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o
|
||||
|
||||
lightningd/handshake/gen_handshake_wire.h: $(WIRE_GEN) lightningd/handshake/handshake_wire.csv
|
||||
$(WIRE_GEN) --header $@ handshake_wire_type < lightningd/handshake/handshake_wire.csv > $@
|
||||
|
||||
lightningd/handshake/gen_handshake_wire.c: $(WIRE_GEN) lightningd/handshake/handshake_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} handshake_wire_type < lightningd/handshake/handshake_wire.csv > $@
|
||||
|
||||
LIGHTNINGD_HANDSHAKE_OBJS := $(LIGHTNINGD_HANDSHAKE_SRC:.c=.o) $(LIGHTNINGD_HANDSHAKE_GEN_SRC:.c=.o)
|
||||
|
||||
lightningd/lightningd_handshake: $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_HANDSHAKE_OBJS) $(HANDSHAKED_COMMON_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS)
|
||||
|
||||
check-source: $(LIGHTNINGD_HANDSHAKE_SRC_NOGEN:%=check-src-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_HANDSHAKE_SRC:%=bolt-check/%) $(LIGHTNINGD_HANDSHAKE_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-whitespace: $(LIGHTNINGD_HANDSHAKE_SRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_HANDSHAKE_HEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/handshake-clean
|
||||
|
||||
lightningd/handshake-clean:
|
||||
$(RM) $(LIGHTNINGD_HANDSHAKE_OBJS) gen_*
|
||||
|
||||
-include lightningd/handshake/test/Makefile
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,56 +0,0 @@
|
||||
#include <common/cryptomsg.h>
|
||||
handshake_bad_command,0x8000
|
||||
initr_act1_bad_ecdh_for_ss,0x8011
|
||||
initr_act1_write_failed,0x8012
|
||||
initr_act2_read_failed,0x8013
|
||||
initr_act2_bad_version,0x8014
|
||||
initr_act2_bad_pubkey,0x8015
|
||||
initr_act2_bad_ecdh_for_ss,0x8016
|
||||
initr_act2_bad_tag,0x8017
|
||||
initr_act3_bad_hsm_ecdh,0x8018
|
||||
initr_act3_write_failed,0x8019
|
||||
respr_act1_read_failed,0x801A
|
||||
respr_act1_bad_version,0x801B
|
||||
respr_act1_bad_pubkey,0x801C
|
||||
respr_act1_bad_hsm_ecdh,0x801D
|
||||
respr_act1_bad_tag,0x801E
|
||||
respr_act2_bad_ecdh_for_ss,0x801F
|
||||
respr_act2_write_failed,0x8020
|
||||
respr_act3_read_failed,0x8021
|
||||
respr_act3_bad_version,0x8022
|
||||
respr_act3_bad_ciphertext,0x8023
|
||||
respr_act3_bad_pubkey,0x8024
|
||||
respr_act3_bad_ecdh_for_ss,0x8025
|
||||
respr_act3_bad_tag,0x8026
|
||||
initmsg_write_failed,0x8030
|
||||
initmsg_read_failed,0x8031
|
||||
|
||||
# FIXME: This is probably too finegrained.
|
||||
initr_act_one,1001
|
||||
initr_act_two,1002
|
||||
initr_act_three,1003
|
||||
respr_act_one,1011
|
||||
respr_act_two,1012
|
||||
respr_act_three,1013
|
||||
success,0
|
||||
|
||||
handshake_responder,1
|
||||
handshake_responder,,my_id,33
|
||||
handshake_responder_reply,101
|
||||
handshake_responder_reply,,initiator_id,33
|
||||
handshake_responder_reply,,cs,struct crypto_state
|
||||
handshake_responder_reply,,gflen,2
|
||||
handshake_responder_reply,,globalfeatures,gflen
|
||||
handshake_responder_reply,,lflen,2
|
||||
handshake_responder_reply,,localfeatures,lflen
|
||||
|
||||
handshake_initiator,2
|
||||
handshake_initiator,,my_id,33
|
||||
handshake_initiator,,responder_id,33
|
||||
|
||||
handshake_initiator_reply,102
|
||||
handshake_initiator_reply,,cs,struct crypto_state
|
||||
handshake_initiator_reply,,gflen,2
|
||||
handshake_initiator_reply,,globalfeatures,gflen
|
||||
handshake_initiator_reply,,lflen,2
|
||||
handshake_initiator_reply,,localfeatures,lflen
|
||||
|
1
lightningd/handshake/test/.gitignore
vendored
1
lightningd/handshake/test/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
run-handshake
|
||||
@@ -1,30 +0,0 @@
|
||||
check: lightningd/handshake-tests
|
||||
|
||||
# Note that these actually #include everything they need, except ccan/ and bitcoin/.
|
||||
# That allows for unit testing of statics, and special effects.
|
||||
LIGHTNINGD_HANDSHAKE_TEST_SRC := $(wildcard lightningd/handshake/test/run-*.c)
|
||||
LIGHTNINGD_HANDSHAKE_TEST_OBJS := $(LIGHTNINGD_HANDSHAKE_TEST_SRC:.c=.o)
|
||||
LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS := $(LIGHTNINGD_HANDSHAKE_TEST_OBJS:.o=)
|
||||
|
||||
LIGHTNINGD_HANDSHAKE_TEST_COMMON_OBJS := \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/dev_disconnect.o \
|
||||
common/htlc_state.o \
|
||||
common/msg_queue.o \
|
||||
common/pseudorand.o \
|
||||
common/status.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o
|
||||
|
||||
update-mocks: $(LIGHTNINGD_HANDSHAKE_TEST_SRC:%=update-mocks/%)
|
||||
|
||||
$(LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS): $(LIGHTNINGD_HANDSHAKE_TEST_COMMON_OBJS) $(LIGHTNINGD_HANDSHAKE_GEN_SRC:.c=.o) $(BITCOIN_OBJS) $(WIRE_OBJS)
|
||||
|
||||
$(LIGHTNINGD_HANDSHAKE_TEST_OBJS): $(LIGHTNINGD_HANDSHAKE_HEADERS)
|
||||
|
||||
ALL_OBJS += $(LIGHTNINGD_HANDSHAKE_TEST_OBJS)
|
||||
ALL_TEST_PROGRAMS += $(LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS)
|
||||
|
||||
lightningd/handshake-tests: $(LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS:%=unittest/%)
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <common/status.h>
|
||||
|
||||
/* Since we use pipes, we need different fds for read and write. */
|
||||
static int read_fd, write_fd;
|
||||
|
||||
static bool fake_read_all(int fd, void *buf, size_t count)
|
||||
{
|
||||
return read_all(read_fd, buf, count);
|
||||
}
|
||||
|
||||
static ssize_t fake_write_all(int fd, const void *buf, size_t count)
|
||||
{
|
||||
return write_all(write_fd, buf, count);
|
||||
}
|
||||
|
||||
static const char *status_prefix;
|
||||
|
||||
/* Simply print out status updates. */
|
||||
#define status_send_sync(msg) \
|
||||
printf("%s:# Act %s\n", status_prefix, \
|
||||
fromwire_peektype(msg) == WIRE_INITR_ACT_ONE ? "One" \
|
||||
: fromwire_peektype(msg) == WIRE_INITR_ACT_TWO ? "Two" \
|
||||
: fromwire_peektype(msg) == WIRE_INITR_ACT_THREE ? "Three" \
|
||||
: fromwire_peektype(msg) == WIRE_RESPR_ACT_ONE ? "One" \
|
||||
: fromwire_peektype(msg) == WIRE_RESPR_ACT_TWO ? "Two" \
|
||||
: fromwire_peektype(msg) == WIRE_RESPR_ACT_THREE ? "Three" \
|
||||
: "UNKNOWN")
|
||||
#define status_failed(code, fmt, ...) \
|
||||
errx(1, "%s:%s:" fmt "\n", status_prefix, #code, __VA_ARGS__)
|
||||
#define status_trace(fmt, ...) \
|
||||
printf("%s:" fmt "\n", status_prefix, __VA_ARGS__)
|
||||
|
||||
#define read_all fake_read_all
|
||||
#define write_all fake_write_all
|
||||
|
||||
/* No randomness please, we want to replicate test vectors. */
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
static unsigned char e_priv[32];
|
||||
#define randombytes_buf(secret, len) memcpy((secret), e_priv, len)
|
||||
|
||||
#define TESTING
|
||||
#include "../handshake.c"
|
||||
#include <common/utils.h>
|
||||
#include <ccan/err/err.h>
|
||||
|
||||
secp256k1_context *secp256k1_ctx;
|
||||
const void *trc;
|
||||
static struct privkey privkey;
|
||||
|
||||
void hsm_setup(int fd)
|
||||
{
|
||||
}
|
||||
|
||||
bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point)
|
||||
{
|
||||
return secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
|
||||
privkey.secret.data) == 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fds1[2], fds2[2];
|
||||
struct pubkey responder_id;
|
||||
struct privkey responder_privkey;
|
||||
struct secret ck, sk, rk;
|
||||
const tal_t *ctx = tal_tmpctx(NULL);
|
||||
|
||||
trc = tal_tmpctx(ctx);
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
memset(responder_privkey.secret.data, 0x21,
|
||||
sizeof(responder_privkey.secret.data));
|
||||
if (!secp256k1_ec_pubkey_create(secp256k1_ctx,
|
||||
&responder_id.pubkey,
|
||||
responder_privkey.secret.data))
|
||||
errx(1, "Keygen failed");
|
||||
|
||||
if (pipe(fds1) != 0 || pipe(fds2) != 0)
|
||||
err(1, "Making pipes");
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
err(1, "fork failed");
|
||||
case 0: {
|
||||
struct pubkey their_id;
|
||||
|
||||
memset(e_priv, 0x22, sizeof(e_priv));
|
||||
read_fd = fds1[0];
|
||||
write_fd = fds2[1];
|
||||
close(fds1[1]);
|
||||
close(fds2[0]);
|
||||
privkey = responder_privkey;
|
||||
status_prefix = "RESPR";
|
||||
status_trace("ls.priv: 0x%s",
|
||||
tal_hexstr(trc, &responder_privkey,
|
||||
sizeof(responder_privkey)));
|
||||
status_trace("ls.pub: 0x%s",
|
||||
type_to_string(trc, struct pubkey, &responder_id));
|
||||
responder(-1, &responder_id, &their_id, &ck, &sk, &rk);
|
||||
if (!write_all(write_fd, &ck, sizeof(ck))
|
||||
|| !write_all(write_fd, &sk, sizeof(sk))
|
||||
|| !write_all(write_fd, &rk, sizeof(rk)))
|
||||
err(1, "writing out secrets failed");
|
||||
goto out;
|
||||
}
|
||||
default: {
|
||||
struct pubkey initiator_id;
|
||||
struct privkey initiator_privkey;
|
||||
struct secret their_ck, their_sk, their_rk;
|
||||
|
||||
read_fd = fds2[0];
|
||||
write_fd = fds1[1];
|
||||
close(fds2[1]);
|
||||
close(fds1[0]);
|
||||
|
||||
memset(initiator_privkey.secret.data, 0x11,
|
||||
sizeof(initiator_privkey.secret.data));
|
||||
memset(e_priv, 0x12, sizeof(e_priv));
|
||||
if (!secp256k1_ec_pubkey_create(secp256k1_ctx,
|
||||
&initiator_id.pubkey,
|
||||
initiator_privkey.secret.data))
|
||||
errx(1, "Initiator keygen failed");
|
||||
privkey = initiator_privkey;
|
||||
status_prefix = "INITR";
|
||||
status_trace("rs.pub: 0x%s",
|
||||
type_to_string(trc, struct pubkey, &responder_id));
|
||||
status_trace("ls.priv: 0x%s",
|
||||
tal_hexstr(trc, &initiator_privkey,
|
||||
sizeof(initiator_privkey)));
|
||||
status_trace("ls.pub: 0x%s",
|
||||
type_to_string(trc, struct pubkey, &initiator_id));
|
||||
|
||||
initiator(-1, &initiator_id, &responder_id, &ck, &sk, &rk);
|
||||
if (!read_all(read_fd, &their_ck, sizeof(their_ck))
|
||||
|| !read_all(read_fd, &their_sk, sizeof(their_sk))
|
||||
|| !read_all(read_fd, &their_rk, sizeof(their_rk)))
|
||||
err(1, "reading their secrets failed");
|
||||
|
||||
assert(structeq(&ck, &their_ck));
|
||||
assert(structeq(&sk, &their_rk));
|
||||
assert(structeq(&rk, &their_sk));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/* No memory leaks please */
|
||||
secp256k1_context_destroy(secp256k1_ctx);
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/hsm-wrongdir:
|
||||
$(MAKE) -C .. lightningd/hsm-all
|
||||
|
||||
default: lightningd/hsm-all
|
||||
|
||||
# Clients use this:
|
||||
LIGHTNINGD_HSM_CLIENT_HEADERS := lightningd/hsm/client.h
|
||||
LIGHTNINGD_HSM_CLIENT_SRC := lightningd/hsm/client.c lightningd/hsm/gen_hsm_client_wire.c
|
||||
LIGHTNINGD_HSM_CLIENT_OBJS := $(LIGHTNINGD_HSM_CLIENT_SRC:.c=.o)
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_HSM_CONTROL_HEADERS := lightningd/hsm/gen_hsm_wire.h
|
||||
LIGHTNINGD_HSM_CONTROL_SRC := lightningd/hsm/gen_hsm_wire.c
|
||||
LIGHTNINGD_HSM_CONTROL_OBJS := $(LIGHTNINGD_HSM_CONTROL_SRC:.c=.o)
|
||||
|
||||
# lightningd/hsm needs these:
|
||||
LIGHTNINGD_HSM_HEADERS := lightningd/hsm/gen_hsm_client_wire.h \
|
||||
lightningd/hsm/gen_hsm_wire.h
|
||||
LIGHTNINGD_HSM_SRC := lightningd/hsm/hsm.c \
|
||||
$(LIGHTNINGD_HSM_HEADERS:.h=.c)
|
||||
LIGHTNINGD_HSM_OBJS := $(LIGHTNINGD_HSM_SRC:.c=.o)
|
||||
|
||||
# Common source we use.
|
||||
HSMD_COMMON_OBJS := \
|
||||
common/bip32.o \
|
||||
common/daemon_conn.o \
|
||||
common/funding_tx.o \
|
||||
common/key_derive.o \
|
||||
common/msg_queue.o \
|
||||
common/permute_tx.o \
|
||||
common/status.o \
|
||||
common/utils.o \
|
||||
common/utxo.o \
|
||||
common/version.o \
|
||||
common/withdraw_tx.o
|
||||
|
||||
# For checking
|
||||
LIGHTNINGD_HSM_ALLSRC_NOGEN := $(filter-out lightningd/hsm/gen_%, $(LIGHTNINGD_HSM_CLIENT_SRC) $(LIGHTNINGD_HSM_SRC))
|
||||
LIGHTNINGD_HSM_ALLHEADERS_NOGEN := $(filter-out lightningd/hsm/gen_%, $(LIGHTNINGD_HSM_CLIENT_HEADERS) $(LIGHTNINGD_HSM_HEADERS))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_HSM_HEADERS) $(LIGHTNINGD_HSM_CLIENT_HEADERS)
|
||||
|
||||
$(LIGHTNINGD_HSM_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
$(LIGHTNINGD_HSM_CONTROL_OBJS) : $(LIGHTNINGD_HSM_CONTROL_HEADERS)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_HSM_OBJS)
|
||||
|
||||
lightningd/hsm-all: lightningd/lightningd_hsm $(LIGHTNINGD_HSM_CLIENT_OBJS)
|
||||
|
||||
lightningd/lightningd_hsm: $(LIGHTNINGD_HSM_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(HSMD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS)
|
||||
|
||||
lightningd/hsm/gen_hsm_client_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_client_wire_csv
|
||||
$(WIRE_GEN) --header $@ hsm_client_wire_type < lightningd/hsm/hsm_client_wire_csv > $@
|
||||
|
||||
lightningd/hsm/gen_hsm_client_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_client_wire_csv
|
||||
$(WIRE_GEN) ${@:.c=.h} hsm_client_wire_type< lightningd/hsm/hsm_client_wire_csv > $@
|
||||
|
||||
lightningd/hsm/gen_hsm_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_wire.csv
|
||||
$(WIRE_GEN) --header $@ hsm_wire_type < lightningd/hsm/hsm_wire.csv > $@
|
||||
|
||||
lightningd/hsm/gen_hsm_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} hsm_wire_type < lightningd/hsm/hsm_wire.csv > $@
|
||||
|
||||
check-source: $(LIGHTNINGD_HSM_ALLSRC_NOGEN:%=check-src-include-order/%) $(LIGHTNINGD_HSM_ALLHEADERS_NOGEN:%=check-hdr-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_HSM_SRC:%=bolt-check/%) $(LIGHTNINGD_HSM_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-whitespace: $(LIGHTNINGD_HSM_ALLSRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_HSM_ALLHEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/hsm-clean
|
||||
|
||||
lightningd/hsm-clean:
|
||||
$(RM) $(LIGHTNINGD_HSM_OBJS) gen_*
|
||||
|
||||
-include lightningd/hsm/test/Makefile
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <lightningd/hsm/client.h>
|
||||
#include <lightningd/hsm/gen_hsm_client_wire.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
static int hsm_fd = -1;
|
||||
|
||||
void hsm_setup(int fd)
|
||||
{
|
||||
hsm_fd = fd;
|
||||
}
|
||||
|
||||
bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point)
|
||||
{
|
||||
u8 *req = towire_hsm_ecdh_req(NULL, point), *resp;
|
||||
size_t len;
|
||||
|
||||
if (!wire_sync_write(hsm_fd, req))
|
||||
goto fail;
|
||||
resp = wire_sync_read(req, hsm_fd);
|
||||
if (!resp)
|
||||
goto fail;
|
||||
len = tal_count(resp);
|
||||
if (!fromwire_hsm_ecdh_resp(resp, &len, ss))
|
||||
goto fail;
|
||||
tal_free(req);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
tal_free(req);
|
||||
return false;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* API to ask the HSM for things. */
|
||||
#ifndef LIGHTNING_LIGHTNINGD_HSM_CLIENT_H
|
||||
#define LIGHTNING_LIGHTNINGD_HSM_CLIENT_H
|
||||
#include "config.h"
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct pubkey;
|
||||
struct secret;
|
||||
|
||||
/* Setup communication to the HSM */
|
||||
void hsm_setup(int fd);
|
||||
|
||||
/* Do ECDH using this node id secret. */
|
||||
bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_HSM_CLIENT_H */
|
||||
@@ -1,677 +0,0 @@
|
||||
#include <bitcoin/address.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/breakpoint/breakpoint.h>
|
||||
#include <ccan/container_of/container_of.h>
|
||||
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/fdpass/fdpass.h>
|
||||
#include <ccan/io/fdpass/fdpass.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/noerr/noerr.h>
|
||||
#include <ccan/ptrint/ptrint.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/take/take.h>
|
||||
#include <common/daemon_conn.h>
|
||||
#include <common/funding_tx.h>
|
||||
#include <common/status.h>
|
||||
#include <common/utils.h>
|
||||
#include <common/version.h>
|
||||
#include <common/withdraw_tx.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/hsm/client.h>
|
||||
#include <lightningd/hsm/gen_hsm_client_wire.h>
|
||||
#include <lightningd/hsm/gen_hsm_wire.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <wally_bip32.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
#include <wire/wire_io.h>
|
||||
|
||||
/* Nobody will ever find it here! */
|
||||
static struct {
|
||||
struct secret hsm_secret;
|
||||
struct ext_key bip32;
|
||||
} secretstuff;
|
||||
|
||||
struct client {
|
||||
struct daemon_conn dc;
|
||||
struct daemon_conn *master;
|
||||
|
||||
u64 id;
|
||||
struct io_plan *(*handle)(struct io_conn *, struct daemon_conn *);
|
||||
};
|
||||
|
||||
static void node_key(struct privkey *node_privkey, struct pubkey *node_id)
|
||||
{
|
||||
u32 salt = 0;
|
||||
struct privkey unused_s;
|
||||
struct pubkey unused_k;
|
||||
|
||||
if (node_privkey == NULL)
|
||||
node_privkey = &unused_s;
|
||||
else if (node_id == NULL)
|
||||
node_id = &unused_k;
|
||||
|
||||
do {
|
||||
hkdf_sha256(node_privkey, sizeof(*node_privkey),
|
||||
&salt, sizeof(salt),
|
||||
&secretstuff.hsm_secret,
|
||||
sizeof(secretstuff.hsm_secret),
|
||||
"nodeid", 6);
|
||||
salt++;
|
||||
} while (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey,
|
||||
node_privkey->secret.data));
|
||||
}
|
||||
|
||||
static struct client *new_client(struct daemon_conn *master,
|
||||
u64 id,
|
||||
struct io_plan *(*handle)(struct io_conn *,
|
||||
struct daemon_conn *),
|
||||
int fd)
|
||||
{
|
||||
struct client *c = tal(master, struct client);
|
||||
c->id = id;
|
||||
c->handle = handle;
|
||||
c->master = master;
|
||||
daemon_conn_init(c, &c->dc, fd, handle, NULL);
|
||||
|
||||
/* Free the connection if we exit everything. */
|
||||
tal_steal(master, c->dc.conn);
|
||||
/* Free client when connection freed. */
|
||||
tal_steal(c->dc.conn, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static struct io_plan *handle_ecdh(struct io_conn *conn, struct daemon_conn *dc)
|
||||
{
|
||||
struct client *c = container_of(dc, struct client, dc);
|
||||
struct privkey privkey;
|
||||
struct pubkey point;
|
||||
struct secret ss;
|
||||
|
||||
if (!fromwire_hsm_ecdh_req(dc->msg_in, NULL, &point)) {
|
||||
daemon_conn_send(c->master,
|
||||
take(towire_hsmstatus_client_bad_request(c,
|
||||
c->id,
|
||||
dc->msg_in)));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
node_key(&privkey, NULL);
|
||||
if (secp256k1_ecdh(secp256k1_ctx, ss.data, &point.pubkey,
|
||||
privkey.secret.data) != 1) {
|
||||
status_trace("secp256k1_ecdh fail for client %"PRIu64, c->id);
|
||||
daemon_conn_send(c->master,
|
||||
take(towire_hsmstatus_client_bad_request(c,
|
||||
c->id,
|
||||
dc->msg_in)));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
daemon_conn_send(dc, take(towire_hsm_ecdh_resp(c, &ss)));
|
||||
return daemon_conn_read_next(conn, dc);
|
||||
}
|
||||
|
||||
static struct io_plan *handle_cannouncement_sig(struct io_conn *conn,
|
||||
struct daemon_conn *dc)
|
||||
{
|
||||
tal_t *ctx = tal_tmpctx(conn);
|
||||
/* First 2 + 256 byte are the signatures and msg type, skip them */
|
||||
size_t offset = 258;
|
||||
struct privkey node_pkey;
|
||||
secp256k1_ecdsa_signature node_sig;
|
||||
struct sha256_double hash;
|
||||
u8 *reply;
|
||||
u8 *ca;
|
||||
struct pubkey bitcoin_id;
|
||||
|
||||
if (!fromwire_hsm_cannouncement_sig_req(ctx, dc->msg_in, NULL,
|
||||
&bitcoin_id, &ca)) {
|
||||
status_trace("Failed to parse cannouncement_sig_req: %s",
|
||||
tal_hex(trc, dc->msg_in));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
if (tal_len(ca) < offset) {
|
||||
status_trace("bad cannounce length %zu", tal_len(ca));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
/* TODO(cdecker) Check that this is actually a valid
|
||||
* channel_announcement */
|
||||
node_key(&node_pkey, NULL);
|
||||
sha256_double(&hash, ca + offset, tal_len(ca) - offset);
|
||||
|
||||
sign_hash(&node_pkey, &hash, &node_sig);
|
||||
|
||||
reply = towire_hsm_cannouncement_sig_reply(ca, &node_sig);
|
||||
daemon_conn_send(dc, take(reply));
|
||||
|
||||
tal_free(ctx);
|
||||
return daemon_conn_read_next(conn, dc);
|
||||
}
|
||||
|
||||
static struct io_plan *handle_channel_update_sig(struct io_conn *conn,
|
||||
struct daemon_conn *dc)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(conn);
|
||||
/* 2 bytes msg type + 64 bytes signature */
|
||||
size_t offset = 66;
|
||||
struct privkey node_pkey;
|
||||
struct sha256_double hash;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
struct short_channel_id scid;
|
||||
u32 timestamp, fee_base_msat, fee_proportional_mill;
|
||||
u64 htlc_minimum_msat;
|
||||
u16 flags, cltv_expiry_delta;
|
||||
struct sha256_double chain_hash;
|
||||
u8 *cu;
|
||||
|
||||
if (!fromwire_hsm_cupdate_sig_req(tmpctx, dc->msg_in, NULL, &cu)) {
|
||||
status_trace("Failed to parse %s: %s",
|
||||
hsm_client_wire_type_name(fromwire_peektype(dc->msg_in)),
|
||||
tal_hex(trc, dc->msg_in));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
if (!fromwire_channel_update(cu, NULL, &sig, &chain_hash,
|
||||
&scid, ×tamp, &flags,
|
||||
&cltv_expiry_delta, &htlc_minimum_msat,
|
||||
&fee_base_msat, &fee_proportional_mill)) {
|
||||
status_trace("Failed to parse inner channel_update: %s",
|
||||
tal_hex(trc, dc->msg_in));
|
||||
return io_close(conn);
|
||||
}
|
||||
if (tal_len(cu) < offset) {
|
||||
status_trace("inner channel_update too short: %s",
|
||||
tal_hex(trc, dc->msg_in));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
node_key(&node_pkey, NULL);
|
||||
sha256_double(&hash, cu + offset, tal_len(cu) - offset);
|
||||
|
||||
sign_hash(&node_pkey, &hash, &sig);
|
||||
|
||||
cu = towire_channel_update(tmpctx, &sig, &chain_hash,
|
||||
&scid, timestamp, flags,
|
||||
cltv_expiry_delta, htlc_minimum_msat,
|
||||
fee_base_msat, fee_proportional_mill);
|
||||
|
||||
daemon_conn_send(dc, take(towire_hsm_cupdate_sig_reply(tmpctx, cu)));
|
||||
tal_free(tmpctx);
|
||||
return daemon_conn_read_next(conn, dc);
|
||||
}
|
||||
|
||||
static struct io_plan *handle_channeld(struct io_conn *conn,
|
||||
struct daemon_conn *dc)
|
||||
{
|
||||
struct client *c = container_of(dc, struct client, dc);
|
||||
enum hsm_client_wire_type t = fromwire_peektype(dc->msg_in);
|
||||
|
||||
switch (t) {
|
||||
case WIRE_HSM_ECDH_REQ:
|
||||
return handle_ecdh(conn, dc);
|
||||
case WIRE_HSM_CANNOUNCEMENT_SIG_REQ:
|
||||
return handle_cannouncement_sig(conn, dc);
|
||||
case WIRE_HSM_CUPDATE_SIG_REQ:
|
||||
return handle_channel_update_sig(conn, dc);
|
||||
|
||||
case WIRE_HSM_ECDH_RESP:
|
||||
case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY:
|
||||
case WIRE_HSM_CUPDATE_SIG_REPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
daemon_conn_send(c->master,
|
||||
take(towire_hsmstatus_client_bad_request(c,
|
||||
c->id,
|
||||
dc->msg_in)));
|
||||
return io_close(conn);
|
||||
}
|
||||
|
||||
/* Control messages */
|
||||
static void send_init_response(struct daemon_conn *master)
|
||||
{
|
||||
struct pubkey node_id;
|
||||
struct secret peer_seed;
|
||||
u8 *msg;
|
||||
|
||||
hkdf_sha256(&peer_seed, sizeof(peer_seed), NULL, 0,
|
||||
&secretstuff.hsm_secret,
|
||||
sizeof(secretstuff.hsm_secret),
|
||||
"peer seed", strlen("peer seed"));
|
||||
node_key(NULL, &node_id);
|
||||
|
||||
msg = towire_hsmctl_init_reply(master, &node_id, &peer_seed,
|
||||
&secretstuff.bip32);
|
||||
daemon_conn_send(master, take(msg));
|
||||
}
|
||||
|
||||
static void populate_secretstuff(void)
|
||||
{
|
||||
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
|
||||
u32 salt = 0;
|
||||
struct ext_key master_extkey, child_extkey;
|
||||
|
||||
/* Fill in the BIP32 tree for bitcoin addresses. */
|
||||
do {
|
||||
hkdf_sha256(bip32_seed, sizeof(bip32_seed),
|
||||
&salt, sizeof(salt),
|
||||
&secretstuff.hsm_secret,
|
||||
sizeof(secretstuff.hsm_secret),
|
||||
"bip32 seed", strlen("bip32 seed"));
|
||||
salt++;
|
||||
} while (bip32_key_from_seed(bip32_seed, sizeof(bip32_seed),
|
||||
BIP32_VER_TEST_PRIVATE,
|
||||
0, &master_extkey) != WALLY_OK);
|
||||
|
||||
/* BIP 32:
|
||||
*
|
||||
* The default wallet layout
|
||||
*
|
||||
* An HDW is organized as several 'accounts'. Accounts are numbered,
|
||||
* the default account ("") being number 0. Clients are not required
|
||||
* to support more than one account - if not, they only use the
|
||||
* default account.
|
||||
*
|
||||
* Each account is composed of two keypair chains: an internal and an
|
||||
* external one. The external keychain is used to generate new public
|
||||
* addresses, while the internal keychain is used for all other
|
||||
* operations (change addresses, generation addresses, ..., anything
|
||||
* that doesn't need to be communicated). Clients that do not support
|
||||
* separate keychains for these should use the external one for
|
||||
* everything.
|
||||
*
|
||||
* - m/iH/0/k corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.
|
||||
*/
|
||||
/* Hence child 0, then child 0 again to get extkey to derive from. */
|
||||
if (bip32_key_from_parent(&master_extkey, 0, BIP32_FLAG_KEY_PRIVATE,
|
||||
&child_extkey) != WALLY_OK)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"Can't derive child bip32 key");
|
||||
|
||||
if (bip32_key_from_parent(&child_extkey, 0, BIP32_FLAG_KEY_PRIVATE,
|
||||
&secretstuff.bip32) != WALLY_OK)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"Can't derive private bip32 key");
|
||||
}
|
||||
|
||||
static void bitcoin_pubkey(struct pubkey *pubkey, u32 index)
|
||||
{
|
||||
struct ext_key ext;
|
||||
|
||||
if (index >= BIP32_INITIAL_HARDENED_CHILD)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"Index %u too great", index);
|
||||
|
||||
if (bip32_key_from_parent(&secretstuff.bip32, index,
|
||||
BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"BIP32 of %u failed", index);
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey->pubkey,
|
||||
ext.pub_key, sizeof(ext.pub_key)))
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"Parse of BIP32 child %u pubkey failed", index);
|
||||
}
|
||||
|
||||
static void bitcoin_keypair(struct privkey *privkey,
|
||||
struct pubkey *pubkey,
|
||||
u32 index)
|
||||
{
|
||||
struct ext_key ext;
|
||||
|
||||
if (index >= BIP32_INITIAL_HARDENED_CHILD)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"Index %u too great", index);
|
||||
|
||||
if (bip32_key_from_parent(&secretstuff.bip32, index,
|
||||
BIP32_FLAG_KEY_PRIVATE, &ext) != WALLY_OK)
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"BIP32 of %u failed", index);
|
||||
|
||||
/* libwally says: The private key with prefix byte 0 */
|
||||
memcpy(privkey->secret.data, ext.priv_key+1, 32);
|
||||
if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &pubkey->pubkey,
|
||||
privkey->secret.data))
|
||||
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
|
||||
"BIP32 pubkey %u create failed", index);
|
||||
}
|
||||
|
||||
static void create_new_hsm(struct daemon_conn *master)
|
||||
{
|
||||
int fd = open("hsm_secret", O_CREAT|O_EXCL|O_WRONLY, 0400);
|
||||
if (fd < 0)
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"creating: %s", strerror(errno));
|
||||
|
||||
randombytes_buf(&secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret));
|
||||
if (!write_all(fd, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret))) {
|
||||
unlink_noerr("hsm_secret");
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"writing: %s", strerror(errno));
|
||||
}
|
||||
if (fsync(fd) != 0) {
|
||||
unlink_noerr("hsm_secret");
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"fsync: %s", strerror(errno));
|
||||
}
|
||||
if (close(fd) != 0) {
|
||||
unlink_noerr("hsm_secret");
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"closing: %s", strerror(errno));
|
||||
}
|
||||
fd = open(".", O_RDONLY);
|
||||
if (fsync(fd) != 0) {
|
||||
unlink_noerr("hsm_secret");
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"fsyncdir: %s", strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
|
||||
populate_secretstuff();
|
||||
}
|
||||
|
||||
static void load_hsm(struct daemon_conn *master)
|
||||
{
|
||||
int fd = open("hsm_secret", O_RDONLY);
|
||||
if (fd < 0)
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"opening: %s", strerror(errno));
|
||||
if (!read_all(fd, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret)))
|
||||
status_failed(WIRE_HSMSTATUS_INIT_FAILED,
|
||||
"reading: %s", strerror(errno));
|
||||
close(fd);
|
||||
|
||||
populate_secretstuff();
|
||||
}
|
||||
|
||||
static void init_hsm(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
bool new;
|
||||
|
||||
if (!fromwire_hsmctl_init(msg, NULL, &new))
|
||||
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "hsmctl_init: %s",
|
||||
tal_hex(msg, msg));
|
||||
if (new)
|
||||
create_new_hsm(master);
|
||||
else
|
||||
load_hsm(master);
|
||||
|
||||
send_init_response(master);
|
||||
}
|
||||
|
||||
static void pass_hsmfd_ecdh(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
int fds[2];
|
||||
u64 id;
|
||||
|
||||
if (!fromwire_hsmctl_hsmfd_ecdh(msg, NULL, &id))
|
||||
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "bad HSMFD_ECDH");
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0)
|
||||
status_failed(WIRE_HSMSTATUS_FD_FAILED,
|
||||
"creating fds: %s", strerror(errno));
|
||||
|
||||
new_client(master, id, handle_ecdh, fds[0]);
|
||||
daemon_conn_send(master,
|
||||
take(towire_hsmctl_hsmfd_ecdh_fd_reply(master)));
|
||||
daemon_conn_send_fd(master, fds[1]);
|
||||
}
|
||||
|
||||
/* Reply to an incoming request for an HSMFD for a channeld. */
|
||||
static void pass_hsmfd_channeld(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
int fds[2];
|
||||
u64 id;
|
||||
|
||||
if (!fromwire_hsmctl_hsmfd_channeld(msg, NULL, &id))
|
||||
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "bad HSMFD_CHANNELD");
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0)
|
||||
status_failed(WIRE_HSMSTATUS_FD_FAILED,
|
||||
"creating fds: %s", strerror(errno));
|
||||
|
||||
new_client(master, id, handle_channeld, fds[0]);
|
||||
daemon_conn_send(master,
|
||||
take(towire_hsmctl_hsmfd_channeld_reply(master)));
|
||||
daemon_conn_send_fd(master, fds[1]);
|
||||
}
|
||||
|
||||
/* Note that it's the main daemon that asks for the funding signature so it
|
||||
* can broadcast it. */
|
||||
static void sign_funding_tx(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
const tal_t *tmpctx = tal_tmpctx(master);
|
||||
u64 satoshi_out, change_out;
|
||||
u32 change_keyindex;
|
||||
struct pubkey local_pubkey, remote_pubkey;
|
||||
struct utxo *inputs;
|
||||
const struct utxo **utxomap;
|
||||
struct bitcoin_tx *tx;
|
||||
u8 *wscript;
|
||||
secp256k1_ecdsa_signature *sig;
|
||||
u16 outnum;
|
||||
size_t i;
|
||||
struct pubkey changekey;
|
||||
|
||||
/* FIXME: Check fee is "reasonable" */
|
||||
if (!fromwire_hsmctl_sign_funding(tmpctx, msg, NULL,
|
||||
&satoshi_out, &change_out,
|
||||
&change_keyindex, &local_pubkey,
|
||||
&remote_pubkey, &inputs))
|
||||
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "Bad SIGN_FUNDING");
|
||||
|
||||
utxomap = to_utxoptr_arr(tmpctx, inputs);
|
||||
|
||||
if (change_out)
|
||||
bitcoin_pubkey(&changekey, change_keyindex);
|
||||
|
||||
tx = funding_tx(tmpctx, &outnum, utxomap,
|
||||
satoshi_out, &local_pubkey, &remote_pubkey,
|
||||
change_out, &changekey,
|
||||
NULL);
|
||||
|
||||
/* Now generate signatures. */
|
||||
sig = tal_arr(tmpctx, secp256k1_ecdsa_signature, tal_count(inputs));
|
||||
for (i = 0; i < tal_count(inputs); i++) {
|
||||
struct pubkey inkey;
|
||||
struct privkey inprivkey;
|
||||
const struct utxo *in = utxomap[i];
|
||||
u8 *subscript;
|
||||
|
||||
bitcoin_keypair(&inprivkey, &inkey, in->keyindex);
|
||||
if (in->is_p2sh)
|
||||
subscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, &inkey);
|
||||
else
|
||||
subscript = NULL;
|
||||
wscript = p2wpkh_scriptcode(tmpctx, &inkey);
|
||||
|
||||
sign_tx_input(tx, i, subscript, wscript,
|
||||
&inprivkey, &inkey, &sig[i]);
|
||||
}
|
||||
|
||||
daemon_conn_send(master,
|
||||
take(towire_hsmctl_sign_funding_reply(tmpctx, sig)));
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* sign_withdrawal_tx - Generate and sign a withdrawal transaction from the master
|
||||
*/
|
||||
static void sign_withdrawal_tx(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
const tal_t *tmpctx = tal_tmpctx(master);
|
||||
u64 satoshi_out, change_out;
|
||||
u32 change_keyindex;
|
||||
struct bitcoin_address destination;
|
||||
struct utxo *utxos;
|
||||
secp256k1_ecdsa_signature *sigs;
|
||||
u8 *wscript;
|
||||
struct bitcoin_tx *tx;
|
||||
struct ext_key ext;
|
||||
struct pubkey changekey;
|
||||
|
||||
if (!fromwire_hsmctl_sign_withdrawal(tmpctx, msg, NULL, &satoshi_out,
|
||||
&change_out, &change_keyindex,
|
||||
destination.addr.u.u8, &utxos)) {
|
||||
status_trace("Failed to parse sign_withdrawal: %s",
|
||||
tal_hex(trc, msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bip32_key_from_parent(&secretstuff.bip32, change_keyindex,
|
||||
BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK) {
|
||||
status_trace("Failed to parse sign_withdrawal: %s",
|
||||
tal_hex(trc, msg));
|
||||
return;
|
||||
}
|
||||
|
||||
pubkey_from_der(ext.pub_key, sizeof(ext.pub_key), &changekey);
|
||||
tx = withdraw_tx(
|
||||
tmpctx, to_utxoptr_arr(tmpctx, utxos), &destination, satoshi_out,
|
||||
&changekey, change_out, NULL);
|
||||
|
||||
/* Now generate signatures. */
|
||||
sigs = tal_arr(tmpctx, secp256k1_ecdsa_signature, 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;
|
||||
|
||||
bitcoin_keypair(&inprivkey, &inkey, in->keyindex);
|
||||
/* We know these are p2sh since that's the only kind we handle */
|
||||
subscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, &inkey);
|
||||
wscript = p2wpkh_scriptcode(tmpctx, &inkey);
|
||||
|
||||
sign_tx_input(tx, i, subscript, wscript,
|
||||
&inprivkey, &inkey, &sigs[i]);
|
||||
}
|
||||
|
||||
daemon_conn_send(master,
|
||||
take(towire_hsmctl_sign_withdrawal_reply(tmpctx, sigs)));
|
||||
tal_free(tmpctx);
|
||||
}
|
||||
|
||||
static void sign_node_announcement(struct daemon_conn *master, const u8 *msg)
|
||||
{
|
||||
/* 2 bytes msg type + 64 bytes signature */
|
||||
size_t offset = 66;
|
||||
struct sha256_double hash;
|
||||
struct privkey node_pkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
u8 *reply;
|
||||
u8 *ann;
|
||||
|
||||
if (!fromwire_hsmctl_node_announcement_sig_req(msg, msg, NULL, &ann)) {
|
||||
status_trace("Failed to parse node_announcement_sig_req: %s",
|
||||
tal_hex(trc, msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tal_len(ann) < offset) {
|
||||
status_trace("Node announcement too short: %s", tal_hex(trc, msg));
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME(cdecker) Check the node announcement's content */
|
||||
node_key(&node_pkey, NULL);
|
||||
sha256_double(&hash, ann + offset, tal_len(ann) - offset);
|
||||
|
||||
sign_hash(&node_pkey, &hash, &sig);
|
||||
|
||||
reply = towire_hsmctl_node_announcement_sig_reply(msg, &sig);
|
||||
daemon_conn_send(master, take(reply));
|
||||
}
|
||||
|
||||
static struct io_plan *control_received_req(struct io_conn *conn,
|
||||
struct daemon_conn *master)
|
||||
{
|
||||
enum hsm_wire_type t = fromwire_peektype(master->msg_in);
|
||||
|
||||
status_trace("Control: type %s len %zu",
|
||||
hsm_wire_type_name(t), tal_count(master->msg_in));
|
||||
|
||||
switch (t) {
|
||||
case WIRE_HSMCTL_INIT:
|
||||
init_hsm(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
case WIRE_HSMCTL_HSMFD_ECDH:
|
||||
pass_hsmfd_ecdh(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
case WIRE_HSMCTL_HSMFD_CHANNELD:
|
||||
pass_hsmfd_channeld(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
case WIRE_HSMCTL_SIGN_FUNDING:
|
||||
sign_funding_tx(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
|
||||
case WIRE_HSMCTL_SIGN_WITHDRAWAL:
|
||||
sign_withdrawal_tx(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
|
||||
case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REQ:
|
||||
sign_node_announcement(master, master->msg_in);
|
||||
return daemon_conn_read_next(conn, master);
|
||||
|
||||
case WIRE_HSMCTL_INIT_REPLY:
|
||||
case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY:
|
||||
case WIRE_HSMCTL_HSMFD_CHANNELD_REPLY:
|
||||
case WIRE_HSMCTL_SIGN_FUNDING_REPLY:
|
||||
case WIRE_HSMCTL_SIGN_WITHDRAWAL_REPLY:
|
||||
case WIRE_HSMSTATUS_INIT_FAILED:
|
||||
case WIRE_HSMSTATUS_WRITEMSG_FAILED:
|
||||
case WIRE_HSMSTATUS_BAD_REQUEST:
|
||||
case WIRE_HSMSTATUS_FD_FAILED:
|
||||
case WIRE_HSMSTATUS_KEY_FAILED:
|
||||
case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST:
|
||||
case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Control shouldn't give bad requests. */
|
||||
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "%i", t);
|
||||
}
|
||||
|
||||
#ifndef TESTING
|
||||
static void master_gone(struct io_conn *unused, struct daemon_conn *dc)
|
||||
{
|
||||
/* Can't tell master, it's gone. */
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct daemon_conn *master;
|
||||
|
||||
if (argc == 2 && streq(argv[1], "--version")) {
|
||||
printf("%s\n", version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
breakpoint();
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
master = tal(NULL, struct daemon_conn);
|
||||
daemon_conn_init(master, master, STDIN_FILENO, control_received_req,
|
||||
master_gone);
|
||||
status_setup_async(master);
|
||||
|
||||
/* When conn closes, everything is freed. */
|
||||
tal_steal(master->conn, master);
|
||||
io_loop(NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
# Give me ECDH(node-id-secret,point)
|
||||
hsm_ecdh_req,1
|
||||
hsm_ecdh_req,,point,struct pubkey
|
||||
hsm_ecdh_resp,100
|
||||
hsm_ecdh_resp,,ss,struct secret
|
||||
|
||||
hsm_cannouncement_sig_req,2
|
||||
hsm_cannouncement_sig_req,,bitcoin_id,struct pubkey
|
||||
hsm_cannouncement_sig_req,,calen,u16
|
||||
hsm_cannouncement_sig_req,,ca,calen
|
||||
|
||||
hsm_cannouncement_sig_reply,102
|
||||
hsm_cannouncement_sig_reply,,node_signature,64
|
||||
|
||||
hsm_cupdate_sig_req,3
|
||||
hsm_cupdate_sig_req,,culen,u16
|
||||
hsm_cupdate_sig_req,,cu,culen
|
||||
|
||||
hsm_cupdate_sig_reply,103
|
||||
hsm_cupdate_sig_reply,,culen,u16
|
||||
hsm_cupdate_sig_reply,,cu,culen
|
||||
@@ -1,73 +0,0 @@
|
||||
# These are fatal.
|
||||
hsmstatus_init_failed,0x8000
|
||||
hsmstatus_writemsg_failed,0x8001
|
||||
hsmstatus_bad_request,0x8002
|
||||
hsmstatus_fd_failed,0x8003
|
||||
hsmstatus_key_failed,0x8004
|
||||
|
||||
# Clients should not give a bad request but not the HSM's decision to crash.
|
||||
hsmstatus_client_bad_request,1000
|
||||
hsmstatus_client_bad_request,,unique_id,8
|
||||
hsmstatus_client_bad_request,,len,2
|
||||
hsmstatus_client_bad_request,,msg,len*u8
|
||||
|
||||
# Start the HSM.
|
||||
hsmctl_init,1
|
||||
hsmctl_init,,new,bool
|
||||
|
||||
#include <common/bip32.h>
|
||||
hsmctl_init_reply,101
|
||||
hsmctl_init_reply,,node_id,33
|
||||
hsmctl_init_reply,,peer_seed,struct secret
|
||||
hsmctl_init_reply,,bip32,struct ext_key
|
||||
|
||||
# ECDH returns an fd.
|
||||
hsmctl_hsmfd_ecdh,3
|
||||
hsmctl_hsmfd_ecdh,,unique_id,8
|
||||
|
||||
# No contents, just an fd.
|
||||
hsmctl_hsmfd_ecdh_fd_reply,103
|
||||
|
||||
# Return signature for a funding tx.
|
||||
#include <common/utxo.h>
|
||||
# FIXME: This should also take their commit sig & details, to verify.
|
||||
hsmctl_sign_funding,4
|
||||
hsmctl_sign_funding,,satoshi_out,8
|
||||
hsmctl_sign_funding,,change_out,8
|
||||
hsmctl_sign_funding,,change_keyindex,4
|
||||
hsmctl_sign_funding,,our_pubkey,33
|
||||
hsmctl_sign_funding,,their_pubkey,33
|
||||
hsmctl_sign_funding,,num_inputs,2
|
||||
hsmctl_sign_funding,,inputs,num_inputs*struct utxo
|
||||
|
||||
hsmctl_sign_funding_reply,104
|
||||
hsmctl_sign_funding_reply,,num_sigs,2
|
||||
hsmctl_sign_funding_reply,,sig,num_sigs*secp256k1_ecdsa_signature
|
||||
|
||||
# Request a client socket for a `channeld`, allows signing announcements
|
||||
hsmctl_hsmfd_channeld,5
|
||||
hsmctl_hsmfd_channeld,,unique_id,8
|
||||
|
||||
# Empty reply, just an fd
|
||||
hsmctl_hsmfd_channeld_reply,105
|
||||
|
||||
# Master asks the HSM to sign a node_announcement
|
||||
hsmctl_node_announcement_sig_req,6
|
||||
hsmctl_node_announcement_sig_req,,annlen,2
|
||||
hsmctl_node_announcement_sig_req,,announcement,annlen*u8
|
||||
|
||||
hsmctl_node_announcement_sig_reply,106
|
||||
hsmctl_node_announcement_sig_reply,,signature,secp256k1_ecdsa_signature
|
||||
|
||||
# Sign a withdrawal request
|
||||
hsmctl_sign_withdrawal,7
|
||||
hsmctl_sign_withdrawal,,satoshi_out,8
|
||||
hsmctl_sign_withdrawal,,change_out,8
|
||||
hsmctl_sign_withdrawal,,change_keyindex,4
|
||||
hsmctl_sign_withdrawal,,pkh,20*u8
|
||||
hsmctl_sign_withdrawal,,num_inputs,2
|
||||
hsmctl_sign_withdrawal,,inputs,num_inputs*struct utxo
|
||||
|
||||
hsmctl_sign_withdrawal_reply,107
|
||||
hsmctl_sign_withdrawal_reply,,num_sigs,2
|
||||
hsmctl_sign_withdrawal_reply,,sig,num_sigs*secp256k1_ecdsa_signature
|
||||
|
@@ -7,8 +7,8 @@
|
||||
#include <common/status.h>
|
||||
#include <common/utils.h>
|
||||
#include <errno.h>
|
||||
#include <hsmd/gen_hsm_wire.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/hsm/gen_hsm_wire.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <string.h>
|
||||
#include <wally_bip32.h>
|
||||
@@ -36,7 +36,7 @@ void hsm_init(struct lightningd *ld, bool newdir)
|
||||
u8 *msg;
|
||||
bool create;
|
||||
|
||||
ld->hsm_fd = subd_raw(ld, "lightningd_hsm");
|
||||
ld->hsm_fd = subd_raw(ld, "lightning_hsmd");
|
||||
if (ld->hsm_fd < 0)
|
||||
err(1, "Could not subd hsm");
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#include <lightningd/invoice.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/onchain/onchain_wire.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <onchaind/onchain_wire.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -100,12 +100,13 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
||||
|
||||
static const char *daemons[] = {
|
||||
"lightningd",
|
||||
"lightningd_channel",
|
||||
"lightningd_closing",
|
||||
"lightningd_gossip",
|
||||
"lightningd_handshake",
|
||||
"lightningd_hsm",
|
||||
"lightningd_opening"
|
||||
"lightning_channeld",
|
||||
"lightning_closingd",
|
||||
"lightning_gossipd",
|
||||
"lightning_handshaked",
|
||||
"lightning_hsmd",
|
||||
"lightning_onchaind",
|
||||
"lightning_openingd"
|
||||
};
|
||||
|
||||
/* Check we can run them, and check their versions */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <common/cryptomsg.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <lightningd/handshake/gen_handshake_wire.h>
|
||||
#include <lightningd/hsm/gen_hsm_wire.h>
|
||||
#include <handshaked/gen_handshake_wire.h>
|
||||
#include <hsmd/gen_hsm_wire.h>
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
@@ -221,7 +221,7 @@ static struct io_plan *hsm_then_handshake(struct io_conn *conn,
|
||||
|
||||
/* Give handshake daemon the hsm fd. */
|
||||
handshaked = new_subd(ld, ld,
|
||||
"lightningd_handshake", NULL,
|
||||
"lightning_handshaked", NULL,
|
||||
handshake_wire_type_name,
|
||||
NULL, NULL,
|
||||
take(&hsmfd), take(&connfd), NULL);
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
lightningd/onchain-wrongdir:
|
||||
$(MAKE) -C ../.. lightningd/onchain-all
|
||||
|
||||
default: lightningd/onchain-all
|
||||
|
||||
lightningd/onchain-all: lightningd/lightningd_onchain
|
||||
|
||||
lightningd/onchain/gen_onchain_types_names.h: lightningd/onchain/onchain_types.h ccan/ccan/cdump/tools/cdump-enumstr
|
||||
ccan/ccan/cdump/tools/cdump-enumstr lightningd/onchain/onchain_types.h > $@
|
||||
|
||||
# lightningd/onchain needs these:
|
||||
LIGHTNINGD_ONCHAIN_HEADERS_GEN := \
|
||||
lightningd/onchain/gen_onchain_wire.h \
|
||||
lightningd/onchain/gen_onchain_types_names.h
|
||||
|
||||
LIGHTNINGD_ONCHAIN_HEADERS_NOGEN := \
|
||||
lightningd/onchain/onchain_types.h \
|
||||
lightningd/onchain/onchain_wire.h
|
||||
|
||||
LIGHTNINGD_ONCHAIN_HEADERS := $(LIGHTNINGD_ONCHAIN_HEADERS_GEN) $(LIGHTNINGD_ONCHAIN_HEADERS_NOGEN)
|
||||
|
||||
LIGHTNINGD_ONCHAIN_SRC := lightningd/onchain/onchain.c \
|
||||
lightningd/onchain/gen_onchain_wire.c \
|
||||
lightningd/onchain/onchain_wire.c
|
||||
|
||||
LIGHTNINGD_ONCHAIN_OBJS := $(LIGHTNINGD_ONCHAIN_SRC:.c=.o)
|
||||
|
||||
# Control daemon uses this:
|
||||
LIGHTNINGD_ONCHAIN_CONTROL_HEADERS := \
|
||||
lightningd/onchain/gen_onchain_wire.h \
|
||||
lightningd/onchain/onchain_wire.h
|
||||
LIGHTNINGD_ONCHAIN_CONTROL_SRC := $(LIGHTNINGD_ONCHAIN_CONTROL_HEADERS:.h=.c)
|
||||
LIGHTNINGD_ONCHAIN_CONTROL_OBJS := $(LIGHTNINGD_ONCHAIN_CONTROL_SRC:.c=.o)
|
||||
|
||||
LIGHTNINGD_ONCHAIN_GEN_SRC := $(filter lightningd/onchain/gen_%, $(LIGHTNINGD_ONCHAIN_SRC) $(LIGHTNINGD_ONCHAIN_CONTROL_SRC))
|
||||
|
||||
LIGHTNINGD_ONCHAIN_SRC_NOGEN := $(filter-out lightningd/onchain/gen_%, $(LIGHTNINGD_ONCHAIN_SRC))
|
||||
|
||||
# Add to headers which any object might need.
|
||||
LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_ONCHAIN_HEADERS_GEN)
|
||||
LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_ONCHAIN_HEADERS_NOGEN)
|
||||
|
||||
$(LIGHTNINGD_ONCHAIN_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
# Common source we use.
|
||||
ONCHAIND_COMMON_OBJS := \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/derive_basepoints.o \
|
||||
common/dev_disconnect.o \
|
||||
common/htlc_tx.o \
|
||||
common/htlc_wire.o \
|
||||
common/initial_commit_tx.o \
|
||||
common/keyset.o \
|
||||
common/key_derive.o \
|
||||
common/msg_queue.o \
|
||||
common/permute_tx.o \
|
||||
common/status.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/version.o
|
||||
|
||||
lightningd/onchain/gen_onchain_wire.h: $(WIRE_GEN) lightningd/onchain/onchain_wire.csv
|
||||
$(WIRE_GEN) --header $@ onchain_wire_type < lightningd/onchain/onchain_wire.csv > $@
|
||||
|
||||
lightningd/onchain/gen_onchain_wire.c: $(WIRE_GEN) lightningd/onchain/onchain_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} onchain_wire_type < lightningd/onchain/onchain_wire.csv > $@
|
||||
|
||||
LIGHTNINGD_ONCHAIN_OBJS := $(LIGHTNINGD_ONCHAIN_SRC:.c=.o) $(LIGHTNINGD_ONCHAIN_GEN_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_ONCHAIN_OBJS)
|
||||
|
||||
lightningd/lightningd_onchain: $(LIGHTNINGD_ONCHAIN_OBJS) $(WIRE_ONION_OBJS) $(ONCHAIND_COMMON_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS)
|
||||
|
||||
check-source: $(LIGHTNINGD_ONCHAIN_SRC_NOGEN:%=check-src-include-order/%)
|
||||
check-source-bolt: $(LIGHTNINGD_ONCHAIN_SRC:%=bolt-check/%) $(LIGHTNINGD_ONCHAIN_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-whitespace: $(LIGHTNINGD_ONCHAIN_SRC_NOGEN:%=check-whitespace/%) $(LIGHTNINGD_ONCHAIN_HEADERS_NOGEN:%=check-whitespace/%)
|
||||
|
||||
clean: lightningd/onchain-clean
|
||||
|
||||
lightningd/onchain-clean:
|
||||
$(RM) $(LIGHTNINGD_ONCHAIN_OBJS) gen_*
|
||||
|
||||
-include lightningd/onchain/test/Makefile
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,54 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_TYPES_H
|
||||
#define LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_TYPES_H
|
||||
#include "config.h"
|
||||
|
||||
/* Different transactions we care about. */
|
||||
enum tx_type {
|
||||
/* The initial 2 of 2 funding transaction */
|
||||
FUNDING_TRANSACTION,
|
||||
|
||||
/* A mutual close: spends funding */
|
||||
MUTUAL_CLOSE,
|
||||
|
||||
/* Their unilateral: spends funding */
|
||||
THEIR_UNILATERAL,
|
||||
|
||||
/* Our unilateral: spends funding */
|
||||
OUR_UNILATERAL,
|
||||
|
||||
/* The 2 different types of HTLC transaction, each way */
|
||||
THEIR_HTLC_TIMEOUT_TO_THEM,
|
||||
THEIR_HTLC_FULFILL_TO_US,
|
||||
OUR_HTLC_TIMEOUT_TO_US,
|
||||
OUR_HTLC_FULFILL_TO_THEM,
|
||||
|
||||
/* When we spend the to-us output (after cltv_expiry) */
|
||||
OUR_UNILATERAL_TO_US_RETURN_TO_WALLET,
|
||||
|
||||
/* Special type for marking outputs as resolved by self. */
|
||||
SELF,
|
||||
|
||||
/* Shouldn't happen. */
|
||||
UNKNOWN_TXTYPE
|
||||
};
|
||||
|
||||
/* Different output types. */
|
||||
enum output_type {
|
||||
/* FUNDING_TRANSACTION */
|
||||
FUNDING_OUTPUT,
|
||||
|
||||
/* THEIR_UNILATERAL */
|
||||
OUTPUT_TO_US,
|
||||
DELAYED_OUTPUT_TO_THEM,
|
||||
|
||||
/* OUR_UNILATERAL */
|
||||
DELAYED_OUTPUT_TO_US,
|
||||
OUTPUT_TO_THEM,
|
||||
|
||||
/* HTLC outputs: their offers and our offers */
|
||||
THEIR_HTLC,
|
||||
OUR_HTLC,
|
||||
};
|
||||
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_TYPES_H */
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <common/htlc_wire.h>
|
||||
#include <lightningd/onchain/onchain_wire.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
void towire_htlc_stub(u8 **pptr, const struct htlc_stub *htlc_stub)
|
||||
{
|
||||
towire_side(pptr, htlc_stub->owner);
|
||||
towire_u32(pptr, htlc_stub->cltv_expiry);
|
||||
towire_ripemd160(pptr, &htlc_stub->ripemd);
|
||||
}
|
||||
|
||||
void fromwire_htlc_stub(const u8 **cursor, size_t *max,
|
||||
struct htlc_stub *htlc_stub)
|
||||
{
|
||||
htlc_stub->owner = fromwire_side(cursor, max);
|
||||
htlc_stub->cltv_expiry = fromwire_u32(cursor, max);
|
||||
fromwire_ripemd160(cursor, max, &htlc_stub->ripemd);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
# Shouldn't happen
|
||||
onchain_bad_command,0x8000
|
||||
onchain_internal_error,0x8003
|
||||
onchain_crypto_failed,0x8004
|
||||
|
||||
#include <common/htlc_wire.h>
|
||||
# Begin! Here's the onchain tx which spends funding tx, followed by all HTLCs.
|
||||
onchain_init,1
|
||||
onchain_init,,seed,struct privkey
|
||||
onchain_init,,shachain,struct shachain
|
||||
onchain_init,,funding_amount_satoshi,u64
|
||||
# Remote per commit point for committed tx.
|
||||
onchain_init,,old_remote_per_commitment_point,struct pubkey
|
||||
# Remote per commit point for current tx (needed if we haven't got revoke_and_ack yet).
|
||||
onchain_init,,remote_per_commitment_point,struct pubkey
|
||||
onchain_init,,local_to_self_delay,u32
|
||||
onchain_init,,remote_to_self_delay,u32
|
||||
onchain_init,,feerate_per_kw,u64
|
||||
onchain_init,,local_dust_limit_satoshi,u64
|
||||
onchain_init,,remote_revocation_basepoint,struct pubkey
|
||||
# Gives an easy way to tell if it's our unilateral close or theirs...
|
||||
onchain_init,,our_broadcast_txid,struct sha256_double
|
||||
onchain_init,,local_scriptpubkey_len,u16
|
||||
onchain_init,,local_scriptpubkey,local_scriptpubkey_len*u8
|
||||
onchain_init,,remote_scriptpubkey_len,u16
|
||||
onchain_init,,remote_scriptpubkey,remote_scriptpubkey_len*u8
|
||||
onchain_init,,ourwallet_pubkey,struct pubkey
|
||||
# We need these two for commit number obscurer
|
||||
onchain_init,,funder,enum side
|
||||
onchain_init,,remote_payment_basepoint,struct pubkey
|
||||
onchain_init,,remote_delayed_payment_basepoint,struct pubkey
|
||||
onchain_init,,tx,struct bitcoin_tx
|
||||
onchain_init,,tx_blockheight,u32
|
||||
onchain_init,,num_htlc_sigs,u16
|
||||
onchain_init,,htlc_signature,num_htlc_sigs*secp256k1_ecdsa_signature
|
||||
onchain_init,,num_htlcs,u64
|
||||
|
||||
#include <lightningd/onchain/onchain_wire.h>
|
||||
# This is all the HTLCs: one per message
|
||||
onchain_htlc,2
|
||||
onchain_htlc,,htlc,struct htlc_stub
|
||||
|
||||
# This sets what the state is, depending on tx.
|
||||
onchain_init_reply,101
|
||||
onchain_init_reply,,state,u8
|
||||
|
||||
# onchaind->master: Send out a tx.
|
||||
onchain_broadcast_tx,3
|
||||
onchain_broadcast_tx,,tx,struct bitcoin_tx
|
||||
|
||||
# master->onchaind: Notifier that an output has been spent by input_num of tx.
|
||||
onchain_spent,4
|
||||
onchain_spent,,tx,struct bitcoin_tx
|
||||
onchain_spent,,input_num,u32
|
||||
onchain_spent,,blockheight,u32
|
||||
|
||||
# master->onchaind: We will receive more than one of these, as depth changes.
|
||||
onchain_depth,5
|
||||
onchain_depth,,txid,struct sha256_double
|
||||
onchain_depth,,depth,u32
|
||||
|
||||
# onchaind->master: We don't want to watch this tx, or its outputs
|
||||
onchain_unwatch_tx,6
|
||||
onchain_unwatch_tx,,txid,struct sha256_double
|
||||
onchain_unwatch_tx,,num_outputs,u32
|
||||
|
||||
# master->onchaind: We know HTLC preimage
|
||||
onchain_known_preimage,7
|
||||
onchain_known_preimage,,preimage,struct preimage
|
||||
|
||||
# onchaind->master: We discovered HTLC preimage
|
||||
onchain_extracted_preimage,8
|
||||
onchain_extracted_preimage,,preimage,struct preimage
|
||||
|
||||
|
@@ -1,18 +0,0 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_WIRE_H
|
||||
#define LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_WIRE_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <common/htlc.h>
|
||||
|
||||
/* The minimal info about an htlc. */
|
||||
struct htlc_stub {
|
||||
enum side owner;
|
||||
u32 cltv_expiry;
|
||||
struct ripemd160 ripemd;
|
||||
};
|
||||
|
||||
void towire_htlc_stub(u8 **pptr, const struct htlc_stub *htlc_stub);
|
||||
void fromwire_htlc_stub(const u8 **cursor, size_t *max,
|
||||
struct htlc_stub *htlc_stub);
|
||||
#endif /* LIGHTNING_LIGHTNINGD_ONCHAIN_ONCHAIN_WIRE_H */
|
||||
@@ -1,88 +0,0 @@
|
||||
#! /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_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)
|
||||
|
||||
# Common source we use.
|
||||
OPENINGD_COMMON_OBJS := \
|
||||
common/bip32.o \
|
||||
common/channel_config.o \
|
||||
common/crypto_sync.o \
|
||||
common/cryptomsg.o \
|
||||
common/daemon_conn.o \
|
||||
common/debug.o \
|
||||
common/derive_basepoints.o \
|
||||
common/dev_disconnect.o \
|
||||
common/funding_tx.o \
|
||||
common/htlc_wire.o \
|
||||
common/initial_channel.o \
|
||||
common/initial_commit_tx.o \
|
||||
common/key_derive.o \
|
||||
common/keyset.o \
|
||||
common/msg_queue.o \
|
||||
common/ping.o \
|
||||
common/peer_failed.o \
|
||||
common/permute_tx.o \
|
||||
common/pseudorand.o \
|
||||
common/status.o \
|
||||
common/type_to_string.o \
|
||||
common/utils.o \
|
||||
common/utxo.o \
|
||||
common/version.o
|
||||
|
||||
$(LIGHTNINGD_OPENING_OBJS): $(LIGHTNINGD_HEADERS)
|
||||
|
||||
lightningd/opening/gen_opening_wire.h: $(WIRE_GEN) lightningd/opening/opening_wire.csv
|
||||
$(WIRE_GEN) --header $@ opening_wire_type < lightningd/opening/opening_wire.csv > $@
|
||||
|
||||
lightningd/opening/gen_opening_wire.c: $(WIRE_GEN) lightningd/opening/opening_wire.csv
|
||||
$(WIRE_GEN) ${@:.c=.h} opening_wire_type < lightningd/opening/opening_wire.csv > $@
|
||||
|
||||
LIGHTNINGD_OPENING_OBJS := $(LIGHTNINGD_OPENING_SRC:.c=.o) $(LIGHTNINGD_OPENING_GEN_SRC:.c=.o)
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_OBJS += $(LIGHTNINGD_OPENING_OBJS)
|
||||
|
||||
lightningd/lightningd_opening: $(LIGHTNINGD_OPENING_OBJS) $(OPENINGD_COMMON_OBJS) $(WIRE_OBJS) $(BITCOIN_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS)
|
||||
|
||||
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
|
||||
@@ -1,766 +0,0 @@
|
||||
#include <bitcoin/block.h>
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/breakpoint/breakpoint.h>
|
||||
#include <ccan/fdpass/fdpass.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <common/crypto_sync.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/derive_basepoints.h>
|
||||
#include <common/funding_tx.h>
|
||||
#include <common/initial_channel.h>
|
||||
#include <common/key_derive.h>
|
||||
#include <common/peer_failed.h>
|
||||
#include <common/ping.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/version.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/opening/gen_opening_wire.h>
|
||||
#include <secp256k1.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <wally_bip32.h>
|
||||
#include <wire/gen_peer_wire.h>
|
||||
#include <wire/peer_wire.h>
|
||||
#include <wire/wire.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
/* stdin == requests, 3 == peer, 4 == gossip */
|
||||
#define REQ_FD STDIN_FILENO
|
||||
#define PEER_FD 3
|
||||
#define GOSSIP_FD 4
|
||||
|
||||
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;
|
||||
u16 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;
|
||||
|
||||
/* Limits on what remote config we accept */
|
||||
u32 max_to_self_delay;
|
||||
u64 min_effective_htlc_capacity_msat;
|
||||
|
||||
struct channel *channel;
|
||||
|
||||
const struct chainparams *chainparams;
|
||||
};
|
||||
|
||||
static void check_config_bounds(struct state *state,
|
||||
const struct channel_config *remoteconf)
|
||||
{
|
||||
u64 capacity_msat;
|
||||
u64 reserve_msat;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiving node MUST fail the channel if `to_self_delay` is
|
||||
* unreasonably large.
|
||||
*/
|
||||
if (remoteconf->to_self_delay > state->max_to_self_delay)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"to_self_delay %u larger than %u",
|
||||
remoteconf->to_self_delay, state->max_to_self_delay);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver MAY fail the channel if `funding_satoshis` is too
|
||||
* small, and MUST fail the channel if `push_msat` is greater than
|
||||
* `funding_satoshis` * 1000. The receiving node MAY fail the channel
|
||||
* if it considers `htlc_minimum_msat` too large,
|
||||
* `max_htlc_value_in_flight_msat` too small, `channel_reserve_satoshis`
|
||||
* too large, or `max_accepted_htlcs` too small.
|
||||
*/
|
||||
/* We accumulate this into an effective bandwidth minimum. */
|
||||
|
||||
/* Overflow check before capacity calc. */
|
||||
if (remoteconf->channel_reserve_satoshis > state->funding_satoshis)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"Invalid channel_reserve_satoshis %"PRIu64
|
||||
" for funding_satoshis %"PRIu64,
|
||||
remoteconf->channel_reserve_satoshis,
|
||||
state->funding_satoshis);
|
||||
|
||||
/* Consider highest reserve. */
|
||||
reserve_msat = remoteconf->channel_reserve_satoshis * 1000;
|
||||
if (state->localconf.channel_reserve_satoshis * 1000 > reserve_msat)
|
||||
reserve_msat = state->localconf.channel_reserve_satoshis * 1000;
|
||||
|
||||
capacity_msat = state->funding_satoshis * 1000 - reserve_msat;
|
||||
|
||||
if (remoteconf->max_htlc_value_in_flight_msat < capacity_msat)
|
||||
capacity_msat = remoteconf->max_htlc_value_in_flight_msat;
|
||||
|
||||
if (remoteconf->htlc_minimum_msat * (u64)1000 > capacity_msat)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"Invalid htlc_minimum_msat %"PRIu64
|
||||
" for funding_satoshis %"PRIu64
|
||||
" capacity_msat %"PRIu64,
|
||||
remoteconf->htlc_minimum_msat,
|
||||
state->funding_satoshis,
|
||||
capacity_msat);
|
||||
|
||||
if (capacity_msat < state->min_effective_htlc_capacity_msat)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"Channel capacity with funding %"PRIu64" msat,"
|
||||
" reserves %"PRIu64"/%"PRIu64" msat,"
|
||||
" max_htlc_value_in_flight_msat %"PRIu64
|
||||
" is %"PRIu64" msat, which is below %"PRIu64" msat",
|
||||
state->funding_satoshis * 1000,
|
||||
remoteconf->channel_reserve_satoshis * 1000,
|
||||
state->localconf.channel_reserve_satoshis * 1000,
|
||||
remoteconf->max_htlc_value_in_flight_msat,
|
||||
capacity_msat,
|
||||
state->min_effective_htlc_capacity_msat);
|
||||
|
||||
/* We don't worry about how many HTLCs they accept, as long as > 0! */
|
||||
if (remoteconf->max_accepted_htlcs == 0)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"max_accepted_htlcs %u invalid",
|
||||
remoteconf->max_accepted_htlcs);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* It MUST fail the channel if `max_accepted_htlcs` is greater
|
||||
* than 483.
|
||||
*/
|
||||
if (remoteconf->max_accepted_htlcs > 483)
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_CONFIG,
|
||||
"max_accepted_htlcs %u too large",
|
||||
remoteconf->max_accepted_htlcs);
|
||||
}
|
||||
|
||||
/* We always set channel_reserve_satoshis to 1%, rounded up. */
|
||||
static void set_reserve(u64 *reserve, u64 funding)
|
||||
{
|
||||
*reserve = (funding + 99) / 100;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A sending node MUST ensure `temporary_channel_id` is unique from any other
|
||||
* channel id with the same peer.
|
||||
*/
|
||||
static void temporary_channel_id(struct channel_id *channel_id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(*channel_id); i++)
|
||||
channel_id->id[i] = pseudorand(256);
|
||||
}
|
||||
|
||||
/* We have to handle random gossip message and pings. */
|
||||
static u8 *read_next_peer_msg(struct state *state, const tal_t *ctx)
|
||||
{
|
||||
for (;;) {
|
||||
u8 *msg = sync_crypto_read(ctx, &state->cs, PEER_FD);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
if (fromwire_peektype(msg) == WIRE_PING) {
|
||||
u8 *pong;
|
||||
if (!check_ping_make_pong(ctx, msg, &pong)) {
|
||||
status_trace("Bad ping message");
|
||||
return tal_free(msg);
|
||||
}
|
||||
if (pong && !sync_crypto_write(&state->cs, PEER_FD,
|
||||
take(pong)))
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_WRITE_FAILED,
|
||||
"Sending pong");
|
||||
} else if (is_gossip_msg(msg)) {
|
||||
/* We relay gossip to gossipd, but don't relay from */
|
||||
if (!wire_sync_write(GOSSIP_FD, take(msg)))
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_WRITE_FAILED,
|
||||
"Relaying gossip message");
|
||||
} else {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 *funder_channel(struct state *state,
|
||||
const struct pubkey *our_funding_pubkey,
|
||||
const struct basepoints *ours,
|
||||
u32 max_minimum_depth,
|
||||
u64 change_satoshis, u32 change_keyindex,
|
||||
u8 channel_flags,
|
||||
const struct utxo *utxos,
|
||||
const struct ext_key *bip32_base)
|
||||
{
|
||||
struct channel_id channel_id, id_in;
|
||||
u8 *msg;
|
||||
struct bitcoin_tx *tx;
|
||||
struct basepoints theirs;
|
||||
struct pubkey their_funding_pubkey, changekey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
u32 minimum_depth;
|
||||
const u8 *wscript;
|
||||
struct bitcoin_tx *funding;
|
||||
const struct utxo **utxomap;
|
||||
|
||||
set_reserve(&state->localconf.channel_reserve_satoshis,
|
||||
state->funding_satoshis);
|
||||
|
||||
temporary_channel_id(&channel_id);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The sender MUST set `funding_satoshis` to less than 2^24 satoshi. */
|
||||
if (state->funding_satoshis >= 1 << 24)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_BAD_PARAM,
|
||||
"push-msat must be < %"PRIu64,
|
||||
1000 * state->funding_satoshis);
|
||||
|
||||
msg = towire_open_channel(state,
|
||||
&state->chainparams->genesis_blockhash,
|
||||
&channel_id,
|
||||
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,
|
||||
our_funding_pubkey,
|
||||
&ours->revocation,
|
||||
&ours->payment,
|
||||
&ours->delayed_payment,
|
||||
&state->next_per_commit[LOCAL],
|
||||
channel_flags);
|
||||
if (!sync_crypto_write(&state->cs, PEER_FD, msg))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_WRITE_FAILED,
|
||||
"Writing open_channel");
|
||||
|
||||
state->remoteconf = tal(state, struct channel_config);
|
||||
|
||||
msg = read_next_peer_msg(state, state);
|
||||
if (!msg)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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, &id_in,
|
||||
&state->remoteconf->dust_limit_satoshis,
|
||||
&state->remoteconf
|
||||
->max_htlc_value_in_flight_msat,
|
||||
&state->remoteconf
|
||||
->channel_reserve_satoshis,
|
||||
&state->remoteconf->htlc_minimum_msat,
|
||||
&minimum_depth,
|
||||
&state->remoteconf->to_self_delay,
|
||||
&state->remoteconf->max_accepted_htlcs,
|
||||
&their_funding_pubkey,
|
||||
&theirs.revocation,
|
||||
&theirs.payment,
|
||||
&theirs.delayed_payment,
|
||||
&state->next_per_commit[REMOTE]))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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(&id_in, &channel_id))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"accept_channel ids don't match: sent %s got %s",
|
||||
type_to_string(msg, struct channel_id, &id_in),
|
||||
type_to_string(msg, struct channel_id, &channel_id));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver MAY reject the `minimum_depth` if it considers it
|
||||
* unreasonably large.
|
||||
*
|
||||
* Other fields have the same requirements as their counterparts in
|
||||
* `open_channel`.
|
||||
*/
|
||||
if (minimum_depth > max_minimum_depth)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_BAD_PARAM,
|
||||
"minimum_depth %u larger than %u",
|
||||
minimum_depth, max_minimum_depth);
|
||||
check_config_bounds(state, state->remoteconf);
|
||||
|
||||
/* Now, ask create funding transaction to pay those two addresses. */
|
||||
if (change_satoshis) {
|
||||
if (!bip32_pubkey(bip32_base, &changekey, change_keyindex))
|
||||
status_failed(WIRE_OPENING_BAD_PARAM,
|
||||
"Bad change key %u", change_keyindex);
|
||||
}
|
||||
|
||||
utxomap = to_utxoptr_arr(state, utxos);
|
||||
funding = funding_tx(state, &state->funding_txout,
|
||||
utxomap, state->funding_satoshis,
|
||||
our_funding_pubkey,
|
||||
&their_funding_pubkey,
|
||||
change_satoshis, &changekey,
|
||||
bip32_base);
|
||||
bitcoin_txid(funding, &state->funding_txid);
|
||||
|
||||
state->channel = new_initial_channel(state,
|
||||
&state->funding_txid,
|
||||
state->funding_txout,
|
||||
state->funding_satoshis,
|
||||
state->funding_satoshis * 1000
|
||||
- state->push_msat,
|
||||
state->feerate_per_kw,
|
||||
&state->localconf,
|
||||
state->remoteconf,
|
||||
ours, &theirs,
|
||||
our_funding_pubkey,
|
||||
&their_funding_pubkey,
|
||||
LOCAL);
|
||||
if (!state->channel)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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 = initial_channel_tx(state, &wscript, state->channel,
|
||||
&state->next_per_commit[REMOTE], REMOTE);
|
||||
|
||||
sign_tx_input(tx, 0, NULL, wscript,
|
||||
&state->our_secrets.funding_privkey,
|
||||
our_funding_pubkey, &sig);
|
||||
status_trace("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, our_funding_pubkey));
|
||||
|
||||
msg = towire_funding_created(state, &channel_id,
|
||||
&state->funding_txid.sha,
|
||||
state->funding_txout,
|
||||
&sig);
|
||||
if (!sync_crypto_write(&state->cs, PEER_FD, msg))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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 = read_next_peer_msg(state, state);
|
||||
if (!msg)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"Reading funding_signed");
|
||||
|
||||
if (!fromwire_funding_signed(msg, NULL, &id_in, &sig))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"Parsing funding_signed (%s)",
|
||||
wire_type_name(fromwire_peektype(msg)));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* This message introduces the `channel_id` to identify the channel, which
|
||||
* is derived from the funding transaction by combining the
|
||||
* `funding_txid` and the `funding_output_index` using big-endian
|
||||
* exclusive-OR (ie. `funding_output_index` alters the last two
|
||||
* bytes).
|
||||
*/
|
||||
derive_channel_id(&channel_id,
|
||||
&state->funding_txid, state->funding_txout);
|
||||
|
||||
if (!structeq(&id_in, &channel_id))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"funding_signed ids don't match: expceted %s got %s",
|
||||
type_to_string(msg, struct channel_id, &channel_id),
|
||||
type_to_string(msg, struct channel_id, &id_in));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The recipient MUST fail the channel if `signature` is incorrect.
|
||||
*/
|
||||
tx = initial_channel_tx(state, &wscript, state->channel,
|
||||
&state->next_per_commit[LOCAL], LOCAL);
|
||||
|
||||
if (!check_tx_sig(tx, 0, NULL, wscript, &their_funding_pubkey, &sig)) {
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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,
|
||||
&their_funding_pubkey));
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* Once the channel funder receives the `funding_signed` message, they
|
||||
* must broadcast the funding transaction to the Bitcoin network.
|
||||
*/
|
||||
return towire_opening_funder_reply(state,
|
||||
state->remoteconf,
|
||||
tx,
|
||||
&sig,
|
||||
&state->cs,
|
||||
&theirs.revocation,
|
||||
&theirs.payment,
|
||||
&theirs.delayed_payment,
|
||||
&state->next_per_commit[REMOTE],
|
||||
minimum_depth,
|
||||
&their_funding_pubkey,
|
||||
&state->funding_txid,
|
||||
state->feerate_per_kw);
|
||||
}
|
||||
|
||||
/* This is handed the message the peer sent which caused gossip to stop:
|
||||
* it should be an open_channel */
|
||||
static u8 *fundee_channel(struct state *state,
|
||||
const struct pubkey *our_funding_pubkey,
|
||||
const struct basepoints *ours,
|
||||
u32 minimum_depth,
|
||||
u32 min_feerate, u32 max_feerate, const u8 *peer_msg)
|
||||
{
|
||||
struct channel_id id_in, channel_id;
|
||||
struct basepoints theirs;
|
||||
struct pubkey their_funding_pubkey;
|
||||
secp256k1_ecdsa_signature theirsig, sig;
|
||||
struct bitcoin_tx *tx;
|
||||
struct sha256_double chain_hash;
|
||||
u8 *msg;
|
||||
const u8 *wscript;
|
||||
u8 channel_flags;
|
||||
|
||||
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, &chain_hash, &channel_id,
|
||||
&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,
|
||||
&their_funding_pubkey,
|
||||
&theirs.revocation,
|
||||
&theirs.payment,
|
||||
&theirs.delayed_payment,
|
||||
&state->next_per_commit[REMOTE],
|
||||
&channel_flags))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_INITIAL_MESSAGE,
|
||||
"Parsing open_channel %s",
|
||||
tal_hex(peer_msg, peer_msg));
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiving MUST reject the channel if the `chain_hash` value
|
||||
* within the `open_channel` message is set to a hash of a chain
|
||||
* unknown to the receiver.
|
||||
*/
|
||||
if (!structeq(&chain_hash, &state->chainparams->genesis_blockhash)) {
|
||||
peer_failed(PEER_FD, &state->cs, NULL,
|
||||
WIRE_OPENING_PEER_BAD_INITIAL_MESSAGE,
|
||||
"Unknown chain-hash %s",
|
||||
type_to_string(peer_msg, struct sha256_double,
|
||||
&chain_hash));
|
||||
}
|
||||
|
||||
/* BOLT #2 FIXME:
|
||||
*
|
||||
* The receiving node ... MUST fail the channel if `funding-satoshis`
|
||||
* is greater than or equal to 2^24 */
|
||||
if (state->funding_satoshis >= 1 << 24)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_FUNDING,
|
||||
"push_msat %"PRIu64
|
||||
" too large for funding_satoshis %"PRIu64,
|
||||
state->push_msat, state->funding_satoshis);
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The receiver MUST fail the channel if it considers `feerate_per_kw`
|
||||
* too small for timely processing, or unreasonably large.
|
||||
*/
|
||||
if (state->feerate_per_kw < min_feerate)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_FUNDING,
|
||||
"feerate_per_kw %u below minimum %u",
|
||||
state->feerate_per_kw, min_feerate);
|
||||
|
||||
if (state->feerate_per_kw > max_feerate)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_FUNDING,
|
||||
"feerate_per_kw %u above maximum %u",
|
||||
state->feerate_per_kw, max_feerate);
|
||||
|
||||
set_reserve(&state->localconf.channel_reserve_satoshis,
|
||||
state->funding_satoshis);
|
||||
check_config_bounds(state, state->remoteconf);
|
||||
|
||||
msg = towire_accept_channel(state, &channel_id,
|
||||
state->localconf.dust_limit_satoshis,
|
||||
state->localconf
|
||||
.max_htlc_value_in_flight_msat,
|
||||
state->localconf.channel_reserve_satoshis,
|
||||
state->localconf.htlc_minimum_msat,
|
||||
minimum_depth,
|
||||
state->localconf.to_self_delay,
|
||||
state->localconf.max_accepted_htlcs,
|
||||
our_funding_pubkey,
|
||||
&ours->revocation,
|
||||
&ours->payment,
|
||||
&ours->delayed_payment,
|
||||
&state->next_per_commit[LOCAL]);
|
||||
|
||||
if (!sync_crypto_write(&state->cs, PEER_FD, take(msg)))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_WRITE_FAILED,
|
||||
"Writing accept_channel");
|
||||
|
||||
msg = read_next_peer_msg(state, state);
|
||||
if (!msg)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"Reading funding_created");
|
||||
|
||||
if (!fromwire_funding_created(msg, NULL, &id_in,
|
||||
&state->funding_txid.sha,
|
||||
&state->funding_txout,
|
||||
&theirsig))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, 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(&id_in, &channel_id))
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"funding_created ids don't match: sent %s got %s",
|
||||
type_to_string(msg, struct channel_id, &channel_id),
|
||||
type_to_string(msg, struct channel_id, &id_in));
|
||||
|
||||
state->channel = new_initial_channel(state,
|
||||
&state->funding_txid,
|
||||
state->funding_txout,
|
||||
state->funding_satoshis,
|
||||
state->push_msat,
|
||||
state->feerate_per_kw,
|
||||
&state->localconf,
|
||||
state->remoteconf,
|
||||
ours, &theirs,
|
||||
our_funding_pubkey,
|
||||
&their_funding_pubkey,
|
||||
REMOTE);
|
||||
if (!state->channel)
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_BAD_PARAM,
|
||||
"could not create channel with given config");
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* The recipient MUST fail the channel if `signature` is incorrect.
|
||||
*/
|
||||
tx = initial_channel_tx(state, &wscript, state->channel,
|
||||
&state->next_per_commit[LOCAL], LOCAL);
|
||||
|
||||
if (!check_tx_sig(tx, 0, NULL, wscript, &their_funding_pubkey,
|
||||
&theirsig)) {
|
||||
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_READ_FAILED,
|
||||
"Bad signature %s on tx %s using key %s",
|
||||
type_to_string(trc, secp256k1_ecdsa_signature,
|
||||
&theirsig),
|
||||
type_to_string(trc, struct bitcoin_tx, tx),
|
||||
type_to_string(trc, struct pubkey,
|
||||
&their_funding_pubkey));
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* This message introduces the `channel_id` to identify the channel,
|
||||
* which is derived from the funding transaction by combining the
|
||||
* `funding_txid` and the `funding_output_index` using big-endian
|
||||
* exclusive-OR (ie. `funding_output_index` alters the last two
|
||||
* bytes).
|
||||
*/
|
||||
derive_channel_id(&channel_id,
|
||||
&state->funding_txid, state->funding_txout);
|
||||
|
||||
/* 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 = initial_channel_tx(state, &wscript, state->channel,
|
||||
&state->next_per_commit[REMOTE], REMOTE);
|
||||
sign_tx_input(tx, 0, NULL, wscript,
|
||||
&state->our_secrets.funding_privkey,
|
||||
our_funding_pubkey, &sig);
|
||||
|
||||
/* We don't send this ourselves: channeld does, because master needs
|
||||
* to save state to disk before doing so. */
|
||||
msg = towire_funding_signed(state, &channel_id, &sig);
|
||||
|
||||
return towire_opening_fundee_reply(state,
|
||||
state->remoteconf,
|
||||
tx,
|
||||
&theirsig,
|
||||
&state->cs,
|
||||
&theirs.revocation,
|
||||
&theirs.payment,
|
||||
&theirs.delayed_payment,
|
||||
&state->next_per_commit[REMOTE],
|
||||
&their_funding_pubkey,
|
||||
&state->funding_txid,
|
||||
state->funding_txout,
|
||||
state->funding_satoshis,
|
||||
state->push_msat,
|
||||
channel_flags,
|
||||
state->feerate_per_kw,
|
||||
msg);
|
||||
}
|
||||
|
||||
#ifndef TESTING
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
u8 *msg, *peer_msg;
|
||||
struct state *state = tal(NULL, struct state);
|
||||
struct privkey seed;
|
||||
struct basepoints our_points;
|
||||
struct pubkey our_funding_pubkey;
|
||||
u32 minimum_depth, max_minimum_depth;
|
||||
u32 min_feerate, max_feerate;
|
||||
u64 change_satoshis;
|
||||
u32 change_keyindex;
|
||||
u8 channel_flags;
|
||||
struct utxo *utxos;
|
||||
struct ext_key bip32_base;
|
||||
u32 network_index;
|
||||
|
||||
if (argc == 2 && streq(argv[1], "--version")) {
|
||||
printf("%s\n", version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
subdaemon_debug(argc, argv);
|
||||
|
||||
/* We handle write returning errors! */
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
status_setup_sync(REQ_FD);
|
||||
|
||||
msg = wire_sync_read(state, REQ_FD);
|
||||
if (!msg)
|
||||
status_failed(WIRE_OPENING_BAD_COMMAND, "%s", strerror(errno));
|
||||
|
||||
if (!fromwire_opening_init(msg, NULL,
|
||||
&network_index,
|
||||
&state->localconf,
|
||||
&state->max_to_self_delay,
|
||||
&state->min_effective_htlc_capacity_msat,
|
||||
&state->cs,
|
||||
&seed))
|
||||
status_failed(WIRE_OPENING_BAD_COMMAND, "%s", strerror(errno));
|
||||
tal_free(msg);
|
||||
|
||||
state->chainparams = chainparams_by_index(network_index);
|
||||
|
||||
/* We derive everything from the one secret seed. */
|
||||
if (!derive_basepoints(&seed, &our_funding_pubkey,
|
||||
&our_points, &state->our_secrets,
|
||||
&state->shaseed))
|
||||
status_failed(WIRE_OPENING_KEY_DERIVATION_FAILED,
|
||||
"Secret derivation failed, secret = %s",
|
||||
type_to_string(trc, struct privkey, &seed));
|
||||
|
||||
if (!per_commit_point(&state->shaseed, &state->next_per_commit[LOCAL],
|
||||
0))
|
||||
status_failed(WIRE_OPENING_KEY_DERIVATION_FAILED,
|
||||
"First per_commitment_point derivation failed,"
|
||||
" secret = %s",
|
||||
type_to_string(trc, struct privkey, &seed));
|
||||
|
||||
status_trace("First per_commit_point = %s",
|
||||
type_to_string(trc, struct pubkey,
|
||||
&state->next_per_commit[LOCAL]));
|
||||
msg = wire_sync_read(state, REQ_FD);
|
||||
if (fromwire_opening_funder(state, msg, NULL,
|
||||
&state->funding_satoshis,
|
||||
&state->push_msat,
|
||||
&state->feerate_per_kw, &max_minimum_depth,
|
||||
&change_satoshis, &change_keyindex,
|
||||
&channel_flags, &utxos, &bip32_base))
|
||||
msg = funder_channel(state, &our_funding_pubkey, &our_points,
|
||||
max_minimum_depth, change_satoshis,
|
||||
change_keyindex, channel_flags,
|
||||
utxos, &bip32_base);
|
||||
else if (fromwire_opening_fundee(state, msg, NULL, &minimum_depth,
|
||||
&min_feerate, &max_feerate, &peer_msg))
|
||||
msg = fundee_channel(state, &our_funding_pubkey, &our_points,
|
||||
minimum_depth, min_feerate, max_feerate,
|
||||
peer_msg);
|
||||
|
||||
/* Write message and hand back the fd. */
|
||||
wire_sync_write(REQ_FD, msg);
|
||||
fdpass_send(REQ_FD, PEER_FD);
|
||||
fdpass_send(REQ_FD, GOSSIP_FD);
|
||||
status_trace("Sent %s with fd",
|
||||
opening_wire_type_name(fromwire_peektype(msg)));
|
||||
tal_free(state);
|
||||
return 0;
|
||||
}
|
||||
#endif /* TESTING */
|
||||
@@ -1,86 +0,0 @@
|
||||
# These shouldn't happen
|
||||
opening_bad_command,0x8000
|
||||
opening_key_derivation_failed,0x8001
|
||||
opening_bad_param,0x8002
|
||||
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
|
||||
|
||||
#include <common/cryptomsg.h>
|
||||
#include <common/channel_config.h>
|
||||
opening_init,0
|
||||
# Which network are we configured for (as index into the chainparams)?
|
||||
opening_init,,network_index,4
|
||||
# Base configuration we'll offer (channel reserve will vary with amount)
|
||||
opening_init,,our_config,struct channel_config
|
||||
# Minimum/maximum configuration values we'll accept
|
||||
opening_init,,max_to_self_delay,4
|
||||
opening_init,,min_effective_htlc_capacity_msat,8
|
||||
opening_init,,crypto_state,struct crypto_state
|
||||
# Seed to generate all the keys from
|
||||
opening_init,,seed,struct privkey
|
||||
|
||||
#include <common/bip32.h>
|
||||
#include <common/htlc_wire.h>
|
||||
# This means we offer the open.
|
||||
opening_funder,1
|
||||
opening_funder,,funding_satoshis,8
|
||||
opening_funder,,push_msat,8
|
||||
opening_funder,,feerate_per_kw,4
|
||||
opening_funder,,max_minimum_depth,4
|
||||
opening_funder,,change_satoshis,u64
|
||||
opening_funder,,change_keyindex,u32
|
||||
opening_funder,,channel_flags,u8
|
||||
#include <common/utxo.h>
|
||||
opening_funder,,num_inputs,u16
|
||||
opening_funder,,inputs,num_inputs*struct utxo
|
||||
opening_funder,,bip32,struct ext_key
|
||||
|
||||
# This gives their sig, means we can broadcast tx: we're done.
|
||||
opening_funder_reply,101
|
||||
opening_funder_reply,,their_config,struct channel_config
|
||||
opening_funder_reply,,first_commit,struct bitcoin_tx
|
||||
opening_funder_reply,,first_commit_sig,secp256k1_ecdsa_signature
|
||||
opening_funder_reply,,crypto_state,struct crypto_state
|
||||
opening_funder_reply,,revocation_basepoint,33
|
||||
opening_funder_reply,,payment_basepoint,33
|
||||
opening_funder_reply,,delayed_payment_basepoint,33
|
||||
opening_funder_reply,,their_per_commit_point,33
|
||||
opening_funder_reply,,minimum_depth,4
|
||||
opening_funder_reply,,remote_fundingkey,33
|
||||
opening_funder_reply,,funding_txid,struct sha256_double
|
||||
opening_funder_reply,,feerate_per_kw,4
|
||||
|
||||
# This means they offer the open (contains their offer packet)
|
||||
opening_fundee,3
|
||||
opening_fundee,,minimum_depth,4
|
||||
opening_fundee,,min_feerate,4
|
||||
opening_fundee,,max_feerate,4
|
||||
opening_fundee,,len,2
|
||||
opening_fundee,,msg,len*u8
|
||||
|
||||
# This gives their txid and info, means we can send funding_signed: we're done.
|
||||
opening_fundee_reply,103
|
||||
opening_fundee_reply,,their_config,struct channel_config
|
||||
opening_fundee_reply,,first_commit,struct bitcoin_tx
|
||||
opening_fundee_reply,,first_commit_sig,secp256k1_ecdsa_signature
|
||||
opening_fundee_reply,,crypto_state,struct crypto_state
|
||||
opening_fundee_reply,,revocation_basepoint,33
|
||||
opening_fundee_reply,,payment_basepoint,33
|
||||
opening_fundee_reply,,delayed_payment_basepoint,33
|
||||
opening_fundee_reply,,their_per_commit_point,33
|
||||
opening_fundee_reply,,remote_fundingkey,33
|
||||
opening_fundee_reply,,funding_txid,struct sha256_double
|
||||
opening_fundee_reply,,funding_txout,u16
|
||||
opening_fundee_reply,,funding_satoshis,8
|
||||
opening_fundee_reply,,push_msat,8
|
||||
opening_fundee_reply,,channel_flags,u8
|
||||
opening_fundee_reply,,feerate_per_kw,4
|
||||
# The (encrypted) funding signed message: send this and we're committed.
|
||||
opening_fundee_reply,,msglen,u16
|
||||
opening_fundee_reply,,funding_signed_msg,msglen*u8
|
||||
|
@@ -2,9 +2,9 @@
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/channel/gen_channel_wire.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <ccan/noerr/noerr.h>
|
||||
#include <ccan/take/take.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <closingd/gen_closing_wire.h>
|
||||
#include <common/close_tx.h>
|
||||
#include <common/dev_disconnect.h>
|
||||
#include <common/funding_tx.h>
|
||||
@@ -17,24 +19,22 @@
|
||||
#include <common/timeout.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <hsmd/gen_hsm_wire.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/build_utxos.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/channel/gen_channel_wire.h>
|
||||
#include <lightningd/closing/gen_closing_wire.h>
|
||||
#include <lightningd/dns.h>
|
||||
#include <lightningd/gen_peer_state_names.h>
|
||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||
#include <lightningd/hsm/gen_hsm_wire.h>
|
||||
#include <lightningd/hsm_control.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/new_connection.h>
|
||||
#include <lightningd/onchain/gen_onchain_wire.h>
|
||||
#include <lightningd/onchain/onchain_wire.h>
|
||||
#include <lightningd/opening/gen_opening_wire.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
#include <netinet/in.h>
|
||||
#include <onchaind/gen_onchain_wire.h>
|
||||
#include <onchaind/onchain_wire.h>
|
||||
#include <openingd/gen_opening_wire.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@@ -1224,7 +1224,7 @@ static enum watch_result funding_spent(struct peer *peer,
|
||||
|
||||
peer_fail_permanent_str(peer, "Funding transaction spent");
|
||||
peer->owner = new_subd(peer->ld, peer->ld,
|
||||
"lightningd_onchain", peer,
|
||||
"lightning_onchaind", peer,
|
||||
onchain_wire_type_name,
|
||||
onchain_msg,
|
||||
peer_onchain_finished,
|
||||
@@ -1783,7 +1783,7 @@ static void peer_start_closingd(struct peer *peer,
|
||||
}
|
||||
|
||||
peer->owner = new_subd(peer->ld, peer->ld,
|
||||
"lightningd_closing", peer,
|
||||
"lightning_closingd", peer,
|
||||
closing_wire_type_name,
|
||||
closing_msg,
|
||||
peer_owner_finished,
|
||||
@@ -1970,7 +1970,7 @@ static bool peer_start_channeld(struct peer *peer,
|
||||
fatal("Could not read fd from HSM: %s", strerror(errno));
|
||||
|
||||
peer->owner = new_subd(peer->ld, peer->ld,
|
||||
"lightningd_channel", peer,
|
||||
"lightning_channeld", peer,
|
||||
channel_wire_type_name,
|
||||
channel_msg,
|
||||
peer_owner_finished,
|
||||
@@ -2282,7 +2282,7 @@ static void channel_config(struct lightningd *ld,
|
||||
*/
|
||||
ours->max_accepted_htlcs = 483;
|
||||
|
||||
/* This is filled in by lightningd_opening, for consistency. */
|
||||
/* This is filled in by lightning_openingd, for consistency. */
|
||||
ours->channel_reserve_satoshis = 0;
|
||||
};
|
||||
|
||||
@@ -2309,7 +2309,7 @@ void peer_fundee_open(struct peer *peer, const u8 *from_peer,
|
||||
}
|
||||
|
||||
peer_set_condition(peer, GOSSIPD, OPENINGD);
|
||||
peer->owner = new_subd(ld, ld, "lightningd_opening", peer,
|
||||
peer->owner = new_subd(ld, ld, "lightning_openingd", peer,
|
||||
opening_wire_type_name,
|
||||
NULL, peer_owner_finished,
|
||||
take(&peer_fd), take(&gossip_fd),
|
||||
@@ -2393,7 +2393,7 @@ static bool gossip_peer_released(struct subd *gossip,
|
||||
|
||||
peer_set_condition(fc->peer, GOSSIPD, OPENINGD);
|
||||
opening = new_subd(fc->peer->ld, ld,
|
||||
"lightningd_opening", fc->peer,
|
||||
"lightning_openingd", fc->peer,
|
||||
opening_wire_type_name,
|
||||
NULL, peer_owner_finished,
|
||||
take(&fds[0]), take(&fds[1]), NULL);
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
#include <ccan/crypto/ripemd160/ripemd160.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <channeld/gen_channel_wire.h>
|
||||
#include <common/derive_basepoints.h>
|
||||
#include <common/htlc_wire.h>
|
||||
#include <common/overflows.h>
|
||||
#include <common/sphinx.h>
|
||||
#include <gossipd/gen_gossip_wire.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/channel/gen_channel_wire.h>
|
||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||
#include <lightningd/htlc_end.h>
|
||||
#include <lightningd/invoice.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/onchain/onchain_wire.h>
|
||||
#include <lightningd/pay.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
#include <lightningd/subd.h>
|
||||
#include <onchaind/onchain_wire.h>
|
||||
#include <wire/gen_onion_wire.h>
|
||||
|
||||
static bool state_update_ok(struct peer *peer,
|
||||
|
||||
@@ -16,7 +16,7 @@ struct io_conn;
|
||||
|
||||
/* One of our subds. */
|
||||
struct subd {
|
||||
/* Name, like John, or "lightningd_hsm" */
|
||||
/* Name, like John, or "lightning_hsmd" */
|
||||
const char *name;
|
||||
/* The Big Cheese. */
|
||||
struct lightningd *ld;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "../../common/key_derive.c"
|
||||
#include "../../common/keyset.c"
|
||||
#include "../../common/initial_channel.c"
|
||||
#include "../channel/full_channel.c"
|
||||
#include "../../channeld/full_channel.c"
|
||||
#include "../../common/initial_commit_tx.c"
|
||||
#include "../channel/commit_tx.c"
|
||||
#include "../../channeld/commit_tx.c"
|
||||
#include "../../common/htlc_tx.c"
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
|
||||
@@ -6,7 +6,7 @@ static bool print_superverbose;
|
||||
#define SUPERVERBOSE(...) \
|
||||
do { if (print_superverbose) printf(__VA_ARGS__); } while(0)
|
||||
#define PRINT_ACTUAL_FEE
|
||||
#include "../channel/commit_tx.c"
|
||||
#include "../../channeld/commit_tx.c"
|
||||
#include "../../common/initial_commit_tx.c"
|
||||
#include "../../common/htlc_tx.c"
|
||||
#include <bitcoin/preimage.h>
|
||||
|
||||
Reference in New Issue
Block a user