Browse Source

gossipd: look up short_channel_id when we see a channel_announcement.

This is done it two parts, since we have to ask the main daemon to do
the lookup for us.

If this becomes a bottleneck, we can have a separate daemon, or even
an RPC pipe to bitcoind ourselves.

Fixes: #403
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
db30411ba5
  1. 34
      gossipd/gossip.c
  2. 183
      gossipd/routing.c
  3. 25
      gossipd/routing.h

34
gossipd/gossip.c

@ -452,15 +452,18 @@ static void handle_gossip_msg(struct daemon *daemon, u8 *msg)
{
struct routing_state *rstate = daemon->rstate;
int t = fromwire_peektype(msg);
switch(t) {
case WIRE_CHANNEL_ANNOUNCEMENT:
/* Add the channel_announcement to the routing state,
* it'll tell us whether this is local and signed, so
* we can hand in a node_announcement as well. */
if(handle_channel_announcement(rstate, msg)) {
send_node_announcement(daemon);
}
case WIRE_CHANNEL_ANNOUNCEMENT: {
const struct short_channel_id *scid;
/* If it's OK, tells us the short_channel_id to lookup */
scid = handle_channel_announcement(rstate, msg);
if (scid)
daemon_conn_send(&daemon->master,
take(towire_gossip_get_txout(daemon,
scid)));
break;
}
case WIRE_NODE_ANNOUNCEMENT:
handle_node_announcement(rstate, msg);
@ -1559,6 +1562,21 @@ static struct io_plan *get_peers(struct io_conn *conn,
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *handle_txout_reply(struct io_conn *conn,
struct daemon *daemon, const u8 *msg)
{
struct short_channel_id scid;
u8 *outscript;
if (!fromwire_gossip_get_txout_reply(msg, msg, NULL, &scid, &outscript))
master_badmsg(WIRE_GOSSIP_GET_TXOUT_REPLY, msg);
if (handle_pending_cannouncement(daemon->rstate, &scid, outscript))
send_node_announcement(daemon);
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master)
{
struct daemon *daemon = container_of(master, struct daemon, master);
@ -1602,7 +1620,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
return get_peers(conn, daemon, master->msg_in);
case WIRE_GOSSIP_GET_TXOUT_REPLY:
/* FIXME */
return handle_txout_reply(conn, daemon, master->msg_in);
/* We send these, we don't receive them */
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:

183
gossipd/routing.c

@ -1,6 +1,7 @@
#include "routing.h"
#include <arpa/inet.h>
#include <bitcoin/block.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/crypto/siphash24/siphash24.h>
#include <ccan/endian/endian.h>
@ -26,6 +27,22 @@
/* Proportional fee must be less than 24 bits, so never overflows. */
#define MAX_PROPORTIONAL_FEE (1 << 24)
/* We've unpacked and checked its signatures, now we wait for master to tell
* us the txout to check */
struct pending_cannouncement {
struct list_node list;
/* Unpacked fields here */
struct short_channel_id short_channel_id;
struct pubkey node_id_1;
struct pubkey node_id_2;
struct pubkey bitcoin_key_1;
struct pubkey bitcoin_key_2;
/* The raw bits */
const u8 *announce;
};
static struct node_map *empty_node_map(const tal_t *ctx)
{
struct node_map *map = tal(ctx, struct node_map);
@ -43,6 +60,7 @@ struct routing_state *new_routing_state(const tal_t *ctx,
rstate->broadcasts = new_broadcast_state(rstate);
rstate->chain_hash = *chain_hash;
rstate->local_id = *local_id;
list_head_init(&rstate->pending_cannouncement);
return rstate;
}
@ -496,44 +514,39 @@ static bool check_channel_announcement(
check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key);
}
bool handle_channel_announcement(
const struct short_channel_id *handle_channel_announcement(
struct routing_state *rstate,
const u8 *announce)
const u8 *announce TAKES)
{
u8 *serialized;
bool forward = false, local, sigfail;
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 pending_cannouncement *pending;
struct bitcoin_blkid chain_hash;
struct node_connection *c0, *c1;
const tal_t *tmpctx = tal_tmpctx(rstate);
u8 *features;
char *tag;
size_t len = tal_len(announce);
const char *tag;
secp256k1_ecdsa_signature node_signature_1, node_signature_2;
secp256k1_ecdsa_signature bitcoin_signature_1, bitcoin_signature_2;
serialized = tal_dup_arr(tmpctx, u8, announce, len, 0);
if (!fromwire_channel_announcement(tmpctx, serialized, NULL,
&node_signature_1, &node_signature_2,
pending = tal(rstate, struct pending_cannouncement);
pending->announce = tal_dup_arr(pending, u8,
announce, tal_len(announce), 0);
if (!fromwire_channel_announcement(pending, pending->announce, 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 false;
&pending->short_channel_id,
&pending->node_id_1,
&pending->node_id_2,
&pending->bitcoin_key_1,
&pending->bitcoin_key_2)) {
tal_free(pending);
return NULL;
}
tag = type_to_string(tmpctx, struct short_channel_id,
&short_channel_id);
tag = type_to_string(pending, struct short_channel_id,
&pending->short_channel_id);
/* BOLT #7:
*
@ -544,54 +557,120 @@ bool handle_channel_announcement(
status_trace(
"Received channel_announcement %s for unknown chain %s",
tag,
type_to_string(tmpctx, struct bitcoin_blkid, &chain_hash));
tal_free(tmpctx);
return false;
type_to_string(pending, struct bitcoin_blkid, &chain_hash));
tal_free(pending);
return NULL;
}
// FIXME: Check features!
//FIXME(cdecker) Check chain topology for the anchor TX
local = pubkey_eq(&node_id_1, &rstate->local_id) ||
pubkey_eq(&node_id_2, &rstate->local_id);
if (!check_channel_announcement(&pending->node_id_1, &pending->node_id_2,
&pending->bitcoin_key_1,
&pending->bitcoin_key_2,
&node_signature_1,
&node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
pending->announce)) {
status_trace("Signature verification of channel_announcement"
" for %s failed", tag);
tal_free(pending);
return NULL;
}
status_trace("Received channel_announcement for channel %s", tag);
tal_free(tag);
sigfail = !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);
list_add_tail(&rstate->pending_cannouncement, &pending->list);
return &pending->short_channel_id;
}
status_trace("Received channel_announcement for channel %s, local=%d, sigfail=%d",
tag, local, sigfail);
/* While master always processes in order, bitcoind is async, so they could
* theoretically return out of order. */
static struct pending_cannouncement *
find_pending_cannouncement(struct routing_state *rstate,
const struct short_channel_id *scid)
{
struct pending_cannouncement *i;
if (sigfail) {
status_trace(
"Signature verification of channel_announcement for %s failed", tag);
tal_free(tmpctx);
list_for_each(&rstate->pending_cannouncement, i, list) {
if (short_channel_id_eq(scid, &i->short_channel_id))
return i;
}
return NULL;
}
bool handle_pending_cannouncement(struct routing_state *rstate,
const struct short_channel_id *scid,
const u8 *outscript)
{
bool forward, local;
struct node_connection *c0, *c1;
const char *tag;
const u8 *s;
struct pending_cannouncement *pending;
pending = find_pending_cannouncement(rstate, scid);
assert(pending);
list_del_from(&rstate->pending_cannouncement, &pending->list);
tag = type_to_string(pending, struct short_channel_id, scid);
/* BOLT #7:
*
* The receiving node MUST ignore the message if this output is spent.
*/
if (tal_len(outscript) == 0) {
status_trace("channel_announcement: no unspent txout %s", tag);
tal_free(pending);
return false;
}
/* BOLT #7:
*
* The receiving node MUST ignore the message if the output
* specified by `short_channel_id` does not correspond to a
* P2WSH using `bitcoin_key_1` and `bitcoin_key_2` as
* specified in [BOLT
* #3](03-transactions.md#funding-transaction-output).
*/
s = scriptpubkey_p2wsh(pending,
bitcoin_redeem_2of2(pending,
&pending->bitcoin_key_1,
&pending->bitcoin_key_2));
if (!scripteq(s, outscript)) {
status_trace("channel_announcement: txout %s expectes %s, got %s",
tag, tal_hex(trc, s), tal_hex(trc, outscript));
tal_free(pending);
return false;
}
/* Is this a new connection? It is if we don't know the
* channel yet, or do not have a matching announcement in the
* case of side-loaded channels*/
c0 = get_connection(rstate, &node_id_2, &node_id_1);
c1 = get_connection(rstate, &node_id_1, &node_id_2);
c0 = get_connection(rstate, &pending->node_id_2, &pending->node_id_1);
c1 = get_connection(rstate, &pending->node_id_1, &pending->node_id_2);
forward = !c0 || !c1 || !c0->channel_announcement || !c1->channel_announcement;
add_channel_direction(rstate, &node_id_1, &node_id_2, &short_channel_id,
serialized);
add_channel_direction(rstate, &node_id_2, &node_id_1, &short_channel_id,
serialized);
add_channel_direction(rstate, &pending->node_id_1, &pending->node_id_2,
&pending->short_channel_id, pending->announce);
add_channel_direction(rstate, &pending->node_id_2, &pending->node_id_1,
&pending->short_channel_id, pending->announce);
if (forward) {
if (queue_broadcast(rstate->broadcasts,
WIRE_CHANNEL_ANNOUNCEMENT,
(u8*)tag, serialized))
(u8*)tag, pending->announce))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Announcement %s was replaced?",
tal_hex(trc, serialized));
tal_hex(trc, pending->announce));
}
tal_free(tmpctx);
local = pubkey_eq(&pending->node_id_1, &rstate->local_id) ||
pubkey_eq(&pending->node_id_2, &rstate->local_id);
tal_free(pending);
return local && forward;
}

25
gossipd/routing.h

@ -80,6 +80,9 @@ struct routing_state {
/* All known nodes. */
struct node_map *nodes;
/* channel_announcement which are pending short_channel_id lookup */
struct list_head pending_cannouncement;
struct broadcast_state *broadcasts;
struct bitcoin_blkid chain_hash;
@ -117,13 +120,25 @@ struct node_connection *get_connection_by_scid(const struct routing_state *rstat
/* Handlers for incoming messages */
/**
* handle_channel_announcement -- Add channel announcement to state
* handle_channel_announcement -- Check channel announcement is valid
*
* Returns a short_channel_id to look up if signatures pass.
*/
const struct short_channel_id *
handle_channel_announcement(struct routing_state *rstate,
const u8 *announce TAKES);
/**
* handle_pending_cannouncement -- handle channel_announce once we've
* completed short_channel_id lookup.
*
* Returns true if the channel was fully signed and is local. This
* means that if we haven't sent a node_announcement just yet, now
* would be a good time.
* Returns true if the channel was new and is local. This means that
* if we haven't sent a node_announcement just yet, now would be a
* good time.
*/
bool handle_channel_announcement(struct routing_state *rstate, const u8 *announce);
bool handle_pending_cannouncement(struct routing_state *rstate,
const struct short_channel_id *scid,
const u8 *txscript);
void handle_channel_update(struct routing_state *rstate, const u8 *update);
void handle_node_announcement(struct routing_state *rstate, const u8 *node);

Loading…
Cancel
Save