lightningd: wire up opening daemon.

Now we can actually open a channel.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-02-24 16:22:56 +10:30
parent d48f9faa19
commit fd258fe495
7 changed files with 384 additions and 9 deletions

View File

@ -114,7 +114,7 @@ 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_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a libsodium.a libwallycore.a
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) libsecp256k1.a libsodium.a libwallycore.a
clean: lightningd-clean

View File

@ -1,4 +1,3 @@
#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>

View File

@ -69,7 +69,7 @@ static void peer_nongossip(struct subdaemon *gossip, const u8 *msg, int fd)
peer_set_condition(peer, "Gossip ended up receipt of %s",
wire_type_name(fromwire_peektype(inner)));
/* FIXME: create new daemon to handle peer. */
peer_accept_open(peer, &cs, inner);
}
static void peer_ready(struct subdaemon *gossip, const u8 *msg)

View File

@ -107,7 +107,8 @@ static const char *daemons[] = {
"lightningd",
"lightningd_hsm",
"lightningd_handshake",
"lightningd_gossip"
"lightningd_gossip",
"lightningd_opening"
};
/* Check we can run them, and check their versions */

View File

@ -1,6 +1,7 @@
#include "lightningd.h"
#include "peer_control.h"
#include "subdaemon.h"
#include <bitcoin/tx.h>
#include <ccan/io/io.h>
#include <ccan/noerr/noerr.h>
#include <ccan/take/take.h>
@ -10,14 +11,20 @@
#include <daemon/log.h>
#include <errno.h>
#include <inttypes.h>
#include <lightningd/build_utxos.h>
#include <lightningd/funding_tx.h>
#include <lightningd/gossip/gen_gossip_control_wire.h>
#include <lightningd/gossip/gen_gossip_status_wire.h>
#include <lightningd/handshake/gen_handshake_control_wire.h>
#include <lightningd/handshake/gen_handshake_status_wire.h>
#include <lightningd/hsm/gen_hsm_control_wire.h>
#include <lightningd/opening/gen_opening_control_wire.h>
#include <lightningd/opening/gen_opening_status_wire.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <wally_bip32.h>
#include <wire/gen_peer_wire.h>
static void destroy_peer(struct peer *peer)
{
@ -29,6 +36,22 @@ static void destroy_peer(struct peer *peer)
peer->condition);
}
static void bitcoin_pubkey(struct lightningd *ld,
struct pubkey *pubkey, u32 index)
{
struct ext_key ext;
assert(index < BIP32_INITIAL_HARDENED_CHILD);
assert(index < ld->bip32_max_index);
if (bip32_key_from_parent(ld->bip32_base, index,
BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK)
fatal("BIP32 of %u failed", index);
if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey->pubkey,
ext.pub_key, sizeof(ext.pub_key)))
fatal("Parse of BIP32 child %u pubkey failed", index);
}
void peer_set_condition(struct peer *peer, const char *fmt, ...)
{
va_list ap;
@ -86,6 +109,16 @@ struct peer *peer_by_unique_id(struct lightningd *ld, u64 unique_id)
return NULL;
}
struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id)
{
struct peer *p;
list_for_each(&ld->peers, p, list)
if (pubkey_eq(p->id, id))
return p;
return NULL;
}
static void handshake_succeeded(struct subdaemon *hs, const u8 *msg,
struct peer *peer)
{
@ -131,8 +164,8 @@ err:
tal_free(peer);
}
static void peer_got_hsmfd(struct subdaemon *hsm, const u8 *msg,
struct peer *peer)
static void peer_got_handshake_hsmfd(struct subdaemon *hsm, const u8 *msg,
struct peer *peer)
{
const u8 *req;
@ -193,7 +226,7 @@ static struct io_plan *peer_in(struct io_conn *conn, struct lightningd *ld)
/* Get HSM fd for this peer. */
subdaemon_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_hsmfd, peer);
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
/* We don't need conn, we'll pass fd to handshaked. */
return io_close_taken_fd(conn);
@ -324,7 +357,7 @@ static struct io_plan *peer_out(struct io_conn *conn,
/* Get HSM fd for this peer. */
subdaemon_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_hsmfd, peer);
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
/* We don't need conn, we'll pass fd to handshaked. */
return io_close_taken_fd(conn);
@ -465,3 +498,337 @@ static const struct json_command getpeers_command = {
"Returns a 'peers' array"
};
AUTODATA(json_command, &getpeers_command);
static struct peer *find_peer_json(struct lightningd *ld,
const char *buffer,
jsmntok_t *peeridtok)
{
struct pubkey peerid;
if (!pubkey_from_hexstr(buffer + peeridtok->start,
peeridtok->end - peeridtok->start, &peerid))
return NULL;
return peer_by_id(ld, &peerid);
}
struct funding_channel {
struct peer *peer;
struct command *cmd;
u64 satoshi;
struct utxo *utxos;
u64 change;
u32 change_keyindex;
struct crypto_state *cs;
struct pubkey local_fundingkey, remote_fundingkey;
struct bitcoin_tx *funding_tx;
};
static void fail_fundchannel_command(struct funding_channel *fc)
{
/* FIXME: More details? */
command_fail(fc->cmd, "Peer died");
}
static void opening_got_hsm_funding_sig(struct subdaemon *hsm, const u8 *resp,
struct funding_channel *fc)
{
secp256k1_ecdsa_signature *sigs;
if (!fromwire_hsmctl_sign_funding_response(fc, resp, NULL, &sigs))
fatal("HSM gave bad sign_funding_response %s",
tal_hex(fc, resp));
peer_set_condition(fc->peer, "Waiting for our funding tx");
/* FIXME: Defer until after funding locked. */
tal_del_destructor(fc, fail_fundchannel_command);
command_success(fc->cmd, null_response(fc->cmd));
fc->cmd = NULL;
/* FIXME: broadcast tx... */
}
static void opening_release_tx(struct subdaemon *opening, const u8 *resp,
struct funding_channel *fc)
{
u8 *msg;
peer_set_condition(fc->peer, "Getting HSM to sign funding tx");
/* Get HSM to sign the funding tx. */
msg = towire_hsmctl_sign_funding(fc, fc->satoshi, fc->change,
fc->change_keyindex,
&fc->local_fundingkey,
&fc->remote_fundingkey,
fc->utxos);
subdaemon_req(fc->peer->ld->hsm, take(msg), -1, NULL,
opening_got_hsm_funding_sig, fc);
}
static void opening_gen_funding(struct subdaemon *opening, const u8 *resp,
struct funding_channel *fc)
{
u8 *msg;
struct sha256_double txid;
u32 outnum;
struct pubkey changekey;
peer_set_condition(fc->peer, "Created funding transaction for channel");
if (!fromwire_opening_open_resp(resp, NULL,
&fc->local_fundingkey,
&fc->remote_fundingkey)) {
log_broken(fc->peer->log, "Bad opening_open_resp %s",
tal_hex(fc, resp));
tal_free(fc);
return;
}
bitcoin_pubkey(fc->peer->ld, &changekey, fc->change_keyindex);
/* FIXME: Real feerate! */
/* FIXME: Real dust limit! */
fc->funding_tx = funding_tx(fc, &outnum, fc->utxos, fc->satoshi,
&fc->local_fundingkey,
&fc->remote_fundingkey,
&changekey, 15000, 546);
bitcoin_txid(fc->funding_tx, &txid);
msg = towire_opening_open_funding(fc, &txid, outnum);
subdaemon_req(fc->peer->owner, take(msg), -1, &fc->peer->fd,
opening_release_tx, fc);
}
static void opening_accept_response(struct subdaemon *opening, const u8 *resp,
struct peer *peer)
{
peer_set_condition(peer, "Waiting for their commitment tx");
/* FIXME... */
}
static void channel_config(struct lightningd *ld,
struct channel_config *ours,
u32 *max_to_self_delay,
u32 *max_minimum_depth,
u64 *min_effective_htlc_capacity_msat)
{
/* FIXME: depend on feerate. */
*max_to_self_delay = ld->dstate.config.locktime_max;
*max_minimum_depth = ld->dstate.config.anchor_confirms_max;
/* This is 1c at $1000/BTC */
*min_effective_htlc_capacity_msat = 1000000;
/* BOLT #2:
*
* The sender SHOULD set `dust-limit-satoshis` to a sufficient
* value to allow commitment transactions to propagate through
* the Bitcoin network.
*/
ours->dust_limit_satoshis = 546;
ours->max_htlc_value_in_flight_msat = UINT64_MAX;
/* BOLT #3:
*
* The sender SHOULD set `minimum-depth` to an amount where
* the sender considers reorganizations to be low risk.
*/
ours->minimum_depth = ld->dstate.config.anchor_confirms;
/* Don't care */
ours->htlc_minimum_msat = 0;
/* BOLT #3:
*
* The sender SHOULD set `to-self-delay` sufficient to ensure
* the sender can irreversibly spend a commitment transaction
* output in case of misbehavior by the receiver.
*/
ours->to_self_delay = ld->dstate.config.locktime_blocks;
/* Don't care. */
ours->max_accepted_htlcs = 511;
/* This is filled in by lightningd_opening, for consistency. */
ours->channel_reserve_satoshis = 0;
};
/* Peer has spontaneously exited from gossip due to msg */
void peer_accept_open(struct peer *peer,
const struct crypto_state *cs, const u8 *from_peer)
{
struct lightningd *ld = peer->ld;
struct privkey seed;
struct channel_config ours;
u32 max_to_self_delay, max_minimum_depth;
u64 min_effective_htlc_capacity_msat;
u8 *msg;
/* Note: gossipd handles unknown packets, so we don't have to worry
* about ignoring odd ones here. */
if (fromwire_peektype(from_peer) != WIRE_OPEN_CHANNEL) {
log_unusual(peer->log, "Strange message to exit gossip: %u",
fromwire_peektype(from_peer));
peer_set_condition(peer, "Bad message during gossiping");
tal_free(peer);
return;
}
peer_set_condition(peer, "Starting opening daemon");
peer->owner = new_subdaemon(peer, ld,
"lightningd_opening",
opening_status_wire_type_name,
opening_control_wire_type_name,
NULL, NULL,
peer->fd, -1);
if (!peer->owner) {
log_unusual(ld->log, "Could not subdaemon opening: %s",
strerror(errno));
peer_set_condition(peer, "Failed to subdaemon opening");
tal_free(peer);
return;
}
tal_steal(peer->owner, peer);
/* We handed off peer fd */
peer->fd = -1;
channel_config(ld, &ours,
&max_to_self_delay, &max_minimum_depth,
&min_effective_htlc_capacity_msat);
derive_peer_seed(ld, &seed, peer->id);
msg = towire_opening_init(peer, &ours,
max_to_self_delay,
min_effective_htlc_capacity_msat,
cs, &seed);
subdaemon_req(peer->owner, take(msg), -1, NULL, NULL, NULL);
/* FIXME: Real feerates! */
msg = towire_opening_accept(peer, 7500, 150000, from_peer);
/* Careful here! Their message could push us overlength! */
if (tal_len(msg) >= 65536) {
peer_set_condition(peer, "Unacceptably long open_channel");
tal_free(peer);
return;
}
subdaemon_req(peer->owner, take(msg), -1, &peer->fd,
opening_accept_response, peer);
}
/* Peer has been released from gossip. Start opening. */
static void gossip_peer_released(struct subdaemon *gossip,
const u8 *resp,
struct funding_channel *fc)
{
struct lightningd *ld = fc->peer->ld;
struct privkey seed;
struct channel_config ours;
u32 max_to_self_delay, max_minimum_depth;
u64 min_effective_htlc_capacity_msat;
u64 id;
u8 *msg;
fc->cs = tal(fc, struct crypto_state);
if (!fromwire_gossipctl_release_peer_response(resp, NULL, &id, fc->cs))
fatal("Gossup daemon gave invalid response %s",
tal_hex(gossip, resp));
if (id != fc->peer->unique_id)
fatal("Gossup daemon release gave %"PRIu64" not %"PRIu64,
id, fc->peer->unique_id);
peer_set_condition(fc->peer, "Starting opening daemon");
fc->peer->owner = new_subdaemon(fc->peer, ld,
"lightningd_opening",
opening_status_wire_type_name,
opening_control_wire_type_name,
NULL, NULL,
fc->peer->fd, -1);
if (!fc->peer->owner) {
log_unusual(ld->log, "Could not subdaemon opening: %s",
strerror(errno));
peer_set_condition(fc->peer, "Failed to subdaemon opening");
tal_free(fc);
return;
}
/* They took our fd. */
fc->peer->fd = -1;
/* fc only lasts as long as this daemon does, for now. */
tal_steal(fc->peer->owner, fc);
channel_config(ld, &ours,
&max_to_self_delay, &max_minimum_depth,
&min_effective_htlc_capacity_msat);
derive_peer_seed(ld, &seed, fc->peer->id);
msg = towire_opening_init(fc, &ours,
max_to_self_delay,
min_effective_htlc_capacity_msat,
fc->cs, &seed);
subdaemon_req(fc->peer->owner, take(msg), -1, NULL, NULL, NULL);
/* FIXME: Support push_msat? */
/* FIXME: Real feerate! */
msg = towire_opening_open(fc, fc->satoshi, 0, 15000, max_minimum_depth);
subdaemon_req(fc->peer->owner, take(msg), -1, NULL,
opening_gen_funding, fc);
}
static void json_fund_channel(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct lightningd *ld = ld_from_dstate(cmd->dstate);
jsmntok_t *peertok, *satoshitok;
struct funding_channel *fc = tal(cmd, struct funding_channel);
u8 *msg;
if (!json_get_params(buffer, params,
"id", &peertok,
"satoshi", &satoshitok,
NULL)) {
command_fail(cmd, "Need peerid and satoshi");
return;
}
fc->cmd = cmd;
fc->peer = find_peer_json(ld, buffer, peertok);
if (!fc->peer) {
command_fail(cmd, "Could not find peer with that peerid");
return;
}
if (fc->peer->owner != ld->gossip) {
command_fail(cmd, "Peer not ready for connection");
return;
}
if (!json_tok_u64(buffer, satoshitok, &fc->satoshi)) {
command_fail(cmd, "Invalid satoshis");
return;
}
/* Try to do this now, so we know if insufficient funds. */
/* FIXME: Feerate & dustlimit */
fc->utxos = build_utxos(fc, ld, fc->satoshi, 15000, 600,
&fc->change, &fc->change_keyindex);
if (!fc->utxos) {
command_fail(cmd, "Cannot afford funding transaction");
return;
}
msg = towire_gossipctl_release_peer(cmd, fc->peer->unique_id);
/* Tie this fc lifetime (and hence utxo release) to the peer */
tal_steal(fc->peer, fc);
tal_add_destructor(fc, fail_fundchannel_command);
subdaemon_req(ld->gossip, msg, -1, &fc->peer->fd,
gossip_peer_released, fc);
}
static const struct json_command fund_channel_command = {
"fundchannel",
json_fund_channel,
"Fund channel with {id} using {satoshi} satoshis",
"Returns once channel established"
};
AUTODATA(json_command, &fund_channel_command);

