Skip to content

Commit 4f9c213

Browse files
committed
routing: Refactoring IRC announcements.
Moving all IRC related functionality from routing.c into its own module so that we can replace it later.
1 parent 6ca7802 commit 4f9c213

File tree

7 files changed

+167
-149
lines changed

7 files changed

+167
-149
lines changed

daemon/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ DAEMON_SRC := \
2626
daemon/feechange.c \
2727
daemon/htlc.c \
2828
daemon/invoice.c \
29+
daemon/irc_announce.c \
2930
daemon/jsonrpc.c \
3031
daemon/lightningd.c \
3132
daemon/netaddr.c \

daemon/irc_announce.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#include "bitcoin/privkey.h"
2+
#include "bitcoin/signature.h"
3+
#include "daemon/chaintopology.h"
4+
#include "daemon/irc_announce.h"
5+
#include "daemon/lightningd.h"
6+
#include "daemon/log.h"
7+
#include "daemon/peer.h"
8+
#include "daemon/routing.h"
9+
#include "daemon/secrets.h"
10+
#include "daemon/timeout.h"
11+
#include "utils.h"
12+
13+
#include <ccan/list/list.h>
14+
#include <ccan/str/hex/hex.h>
15+
16+
static bool announce_channel(const tal_t *ctx, struct ircstate *state, struct peer *p)
17+
{
18+
char txid[65];
19+
int siglen;
20+
u8 der[72];
21+
struct signature sig;
22+
struct privmsg *msg = talz(ctx, struct privmsg);
23+
struct txlocator *loc = locate_tx(ctx, state->dstate, &p->anchor.txid);
24+
25+
if (loc == NULL)
26+
return false;
27+
28+
bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid));
29+
msg->channel = "#lightning-nodes";
30+
msg->msg = tal_fmt(
31+
msg, "CHAN %s %s %s %d %d %d %d %d",
32+
pubkey_to_hexstr(msg, state->dstate->secpctx, &state->dstate->id),
33+
pubkey_to_hexstr(msg, state->dstate->secpctx, p->id),
34+
txid,
35+
loc->blkheight,
36+
loc->index,
37+
state->dstate->config.fee_base,
38+
state->dstate->config.fee_per_satoshi,
39+
p->remote.locktime.locktime
40+
);
41+
42+
privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig);
43+
siglen = signature_to_der(state->dstate->secpctx, der, &sig);
44+
msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(ctx, der, siglen), msg->msg);
45+
46+
irc_send_msg(state, msg);
47+
return true;
48+
}
49+
50+
static void announce_channels(struct ircstate *state)
51+
{
52+
tal_t *ctx = tal(state, tal_t);
53+
struct peer *p;
54+
55+
list_for_each(&state->dstate->peers, p, list) {
56+
57+
if (!state_is_normal(p->state))
58+
continue;
59+
announce_channel(ctx, state, p);
60+
}
61+
tal_free(ctx);
62+
63+
new_reltimer(state->dstate, state, time_from_sec(60), announce_channels, state);
64+
}
65+
66+
/* Reconnect to IRC server upon disconnection. */
67+
static void handle_irc_disconnect(struct ircstate *state)
68+
{
69+
new_reltimer(state->dstate, state, state->reconnect_timeout, irc_connect, state);
70+
}
71+
72+
/*
73+
* Handle an incoming message by checking if it is a channel
74+
* announcement, parse it and add the channel to the topology if yes.
75+
*
76+
* The format for a valid announcement is:
77+
* <sig> CHAN <pk1> <pk2> <anchor txid> <block height> <tx position> <base_fee>
78+
* <proportional_fee> <locktime>
79+
*/
80+
static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg)
81+
{
82+
int blkheight;
83+
char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY);
84+
85+
if (tal_count(splits) != 11 || !streq(splits[1], "CHAN"))
86+
return;
87+
88+
int siglen = hex_data_size(strlen(splits[0]));
89+
u8 *der = tal_hexdata(msg, splits[0], strlen(splits[0]));
90+
if (der == NULL)
91+
return;
92+
93+
struct signature sig;
94+
struct sha256_double hash;
95+
char *content = strchr(msg->msg, ' ') + 1;
96+
if (!signature_from_der(istate->dstate->secpctx, der, siglen, &sig))
97+
return;
98+
99+
sha256_double(&hash, content, strlen(content));
100+
splits++;
101+
102+
struct pubkey *pk1 = talz(msg, struct pubkey);
103+
struct pubkey *pk2 = talz(msg, struct pubkey);
104+
struct sha256_double *txid = talz(msg, struct sha256_double);
105+
int index;
106+
107+
bool ok = true;
108+
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[1], strlen(splits[1]), pk1);
109+
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[2], strlen(splits[2]), pk2);
110+
ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid);
111+
blkheight = atoi(splits[4]);
112+
index = atoi(splits[5]);
113+
if (!ok || index < 0 || blkheight < 0) {
114+
log_debug(istate->dstate->base_log, "Unable to parse channel announcent.");
115+
return;
116+
}
117+
118+
if (!check_signed_hash(istate->dstate->secpctx, &hash, &sig, pk1)) {
119+
log_debug(istate->log,
120+
"Ignoring announcement from %s, signature check failed.",
121+
splits[1]);
122+
return;
123+
}
124+
125+
/*
126+
* FIXME Check in topology that the tx is in the block and
127+
* that the endpoints match.
128+
*/
129+
130+
add_connection(istate->dstate, pk1, pk2, atoi(splits[6]),
131+
atoi(splits[7]), atoi(splits[8]), 6);
132+
}
133+
134+
void setup_irc_connection(struct lightningd_state *dstate)
135+
{
136+
// Register callback
137+
irc_privmsg_cb = *handle_irc_privmsg;
138+
irc_disconnect_cb = *handle_irc_disconnect;
139+
140+
struct ircstate *state = talz(dstate, struct ircstate);
141+
state->dstate = dstate;
142+
state->server = "irc.freenode.net";
143+
state->reconnect_timeout = time_from_sec(15);
144+
state->log = new_log(state, state->dstate->log_record, "%s:irc",
145+
log_prefix(state->dstate->base_log));
146+
147+
/* Truncate nick at 13 bytes, would be imposed by freenode anyway */
148+
state->nick = tal_fmt(
149+
state,
150+
"N%.12s",
151+
pubkey_to_hexstr(state, dstate->secpctx, &dstate->id) + 1);
152+
153+
irc_connect(state);
154+
announce_channels(state);
155+
}

