Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bitcoin/signature.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions bitcoin/signature.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 */
2 changes: 2 additions & 0 deletions daemon/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ DAEMON_SRC := \
daemon/feechange.c \
daemon/htlc.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
Expand All@@ -41,6 +42,7 @@ DAEMON_SRC := \
daemon/wallet.c \
daemon/watch.c \
names.c \
irc.c \
state.c

DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
Expand Down
21 changes: 21 additions & 0 deletions daemon/chaintopology.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
Expand Down
12 changes: 12 additions & 0 deletions daemon/chaintopology.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -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,
Expand All@@ -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 changes: 155 additions & 0 deletions daemon/irc_announce.c
Original file line numberDiff line numberDiff line change
@@ -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 changes: 9 additions & 0 deletions daemon/irc_announce.h
Original file line numberDiff line numberDiff line change
@@ -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 */
11 changes: 11 additions & 0 deletions daemon/lightningd.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@
#include "configdir.h"
#include "controlled_time.h"
#include "db.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
Expand DownExpand Up@@ -145,6 +146,9 @@ static void config_register_opts(struct lightningd_state *dstate)
dstate,
"Add route of form srcid/dstid/base/var/delay/minblocks"
"(base in millisatoshi, var in millionths of satoshi per satoshi)");
opt_register_noarg("--disable-irc", opt_set_invbool,
&dstate->config.use_irc,
"Disable IRC peer discovery for routing");
}

static void dev_register_opts(struct lightningd_state *dstate)
Expand DownExpand Up@@ -210,6 +214,9 @@ static void default_config(struct config *config)
config->fee_base = 546000;
/* Take 0.001% */
config->fee_per_satoshi = 10;

/* Discover new peers using IRC */
config->use_irc = true;
}

static void check_config(struct lightningd_state *dstate)
Expand DownExpand Up@@ -360,6 +367,10 @@ int main(int argc, char *argv[])
/* Set up connections from peers. */
setup_listeners(dstate, portnum);

/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);

/* Make sure we use the artificially-controlled time for timers */
io_time_override(controlled_time);

Expand Down
3 changes: 3 additions & 0 deletions daemon/lightningd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,9 @@ struct config {

/* How long between changing commit and sending COMMIT message. */
struct timerel commit_time;

/* Whether to enable IRC peer discovery. */
bool use_irc;
};

/* Here's where the global variables hide! */
Expand Down
Loading