Browse Source

routing: Added IRC announcement glue

Added channel announcement serialization and parsing, as well as the
entrypoints for the IRC peer discovery. Announcements are signed by the
sending endpoint and signatures are verified before adding the channels
to the local view of the topology. We do not yet verify the existence of
the anchor transaction.
ppa-0.6.1
Christian Decker 8 years ago
parent
commit
f4568e5c1c
  1. 6
      bitcoin/signature.c
  2. 4
      bitcoin/signature.h
  3. 21
      daemon/chaintopology.c
  4. 12
      daemon/chaintopology.h
  5. 155
      daemon/irc_announce.c
  6. 9
      daemon/irc_announce.h
  7. 8
      utils.c
  8. 4
      utils.h

6
bitcoin/signature.c

@ -251,6 +251,12 @@ size_t signature_to_der(secp256k1_context *secpctx,
return len;
}
bool signature_from_der(secp256k1_context *secpctx,
const u8 *der, size_t len, struct signature *sig)
{
return secp256k1_ecdsa_signature_parse_der(secpctx, &sig->sig, der, len);
}
/* Signature must have low S value. */
bool sig_valid(secp256k1_context *secpctx, const struct signature *sig)
{

4
bitcoin/signature.h

@ -58,4 +58,8 @@ bool sig_valid(secp256k1_context *secpctx, const struct signature *sig);
size_t signature_to_der(secp256k1_context *secpctx,
u8 der[72], const struct signature *s);
/* Parse DER encoding into signature sig */
bool signature_from_der(secp256k1_context *secpctx,
const u8 *der, size_t len, struct signature *sig);
#endif /* LIGHTNING_BITCOIN_SIGNATURE_H */

21
daemon/chaintopology.c

@ -493,6 +493,27 @@ u64 get_feerate(struct lightningd_state *dstate)
return dstate->topology->feerate;
}
struct txlocator *locate_tx(const void *ctx, struct lightningd_state *dstate,
const struct sha256_double *txid)
{
struct block *block = block_for_tx(dstate, txid);
if (block == NULL) {
return NULL;
}
struct txlocator *loc = talz(ctx, struct txlocator);
loc->blkheight = block->height;
size_t i, n = tal_count(block->txids);
for (i = 0; i < n; i++) {
if (structeq(&block->txids[i], txid)){
loc->index = i;
break;
}
}
return loc;
}
void setup_topology(struct lightningd_state *dstate)
{
dstate->topology = tal(dstate, struct topology);

12
daemon/chaintopology.h

@ -10,6 +10,16 @@ struct peer;
struct sha256_double;
struct txwatch;
/* Information relevant to locating a TX in a blockchain. */
struct txlocator {
/* The height of the block that includes this transaction */
u32 blkheight;
/* Position of the transaction in the transactions list */
u32 index;
};
/* This is the number of blocks which would have to be mined to invalidate
* the tx. */
size_t get_tx_depth(struct lightningd_state *dstate,
@ -33,4 +43,6 @@ void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx);
void setup_topology(struct lightningd_state *dstate);
struct txlocator *locate_tx(const void *ctx, struct lightningd_state *dstate, const struct sha256_double *txid);
#endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */

155
daemon/irc_announce.c

@ -0,0 +1,155 @@
#include "bitcoin/privkey.h"
#include "bitcoin/signature.h"
#include "daemon/chaintopology.h"
#include "daemon/irc_announce.h"
#include "daemon/lightningd.h"
#include "daemon/log.h"
#include "daemon/peer.h"
#include "daemon/routing.h"
#include "daemon/secrets.h"
#include "daemon/timeout.h"
#include "utils.h"
#include <ccan/list/list.h>
#include <ccan/str/hex/hex.h>
static bool announce_channel(const tal_t *ctx, struct ircstate *state, struct peer *p)
{
char txid[65];
int siglen;
u8 der[72];
struct signature sig;
struct privmsg *msg = talz(ctx, struct privmsg);
struct txlocator *loc = locate_tx(ctx, state->dstate, &p->anchor.txid);
if (loc == NULL)
return false;
bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid));
msg->channel = "#lightning-nodes";
msg->msg = tal_fmt(
msg, "CHAN %s %s %s %d %d %d %d %d",
pubkey_to_hexstr(msg, state->dstate->secpctx, &state->dstate->id),
pubkey_to_hexstr(msg, state->dstate->secpctx, p->id),
txid,
loc->blkheight,
loc->index,
state->dstate->config.fee_base,
state->dstate->config.fee_per_satoshi,
p->remote.locktime.locktime
);
privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig);
siglen = signature_to_der(state->dstate->secpctx, der, &sig);
msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(ctx, der, siglen), msg->msg);
irc_send_msg(state, msg);
return true;
}
static void announce_channels(struct ircstate *state)
{
tal_t *ctx = tal(state, tal_t);
struct peer *p;
list_for_each(&state->dstate->peers, p, list) {
if (!state_is_normal(p->state))
continue;
announce_channel(ctx, state, p);
}
tal_free(ctx);
new_reltimer(state->dstate, state, time_from_sec(60), announce_channels, state);
}
/* Reconnect to IRC server upon disconnection. */
static void handle_irc_disconnect(struct ircstate *state)
{
new_reltimer(state->dstate, state, state->reconnect_timeout, irc_connect, state);
}
/*
* Handle an incoming message by checking if it is a channel
* announcement, parse it and add the channel to the topology if yes.
*
* The format for a valid announcement is:
* <sig> CHAN <pk1> <pk2> <anchor txid> <block height> <tx position> <base_fee>
* <proportional_fee> <locktime>
*/
static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg)
{
int blkheight;
char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY);
if (tal_count(splits) != 11 || !streq(splits[1], "CHAN"))
return;
int siglen = hex_data_size(strlen(splits[0]));
u8 *der = tal_hexdata(msg, splits[0], strlen(splits[0]));
if (der == NULL)
return;
struct signature sig;
struct sha256_double hash;
char *content = strchr(msg->msg, ' ') + 1;
if (!signature_from_der(istate->dstate->secpctx, der, siglen, &sig))
return;
sha256_double(&hash, content, strlen(content));
splits++;
struct pubkey *pk1 = talz(msg, struct pubkey);
struct pubkey *pk2 = talz(msg, struct pubkey);
struct sha256_double *txid = talz(msg, struct sha256_double);
int index;
bool ok = true;
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[1], strlen(splits[1]), pk1);
ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[2], strlen(splits[2]), pk2);
ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid);
blkheight = atoi(splits[4]);
index = atoi(splits[5]);
if (!ok || index < 0 || blkheight < 0) {
log_debug(istate->dstate->base_log, "Unable to parse channel announcent.");
return;
}
if (!check_signed_hash(istate->dstate->secpctx, &hash, &sig, pk1)) {
log_debug(istate->log,
"Ignoring announcement from %s, signature check failed.",
splits[1]);
return;
}
/*
* FIXME Check in topology that the tx is in the block and
* that the endpoints match.
*/
add_connection(istate->dstate, pk1, pk2, atoi(splits[6]),
atoi(splits[7]), atoi(splits[8]), 6);
}
void setup_irc_connection(struct lightningd_state *dstate)
{
// Register callback
irc_privmsg_cb = *handle_irc_privmsg;
irc_disconnect_cb = *handle_irc_disconnect;
struct ircstate *state = talz(dstate, struct ircstate);
state->dstate = dstate;
state->server = "irc.freenode.net";
state->reconnect_timeout = time_from_sec(15);
state->log = new_log(state, state->dstate->log_record, "%s:irc",
log_prefix(state->dstate->base_log));
/* Truncate nick at 13 bytes, would be imposed by freenode anyway */
state->nick = tal_fmt(
state,
"N%.12s",
pubkey_to_hexstr(state, dstate->secpctx, &dstate->id) + 1);
irc_connect(state);
announce_channels(state);
}