daemon/irc_announce.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef LIGHTNING_DAEMON_IRC_ANNOUNCE_H
2+
#define LIGHTNING_DAEMON_IRC_ANNOUNCE_H
3+
#include "config.h"
4+
#include "irc.h"
5+
6+
// Main entrypoint for the lightning daemon
7+
void setup_irc_connection(struct lightningd_state *dstate);
8+
9+
#endif /* LIGHTNING_DAEMON_IRC_ANNOUNCE_H */

daemon/lightningd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "configdir.h"
44
#include "controlled_time.h"
55
#include "db.h"
6+
#include "irc_announce.h"
67
#include "jsonrpc.h"
78
#include "lightningd.h"
89
#include "log.h"

daemon/lightningd.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#define LIGHTNING_DAEMON_LIGHTNING_H
33
#include "config.h"
44
#include "bitcoin/pubkey.h"
5-
#include "routing.h"
65
#include "watch.h"
76
#include <ccan/list/list.h>
87
#include <ccan/short_types/short_types.h>

daemon/routing.c

Lines changed: 1 addition & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
#include "jsonrpc.h"
2-
#include "bitcoin/block.h"
3-
#include "chaintopology.h"
4-
#include "daemon/secrets.h"
52
#include "lightningd.h"
63
#include "log.h"
74
#include "overflows.h"
85
#include "peer.h"
96
#include "pseudorand.h"
107
#include "routing.h"
11-
#include "timeout.h"
12-
#include "utils.h"
138
#include <ccan/array_size/array_size.h>
149
#include <ccan/crypto/siphash24/siphash24.h>
1510
#include <ccan/htable/htable_type.h>
16-
#include <ccan/str/hex/hex.h>
1711
#include <ccan/structeq/structeq.h>
18-
#include <ccan/tal/str/str.h>
1912
#include <inttypes.h>
2013

