2018-01-04 12:40:58 +01:00
# include "bitcoind.h"
# include "chaintopology.h"
2017-01-10 06:08:33 +01:00
# include "gossip_control.h"
# include "lightningd.h"
# include "peer_control.h"
2017-03-10 11:50:43 +01:00
# include "subd.h"
2018-01-16 20:44:32 +01:00
# include <ccan/array_size/array_size.h>
2017-01-10 06:08:33 +01:00
# include <ccan/err/err.h>
2017-10-11 11:58:50 +02:00
# include <ccan/fdpass/fdpass.h>
2017-01-10 06:08:33 +01:00
# include <ccan/take/take.h>
2017-03-22 13:30:09 +01:00
# include <ccan/tal/str/str.h>
2018-01-12 14:35:52 +01:00
# include <common/features.h>
2017-08-28 18:02:01 +02:00
# include <common/type_to_string.h>
# include <common/utils.h>
2017-10-11 11:58:50 +02:00
# include <errno.h>
2017-08-29 06:12:04 +02:00
# include <gossipd/gen_gossip_wire.h>
2017-11-28 17:14:52 +01:00
# include <hsmd/capabilities.h>
2017-11-30 17:07:38 +01:00
# include <hsmd/gen_hsm_client_wire.h>
2017-01-10 06:08:33 +01:00
# include <inttypes.h>
2018-02-20 21:59:09 +01:00
# include <lightningd/connect_control.h>
2017-03-12 13:39:23 +01:00
# include <lightningd/gossip_msg.h>
2017-10-11 11:58:50 +02:00
# include <lightningd/hsm_control.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/jsonrpc.h>
# include <lightningd/log.h>
2017-02-24 06:52:56 +01:00
# include <wire/gen_peer_wire.h>
2017-10-11 11:58:50 +02:00
# include <wire/wire_sync.h>
2017-01-10 06:08:33 +01:00
2017-03-19 21:32:40 +01:00
static void peer_nongossip ( struct subd * gossip , const u8 * msg ,
int peer_fd , int gossip_fd )
2017-01-10 06:08:33 +01:00
{
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
struct pubkey id ;
2017-02-24 06:52:56 +01:00
struct crypto_state cs ;
2017-10-23 06:17:38 +02:00
struct wireaddr addr ;
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
u8 * gfeatures , * lfeatures , * in_pkt ;
2017-12-11 04:33:16 +01:00
u64 gossip_index ;
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
2018-02-20 21:59:09 +01:00
if ( ! fromwire_gossip_peer_nongossip ( msg , msg ,
2017-12-11 04:33:16 +01:00
& id , & addr , & cs , & gossip_index ,
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
& gfeatures ,
& lfeatures ,
& in_pkt ) )
fatal ( " Gossip gave bad GOSSIP_PEER_NONGOSSIP message %s " ,
2017-01-10 06:08:33 +01:00
tal_hex ( msg , msg ) ) ;
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
/* We already checked the features when it first connected. */
if ( unsupported_features ( gfeatures , lfeatures ) ) {
log_unusual ( gossip - > log ,
" Gossip gave unsupported features %s/%s " ,
tal_hex ( msg , gfeatures ) ,
tal_hex ( msg , lfeatures ) ) ;
close ( peer_fd ) ;
close ( gossip_fd ) ;
return ;
}
2017-01-10 06:08:33 +01:00
2017-12-11 04:33:16 +01:00
peer_sent_nongossip ( gossip - > ld , & id , & addr , & cs , gossip_index ,
gfeatures , lfeatures ,
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
peer_fd , gossip_fd , in_pkt ) ;
2017-01-10 06:08:33 +01:00
}
2018-01-04 12:40:58 +01:00
static void got_txout ( struct bitcoind * bitcoind ,
const struct bitcoin_tx_output * output ,
struct short_channel_id * scid )
{
2018-01-15 02:34:34 +01:00
const u8 * script ;
2018-01-04 12:40:58 +01:00
/* output will be NULL if it wasn't found */
2018-01-15 02:34:34 +01:00
if ( output )
script = output - > script ;
else
script = NULL ;
2018-01-04 12:40:58 +01:00
subd_send_msg ( bitcoind - > ld - > gossip ,
2018-01-15 02:34:34 +01:00
towire_gossip_get_txout_reply ( scid , scid , script ) ) ;
2018-01-04 12:40:58 +01:00
tal_free ( scid ) ;
}
static void get_txout ( struct subd * gossip , const u8 * msg )
{
struct short_channel_id * scid = tal ( gossip , struct short_channel_id ) ;
2018-02-20 21:59:09 +01:00
if ( ! fromwire_gossip_get_txout ( msg , scid ) )
2018-01-04 12:40:58 +01:00
fatal ( " Gossip gave bad GOSSIP_GET_TXOUT message %s " ,
tal_hex ( msg , msg ) ) ;
/* FIXME: Block less than 6 deep? */
bitcoind_getoutput ( gossip - > ld - > topology - > bitcoind ,
scid - > blocknum , scid - > txnum , scid - > outnum ,
got_txout , scid ) ;
}
2017-10-12 08:35:04 +02:00
static unsigned gossip_msg ( struct subd * gossip , const u8 * msg , const int * fds )
2017-01-10 06:08:33 +01:00
{
2017-03-10 11:50:43 +01:00
enum gossip_wire_type t = fromwire_peektype ( msg ) ;
2017-01-10 06:08:33 +01:00
switch ( t ) {
2017-03-10 11:50:43 +01:00
/* These are messages we send, not them. */
2017-04-24 14:31:26 +02:00
case WIRE_GOSSIPCTL_INIT :
2017-03-12 13:39:23 +01:00
case WIRE_GOSSIP_GETNODES_REQUEST :
2017-03-15 11:36:52 +01:00
case WIRE_GOSSIP_GETROUTE_REQUEST :
2017-03-22 13:30:09 +01:00
case WIRE_GOSSIP_GETCHANNELS_REQUEST :
2017-10-23 06:19:38 +02:00
case WIRE_GOSSIP_GETPEERS_REQUEST :
2017-04-12 20:20:48 +02:00
case WIRE_GOSSIP_PING :
2017-04-30 23:49:15 +02:00
case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST :
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
case WIRE_GOSSIPCTL_REACH_PEER :
2017-12-11 04:16:50 +01:00
case WIRE_GOSSIPCTL_HAND_BACK_PEER :
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
case WIRE_GOSSIPCTL_RELEASE_PEER :
case WIRE_GOSSIPCTL_PEER_ADDRHINT :
2017-11-28 23:52:32 +01:00
case WIRE_GOSSIP_GET_UPDATE :
2017-12-11 04:33:16 +01:00
case WIRE_GOSSIP_SEND_GOSSIP :
2018-01-04 12:40:58 +01:00
case WIRE_GOSSIP_GET_TXOUT_REPLY :
2018-01-23 22:13:19 +01:00
case WIRE_GOSSIP_DISABLE_CHANNEL :
2018-01-18 00:32:36 +01:00
case WIRE_GOSSIP_ROUTING_FAILURE :
2018-02-06 16:32:06 +01:00
case WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE :
2017-03-10 11:50:43 +01:00
/* This is a reply, so never gets through to here. */
2017-11-28 23:52:32 +01:00
case WIRE_GOSSIP_GET_UPDATE_REPLY :
2017-03-12 13:39:23 +01:00
case WIRE_GOSSIP_GETNODES_REPLY :
2017-03-15 11:36:52 +01:00
case WIRE_GOSSIP_GETROUTE_REPLY :
2017-03-22 13:30:09 +01:00
case WIRE_GOSSIP_GETCHANNELS_REPLY :
2017-10-23 06:19:38 +02:00
case WIRE_GOSSIP_GETPEERS_REPLY :
2017-04-12 20:20:48 +02:00
case WIRE_GOSSIP_PING_REPLY :
2017-04-30 23:49:15 +02:00
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY :
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY :
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL :
2017-01-10 06:08:33 +01:00
break ;
2017-12-15 15:16:42 +01:00
/* These are inter-daemon messages, not received by us */
case WIRE_GOSSIP_LOCAL_ADD_CHANNEL :
break ;
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
case WIRE_GOSSIP_PEER_CONNECTED :
if ( tal_count ( fds ) ! = 2 )
return 2 ;
peer_connected ( gossip - > ld , msg , fds [ 0 ] , fds [ 1 ] ) ;
2017-03-19 21:32:40 +01:00
break ;
2018-01-10 06:30:54 +01:00
case WIRE_GOSSIP_PEER_ALREADY_CONNECTED :
peer_already_connected ( gossip - > ld , msg ) ;
break ;
2018-01-27 15:59:18 +01:00
case WIRE_GOSSIP_PEER_CONNECTION_FAILED :
2018-01-27 16:56:12 +01:00
peer_connection_failed ( gossip - > ld , msg ) ;
2018-01-27 15:59:18 +01:00
break ;
gossipd: rewrite to do the handshake internally.
Now the flow is much simpler from a lightningd POV:
1. If we want to connect to a peer, just send gossipd `gossipctl_reach_peer`.
2. Every new peer, gossipd hands up to lightningd, with global/local features
and the peer fd and a gossip fd using `gossip_peer_connected`
3. If lightningd doesn't want it, it just hands the peerfd and global/local
features back to gossipd using `gossipctl_handle_peer`
4. If a peer sends a non-gossip msg (eg `open_channel`) the gossipd sends
it up using `gossip_peer_nongossip`.
5. If lightningd wants to fund a channel, it simply calls `release_channel`.
Notes:
* There's no more "unique_id": we use the peer id.
* For the moment, we don't ask gossipd when we're told to list peers, so
connected peers without a channel don't appear in the JSON getpeers API.
* We add a `gossipctl_peer_addrhint` for the moment, so you can connect to
a specific ip/port, but using other sources is a TODO.
* We now (correctly) only give up on reaching a peer after we exchange init
messages, which changes the test_disconnect case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-10-11 12:09:49 +02:00
case WIRE_GOSSIP_PEER_NONGOSSIP :
2017-03-19 21:32:40 +01:00
if ( tal_count ( fds ) ! = 2 )
return 2 ;
peer_nongossip ( gossip , msg , fds [ 0 ] , fds [ 1 ] ) ;
2017-01-10 06:08:33 +01:00
break ;
2018-01-04 12:40:58 +01:00
case WIRE_GOSSIP_GET_TXOUT :
get_txout ( gossip , msg ) ;
break ;
2017-01-10 06:08:33 +01:00
}
2017-03-19 21:31:35 +01:00
return 0 ;
2017-01-10 06:08:33 +01:00
}
2017-04-24 14:31:26 +02:00
/* Create the `gossipd` subdaemon and send the initialization
* message */
2017-01-10 06:08:33 +01:00
void gossip_init ( struct lightningd * ld )
{
2017-04-24 14:31:26 +02:00
tal_t * tmpctx = tal_tmpctx ( ld ) ;
2017-10-11 11:58:50 +02:00
u8 * msg ;
int hsmfd ;
2017-11-28 17:14:52 +01:00
u64 capabilities = HSM_CAP_ECDH | HSM_CAP_SIGN_GOSSIP ;
2017-10-11 11:58:50 +02:00
2017-11-30 17:07:38 +01:00
msg = towire_hsm_client_hsmfd ( tmpctx , & ld - > id , capabilities ) ;
2017-10-11 11:58:50 +02:00
if ( ! wire_sync_write ( ld - > hsm_fd , msg ) )
fatal ( " Could not write to HSM: %s " , strerror ( errno ) ) ;
msg = hsm_sync_read ( tmpctx , ld ) ;
2018-02-20 21:59:09 +01:00
if ( ! fromwire_hsm_client_hsmfd_reply ( msg ) )
2017-10-11 11:58:50 +02:00
fatal ( " Malformed hsmfd response: %s " , tal_hex ( msg , msg ) ) ;
hsmfd = fdpass_recv ( ld - > hsm_fd ) ;
if ( hsmfd < 0 )
fatal ( " Could not read fd from HSM: %s " , strerror ( errno ) ) ;
2017-10-12 08:35:03 +02:00
ld - > gossip = new_global_subd ( ld , " lightning_gossipd " ,
gossip_wire_type_name , gossip_msg ,
take ( & hsmfd ) , NULL ) ;
2017-01-10 06:08:33 +01:00
if ( ! ld - > gossip )
err ( 1 , " Could not subdaemon gossip " ) ;
2017-04-24 14:31:26 +02:00
2018-01-09 15:52:21 +01:00
msg = towire_gossipctl_init (
tmpctx , ld - > config . broadcast_interval ,
& get_chainparams ( ld ) - > genesis_blockhash , & ld - > id , ld - > portnum ,
get_supported_global_features ( tmpctx ) ,
get_supported_local_features ( tmpctx ) , ld - > wireaddrs , ld - > rgb ,
ld - > alias , ld - > config . channel_update_interval ) ;
2017-10-11 11:58:50 +02:00
subd_send_msg ( ld - > gossip , msg ) ;
2017-04-24 14:31:26 +02:00
tal_free ( tmpctx ) ;
2017-01-10 06:08:33 +01:00
}
2017-03-12 13:39:23 +01:00
2018-02-21 16:06:07 +01:00
static void json_getnodes_reply ( struct subd * gossip UNUSED , const u8 * reply ,
const int * fds UNUSED ,
2017-03-12 13:39:23 +01:00
struct command * cmd )
{
2018-02-08 02:24:46 +01:00
struct gossip_getnodes_entry * * nodes ;
2017-03-12 13:39:23 +01:00
struct json_result * response = new_json_result ( cmd ) ;
2017-05-08 23:22:59 +02:00
size_t i , j ;
2017-03-16 05:05:26 +01:00
2018-02-20 21:59:09 +01:00
if ( ! fromwire_gossip_getnodes_reply ( reply , reply , & nodes ) ) {
2017-03-16 05:05:26 +01:00
command_fail ( cmd , " Malformed gossip_getnodes response " ) ;
2017-10-12 08:35:04 +02:00
return ;
2017-03-16 05:05:26 +01:00
}
2017-03-12 13:39:23 +01:00
json_object_start ( response , NULL ) ;
json_array_start ( response , " nodes " ) ;
2017-03-16 05:05:26 +01:00
for ( i = 0 ; i < tal_count ( nodes ) ; i + + ) {
2017-03-12 13:39:23 +01:00
json_object_start ( response , NULL ) ;
2018-02-08 02:24:46 +01:00
json_add_pubkey ( response , " nodeid " , & nodes [ i ] - > nodeid ) ;
if ( nodes [ i ] - > last_timestamp < 0 ) {
2018-01-16 20:44:32 +01:00
json_object_end ( response ) ;
continue ;
}
json_add_string ( response , " alias " ,
2018-02-08 02:24:46 +01:00
tal_strndup ( response , ( char * ) nodes [ i ] - > alias ,
tal_len ( nodes [ i ] - > alias ) ) ) ;
2018-01-16 20:44:32 +01:00
json_add_hex ( response , " color " ,
2018-02-08 02:24:46 +01:00
nodes [ i ] - > color , ARRAY_SIZE ( nodes [ i ] - > color ) ) ;
2018-01-16 20:44:32 +01:00
json_add_u64 ( response , " last_timestamp " ,
2018-02-08 02:24:46 +01:00
nodes [ i ] - > last_timestamp ) ;
2017-05-08 23:22:59 +02:00
json_array_start ( response , " addresses " ) ;
2018-02-08 02:24:46 +01:00
for ( j = 0 ; j < tal_count ( nodes [ i ] - > addresses ) ; j + + ) {
json_add_address ( response , NULL , & nodes [ i ] - > addresses [ j ] ) ;
2017-03-12 13:39:23 +01:00
}
2017-05-08 23:22:59 +02:00
json_array_end ( response ) ;
2017-03-12 13:39:23 +01:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
json_object_end ( response ) ;
command_success ( cmd , response ) ;
}
2018-01-16 20:44:32 +01:00
static void json_listnodes ( struct command * cmd , const char * buffer ,
2017-03-12 13:39:23 +01:00
const jsmntok_t * params )
{
2018-01-16 20:44:32 +01:00
u8 * req ;
jsmntok_t * idtok = NULL ;
struct pubkey * id = NULL ;
2018-01-29 01:34:28 +01:00
if ( ! json_get_params ( cmd , buffer , params ,
2018-01-16 20:44:32 +01:00
" ?id " , & idtok ,
NULL ) ) {
return ;
}
if ( idtok ) {
id = tal_arr ( cmd , struct pubkey , 1 ) ;
if ( ! json_tok_pubkey ( buffer , idtok , id ) ) {
command_fail ( cmd , " Invalid id " ) ;
return ;
}
}
req = towire_gossip_getnodes_request ( cmd , id ) ;
2017-08-28 18:09:01 +02:00
subd_req ( cmd , cmd - > ld - > gossip , req , - 1 , 0 , json_getnodes_reply , cmd ) ;
2017-12-15 11:15:54 +01:00
command_still_pending ( cmd ) ;
2017-03-12 13:39:23 +01:00
}
2018-01-16 20:44:32 +01:00
static const struct json_command listnodes_command = {
2018-01-22 09:55:07 +01:00
" listnodes " ,
json_listnodes ,
" Show all nodes in our local network view "
} ;
2018-01-16 20:44:32 +01:00
AUTODATA ( json_command , & listnodes_command ) ;
2017-03-15 11:36:52 +01:00
2018-02-21 16:06:07 +01:00
static void json_getroute_reply ( struct subd * gossip UNUSED , const u8 * reply , const int * fds UNUSED ,
2017-03-15 13:46:29 +01:00
struct command * cmd )
{
struct json_result * response ;
struct route_hop * hops ;
size_t i ;
2018-02-20 21:59:09 +01:00
fromwire_gossip_getroute_reply ( reply , reply , & hops ) ;
2017-03-15 13:46:29 +01:00
if ( tal_count ( hops ) = = 0 ) {
command_fail ( cmd , " Could not find a route " ) ;
2017-10-12 08:35:04 +02:00
return ;
2017-03-15 13:46:29 +01:00
}
response = new_json_result ( cmd ) ;
json_object_start ( response , NULL ) ;
json_array_start ( response , " route " ) ;
2017-04-29 10:52:40 +02:00
for ( i = 0 ; i < tal_count ( hops ) ; i + + ) {
2017-03-15 13:46:29 +01:00
json_object_start ( response , NULL ) ;
json_add_pubkey ( response , " id " , & hops [ i ] . nodeid ) ;
2017-04-29 10:52:40 +02:00
json_add_short_channel_id ( response , " channel " ,
& hops [ i ] . channel_id ) ;
2017-03-15 13:46:29 +01:00
json_add_u64 ( response , " msatoshi " , hops [ i ] . amount ) ;
json_add_num ( response , " delay " , hops [ i ] . delay ) ;
json_object_end ( response ) ;
}
json_array_end ( response ) ;
json_object_end ( response ) ;
command_success ( cmd , response ) ;
}
2017-03-15 11:36:52 +01:00
static void json_getroute ( struct command * cmd , const char * buffer , const jsmntok_t * params )
{
2018-02-10 21:38:26 +01:00
struct lightningd * ld = cmd - > ld ;
struct pubkey source = ld - > id , destination ;
2018-02-07 15:45:42 +01:00
jsmntok_t * idtok , * msatoshitok , * riskfactortok , * cltvtok , * fromidtok ;
2017-03-15 13:46:29 +01:00
u64 msatoshi ;
2017-10-23 06:16:57 +02:00
unsigned cltv = 9 ;
2017-03-15 13:46:29 +01:00
double riskfactor ;
2017-08-28 18:09:01 +02:00
2018-01-29 01:34:28 +01:00
if ( ! json_get_params ( cmd , buffer , params ,
2017-03-15 13:46:29 +01:00
" id " , & idtok ,
" msatoshi " , & msatoshitok ,
" riskfactor " , & riskfactortok ,
2017-10-23 06:16:57 +02:00
" ?cltv " , & cltvtok ,
2018-02-07 15:45:42 +01:00
" ?fromid " , & fromidtok ,
2017-03-15 13:46:29 +01:00
NULL ) ) {
return ;
}
2018-02-10 21:38:26 +01:00
if ( ! json_tok_pubkey ( buffer , idtok , & destination ) ) {
2017-03-15 13:46:29 +01:00
command_fail ( cmd , " Invalid id " ) ;
return ;
}
2017-10-23 06:16:57 +02:00
if ( cltvtok & & ! json_tok_number ( buffer , cltvtok , & cltv ) ) {
command_fail ( cmd , " Invalid cltv " ) ;
return ;
}
2017-03-15 13:46:29 +01:00
if ( ! json_tok_u64 ( buffer , msatoshitok , & msatoshi ) ) {
command_fail ( cmd , " '%.*s' is not a valid number " ,
2018-02-21 11:29:57 +01:00
msatoshitok - > end - msatoshitok - > start ,
2017-03-15 13:46:29 +01:00
buffer + msatoshitok - > start ) ;
return ;
}
if ( ! json_tok_double ( buffer , riskfactortok , & riskfactor ) ) {
command_fail ( cmd , " '%.*s' is not a valid double " ,
2018-02-21 11:29:57 +01:00
riskfactortok - > end - riskfactortok - > start ,
2017-03-15 13:46:29 +01:00
buffer + riskfactortok - > start ) ;
return ;
}
2018-02-07 15:45:42 +01:00
2018-02-10 21:38:26 +01:00
if ( fromidtok & & ! json_tok_pubkey ( buffer , fromidtok , & source ) ) {
command_fail ( cmd , " Invalid from id " ) ;
return ;
2018-02-07 15:45:42 +01:00
}
2018-02-10 21:38:26 +01:00
u8 * req = towire_gossip_getroute_request ( cmd , & source , & destination , msatoshi , riskfactor * 1000 , cltv ) ;
2017-04-01 12:58:30 +02:00
subd_req ( ld - > gossip , ld - > gossip , req , - 1 , 0 , json_getroute_reply , cmd ) ;
2017-12-15 11:15:54 +01:00
command_still_pending ( cmd ) ;
2017-03-15 11:36:52 +01:00
}
static const struct json_command getroute_command = {
2018-01-22 09:55:07 +01:00
" getroute " ,
json_getroute ,
2018-02-10 21:38:26 +01:00
" Show route to {id} for {msatoshi}, using {riskfactor} and optional {cltv} (default 9), if specified search from {source} otherwise use this node as source. "
2017-03-15 11:36:52 +01:00
} ;
AUTODATA ( json_command , & getroute_command ) ;
2017-03-22 13:30:09 +01:00
/* Called upon receiving a getchannels_reply from `gossipd` */
2018-02-21 16:06:07 +01:00
static void json_listchannels_reply ( struct subd * gossip UNUSED , const u8 * reply ,
const int * fds UNUSED , struct command * cmd )
2017-03-22 13:30:09 +01:00
{
size_t i ;
struct gossip_getchannels_entry * entries ;
struct json_result * response = new_json_result ( cmd ) ;
2018-02-20 21:59:09 +01:00
if ( ! fromwire_gossip_getchannels_reply ( reply , reply , & entries ) ) {
2017-03-22 13:30:09 +01:00
command_fail ( cmd , " Invalid reply from gossipd " ) ;
2017-10-12 08:35:04 +02:00
return ;
2017-03-22 13:30:09 +01:00
}
json_object_start ( response , NULL ) ;
json_array_start ( response , " channels " ) ;
for ( i = 0 ; i < tal_count ( entries ) ; i + + ) {
json_object_start ( response , NULL ) ;
json_add_pubkey ( response , " source " , & entries [ i ] . source ) ;
json_add_pubkey ( response , " destination " ,
& entries [ i ] . destination ) ;
2018-01-04 00:49:26 +01:00
json_add_string ( response , " short_channel_id " ,
type_to_string ( reply , struct short_channel_id ,
& entries [ i ] . short_channel_id ) ) ;
2017-09-01 06:18:54 +02:00
json_add_num ( response , " flags " , entries [ i ] . flags ) ;
json_add_bool ( response , " active " , entries [ i ] . active ) ;
2018-01-04 00:51:21 +01:00
json_add_bool ( response , " public " , entries [ i ] . public ) ;
2017-09-01 06:18:54 +02:00
if ( entries [ i ] . last_update_timestamp > = 0 ) {
json_add_num ( response , " last_update " ,
entries [ i ] . last_update_timestamp ) ;
2017-09-01 06:18:54 +02:00
json_add_num ( response , " base_fee_millisatoshi " ,
entries [ i ] . base_fee_msat ) ;
json_add_num ( response , " fee_per_millionth " ,
entries [ i ] . fee_per_millionth ) ;
2017-09-01 06:18:54 +02:00
json_add_num ( response , " delay " , entries [ i ] . delay ) ;
}
2017-03-22 13:30:09 +01:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
json_object_end ( response ) ;
command_success ( cmd , response ) ;
}
2018-01-16 20:44:32 +01:00
static void json_listchannels ( struct command * cmd , const char * buffer ,
2017-03-22 13:30:09 +01:00
const jsmntok_t * params )
{
2018-01-16 20:44:32 +01:00
u8 * req ;
jsmntok_t * idtok ;
struct short_channel_id * id = NULL ;
2018-01-29 01:34:28 +01:00
if ( ! json_get_params ( cmd , buffer , params ,
2018-01-16 20:44:32 +01:00
" ?short_channel_id " , & idtok ,
NULL ) ) {
return ;
}
if ( idtok ) {
id = tal_arr ( cmd , struct short_channel_id , 1 ) ;
if ( ! json_tok_short_channel_id ( buffer , idtok , id ) ) {
command_fail ( cmd , " Invalid short_channel_id " ) ;
return ;
}
}
req = towire_gossip_getchannels_request ( cmd , id ) ;
2017-08-28 18:09:01 +02:00
subd_req ( cmd - > ld - > gossip , cmd - > ld - > gossip ,
2018-01-16 20:44:32 +01:00
req , - 1 , 0 , json_listchannels_reply , cmd ) ;
2017-12-15 11:15:54 +01:00
command_still_pending ( cmd ) ;
2017-03-22 13:30:09 +01:00
}
2018-01-16 20:44:32 +01:00
static const struct json_command listchannels_command = {
2018-01-22 09:55:07 +01:00
" listchannels " ,
json_listchannels ,
" Show all known channels "
} ;
2018-01-16 20:44:32 +01:00
AUTODATA ( json_command , & listchannels_command ) ;