9
daemon/irc_announce.h

@ -0,0 +1,9 @@
#ifndef LIGHTNING_DAEMON_IRC_ANNOUNCE_H
#define LIGHTNING_DAEMON_IRC_ANNOUNCE_H
#include "config.h"
#include "irc.h"
// Main entrypoint for the lightning daemon
void setup_irc_connection(struct lightningd_state *dstate);
#endif /* LIGHTNING_DAEMON_IRC_ANNOUNCE_H */

8
utils.c

@ -7,3 +7,11 @@ char *tal_hexstr(const tal_t *ctx, const void *data, size_t len)
hex_encode(data, len, str, hex_str_size(len));
return str;
}
u8 *tal_hexdata(const tal_t *ctx, const void *str, size_t len)
{
u8 *data = tal_arr(ctx, u8, hex_data_size(len));
if (!hex_decode(str, len, data, hex_data_size(len)))
return NULL;
return data;
}

4
utils.h

@ -1,9 +1,13 @@
#ifndef LIGHTNING_UTILS_H
#define LIGHTNING_UTILS_H
#include "config.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
/* Allocate and fill in a hex-encoded string of this data. */
char *tal_hexstr(const tal_t *ctx, const void *data, size_t len);
/* Allocate and fill a buffer with the data of this hex string. */
u8 *tal_hexdata(const tal_t *ctx, const void *str, size_t len);
#endif /* LIGHTNING_UTILS_H */

Loading…
Cancel
Save