2114
/* 365.25 * 24 * 60 / 10 */
@@ -490,146 +483,10 @@ static void json_routefail(struct command *cmd,
490483

491484
command_success(cmd, null_response(cmd));
492485
}
486+
493487
const struct json_command dev_routefail_command = {
494488
"dev-routefail",
495489
json_routefail,
496490
"FAIL htlcs that we can't route if {enable}",
497491
"Returns an empty result on success"
498492
};
499-
500-
static void announce_channels(struct ircstate *state)
501-
{
502-
tal_t *ctx = tal(state, tal_t);
503-
char txid[65];
504-
struct peer *p;
505-
506-
list_for_each(&state->dstate->peers, p, list) {
507-
508-
if (!state_is_normal(p->state))
509-
continue;
510-
511-
struct txlocator *loc = locate_tx(ctx, state->dstate, &p->anchor.txid);
512-
if (loc == NULL)
513-
continue;
514-
515-
bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid));
516-
struct privmsg *msg = talz(state, struct privmsg);
517-
msg->channel = "#lightning-nodes";
518-
msg->msg = tal_fmt(
519-
msg, "CHAN %s %s %s %d %d %d %d %d",
520-
pubkey_to_hexstr(msg, state->dstate->secpctx, &state->dstate->id),
521-
pubkey_to_hexstr(msg, state->dstate->secpctx, p->id),
522-
txid,
523-
loc->blkheight,
524-
loc->index,
525-
state->dstate->config.fee_base,
526-
state->dstate->config.fee_per_satoshi,
527-
p->remote.locktime.locktime
528-
);
529-
530-
struct signature sig;
531-
u8 der[72];
532-
533-
memset(der, 0, sizeof(der));
534-
privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig);
535-
int numbytes = signature_to_der(state->dstate->secpctx, der, &sig);
536-
msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(ctx, der, numbytes), msg->msg);
537-
538-
irc_send_msg(state, msg);
539-
tal_free(loc);
540-
}
541-
tal_free(ctx);
542-
543-
new_reltimer(state->dstate, state, time_from_sec(60), announce_channels, state);
544-
}
545-
546-
/* Reconnect to IRC server upon disconnection. */
547-
static void handle_irc_disconnect(struct ircstate *state)
548-
{
549-
new_reltimer(state->dstate, state, state->reconnect_timeout, irc_connect, state);
550-
}
551-
552-
/*
553-
* Handle an incoming message by checking if it is a channel
554-
* announcement, parse it and add the channel to the topology if yes.
555-
*
556-
* The format for a valid announcement is:
557-
* <sig> CHAN <pk1> <pk2> <anchor txid> <block height> <tx position> <base_fee>
558-
* <proportional_fee> <locktime>
559-
*/
560-
static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg)
561-
{
562-
int blkheight;
563-
char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY);
564-
565-
if (tal_count(splits) != 11 || !streq(splits[1], "CHAN"))
566-
return;
567-
568-
int siglen = hex_data_size(strlen(splits[0]));
569-
u8 *der = tal_hexdata(msg, splits[0], strlen(splits[0]));
570-
if (der == NULL)
571-
return;
572-
573-
struct signature sig;
574-
struct sha256_double hash;
575-
char *content = strchr(msg->msg, ' ') + 1;
576-
if (!signature_from_der(istate->dstate->secpctx, der, siglen, &sig))
577-
return;
578-
579-
sha256_double(&hash, content, strlen(content));
580-
splits++;
581-
582-
struct pubkey *pk1 = talz(msg, struct pubkey);
583-
struct pubkey *pk2 = talz(msg, struct pubkey);
584-
struct sha256_double *txid = talz(msg, struct sha256_double);
585-
int index;
586-
587-
bool ok = true;
588-
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[1], strlen(splits[1]), pk1);
589-
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[2], strlen(splits[2]), pk2);
590-
ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid);
591-
blkheight = atoi(splits[4]);
592-
index = atoi(splits[5]);
593-
if (!ok || index < 0 || blkheight < 0) {
594-
log_debug(istate->dstate->base_log, "Unable to parse channel announcent.");
595-
return;
596-
}
597-
598-
if(!check_signed_hash(istate->dstate->secpctx, &hash, &sig, pk1)){
599-
log_debug(istate->log,
600-
"Ignoring announcement from %s, signature check failed.",
601-
splits[1]);
602-
return;
603-
}
604-
605-
/*
606-
* FIXME Check in topology that the tx is in the block and
607-
* that the endpoints match.
608-
*/
609-
610-
add_connection(istate->dstate, pk1, pk2, atoi(splits[6]),
611-
atoi(splits[7]), atoi(splits[8]), 6);
612-
}
613-
614-
void setup_irc_connection(struct lightningd_state *dstate)
615-
{
616-
// Register callback
617-
irc_privmsg_cb = *handle_irc_privmsg;
618-
irc_disconnect_cb = *handle_irc_disconnect;
619-
620-
struct ircstate *state = talz(dstate, struct ircstate);
621-
state->dstate = dstate;
622-
state->server = "irc.freenode.net";
623-
state->reconnect_timeout = time_from_sec(15);
624-
state->log = new_log(state, state->dstate->log_record, "%s:irc",
625-
log_prefix(state->dstate->base_log));
626-
627-
/* Truncate nick at 13 bytes, would be imposed by freenode anyway */
628-
state->nick = tal_fmt(
629-
state,
630-
"N%.12s",
631-
pubkey_to_hexstr(state, dstate->secpctx, &dstate->id) + 1);
632-
633-
irc_connect(state);
634-
announce_channels(state);
635-
}

daemon/routing.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#define LIGHTNING_DAEMON_ROUTING_H
33
#include "config.h"
44
#include "bitcoin/pubkey.h"
5-
#include "irc.h"
65

76
#define ROUTING_MAX_HOPS 20
87

@@ -68,7 +67,4 @@ struct node_map *empty_node_map(struct lightningd_state *dstate);
6867

6968
char *opt_add_route(const char *arg, struct lightningd_state *dstate);
7069

71-
// Main entrypoint for the lightning daemon
72-
void setup_irc_connection(struct lightningd_state *dstate);
73-
7470
#endif /* LIGHTNING_DAEMON_ROUTING_H */

0 commit comments

Comments
 (0)