View File

@ -5,6 +5,8 @@
#include <daemon/netaddr.h>
#include <stdbool.h>
struct crypto_state;
struct peer {
struct lightningd *ld;
@ -41,6 +43,10 @@ struct peer {
};
struct peer *peer_by_unique_id(struct lightningd *ld, u64 unique_id);
struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id);
void peer_accept_open(struct peer *peer,
const struct crypto_state *cs, const u8 *msg);
PRINTF_FMT(2,3) void peer_set_condition(struct peer *peer, const char *fmt, ...);
void setup_listeners(struct lightningd *ld);

View File

@ -31,13 +31,15 @@ lcli1 getpeers | $FGREP '"owner" : "lightningd_gossip"'
lcli2 getpeers | $FGREP '"owner" : "lightningd_gossip"'
# Add some funds.
set -x
NEWADDR=`lcli1 newaddr | get_field address`
FUND_INPUT_TXID=`$CLI sendtoaddress $NEWADDR 0.10000002`
FUND_INPUT_TX=`$CLI getrawtransaction $FUND_INPUT_TXID`
lcli1 addfunds $FUND_INPUT_TX | $FGREP '"satoshis" : 10000002'
# Now fund a channel.
lcli1 fundchannel $ID2 100000
lcli1 stop
lcli2 stop