@ -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_h smfd ( 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_h smfd , 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_h smfd , 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 ) ;