Browse Source

lightningd: addgossip API to inject gossip messages.

Importantly, this is synchronous, so pay will be able to use it
reliably.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
master
Rusty Russell 4 years ago
committed by Christian Decker
parent
commit
3c5502426b
  1. 9
      contrib/pyln-client/pyln/client/lightning.py
  2. 70
      gossipd/gossipd.c
  3. 10
      gossipd/gossipd_wire.csv
  4. 57
      gossipd/gossipd_wiregen.c
  5. 16
      gossipd/gossipd_wiregen.h
  6. 30
      gossipd/routing.c
  7. 51
      lightningd/gossip_control.c
  8. 44
      tests/test_gossip.py

9
contrib/pyln-client/pyln/client/lightning.py

@ -484,6 +484,15 @@ class LightningRpc(UnixDomainSocketRpc):
if patch_json: if patch_json:
monkey_patch_json(patch=True) monkey_patch_json(patch=True)
def addgossip(self, message):
"""
Inject this (hex-encoded) gossip message.
"""
payload = {
"message": message,
}
return self.call("addgossip", payload)
def autocleaninvoice(self, cycle_seconds=None, expired_by=None): def autocleaninvoice(self, cycle_seconds=None, expired_by=None):
""" """
Sets up automatic cleaning of expired invoices. {cycle_seconds} sets Sets up automatic cleaning of expired invoices. {cycle_seconds} sets

70
gossipd/gossipd.c

@ -230,7 +230,8 @@ static bool get_node_announcement_by_id(const tal_t *ctx,
* message, and puts the announcemnt on an internal 'pending' * message, and puts the announcemnt on an internal 'pending'
* queue. We'll send a request to lightningd to look it up, and continue * queue. We'll send a request to lightningd to look it up, and continue
* processing in `handle_txout_reply`. */ * processing in `handle_txout_reply`. */
static const u8 *handle_channel_announcement_msg(struct peer *peer, static const u8 *handle_channel_announcement_msg(struct daemon *daemon,
struct peer *peer,
const u8 *msg) const u8 *msg)
{ {
const struct short_channel_id *scid; const struct short_channel_id *scid;
@ -239,20 +240,20 @@ static const u8 *handle_channel_announcement_msg(struct peer *peer,
/* If it's OK, tells us the short_channel_id to lookup; it notes /* If it's OK, tells us the short_channel_id to lookup; it notes
* if this is the unknown channel the peer was looking for (in * if this is the unknown channel the peer was looking for (in
* which case, it frees and NULLs that ptr) */ * which case, it frees and NULLs that ptr) */
err = handle_channel_announcement(peer->daemon->rstate, msg, err = handle_channel_announcement(daemon->rstate, msg,
peer->daemon->current_blockheight, daemon->current_blockheight,
&scid, peer); &scid, peer);
if (err) if (err)
return err; return err;
else if (scid) { else if (scid) {
/* We give them some grace period, in case we don't know about /* We give them some grace period, in case we don't know about
* block yet. */ * block yet. */
if (peer->daemon->current_blockheight == 0 if (daemon->current_blockheight == 0
|| !is_scid_depth_announceable(scid, || !is_scid_depth_announceable(scid,
peer->daemon->current_blockheight)) { daemon->current_blockheight)) {
tal_arr_expand(&peer->daemon->deferred_txouts, *scid); tal_arr_expand(&daemon->deferred_txouts, *scid);
} else { } else {
daemon_conn_send(peer->daemon->master, daemon_conn_send(daemon->master,
take(towire_gossipd_get_txout(NULL, take(towire_gossipd_get_txout(NULL,
scid))); scid)));
} }
@ -420,7 +421,7 @@ static bool handle_local_channel_announcement(struct daemon *daemon,
return false; return false;
} }
err = handle_channel_announcement_msg(peer, cannouncement); err = handle_channel_announcement_msg(daemon, peer, cannouncement);
if (err) { if (err) {
status_broken("peer %s invalid local_channel_announcement %s (%s)", status_broken("peer %s invalid local_channel_announcement %s (%s)",
type_to_string(tmpctx, struct node_id, &peer->id), type_to_string(tmpctx, struct node_id, &peer->id),
@ -705,7 +706,7 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
/* These are messages relayed from peer */ /* These are messages relayed from peer */
switch ((enum peer_wire)fromwire_peektype(msg)) { switch ((enum peer_wire)fromwire_peektype(msg)) {
case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_ANNOUNCEMENT:
err = handle_channel_announcement_msg(peer, msg); err = handle_channel_announcement_msg(peer->daemon, peer, msg);
goto handled_relay; goto handled_relay;
case WIRE_CHANNEL_UPDATE: case WIRE_CHANNEL_UPDATE:
err = handle_channel_update_msg(peer, msg); err = handle_channel_update_msg(peer, msg);
@ -1809,6 +1810,53 @@ static struct io_plan *handle_payment_failure(struct io_conn *conn,
return daemon_conn_read_next(conn, daemon->master); return daemon_conn_read_next(conn, daemon->master);
} }
/*~ lightningd tells us when about a gossip message directly, when told to by
* the addgossip RPC call. That's usually used when a plugin gets an update
* returned in an payment error. */
static struct io_plan *inject_gossip(struct io_conn *conn,
struct daemon *daemon,
const u8 *msg)
{
u8 *goss;
const u8 *errmsg;
const char *err;
if (!fromwire_gossipd_addgossip(msg, msg, &goss))
master_badmsg(WIRE_GOSSIPD_ADDGOSSIP, msg);
switch (fromwire_peektype(goss)) {
case WIRE_CHANNEL_ANNOUNCEMENT:
errmsg = handle_channel_announcement_msg(daemon, NULL, goss);
break;
case WIRE_NODE_ANNOUNCEMENT:
errmsg = handle_node_announcement(daemon->rstate, goss,
NULL, NULL);
break;
case WIRE_CHANNEL_UPDATE:
errmsg = handle_channel_update(daemon->rstate, goss,
NULL, NULL, true);
break;
default:
err = tal_fmt(tmpctx, "unknown gossip type %i",
fromwire_peektype(goss));
goto err_extracted;
}
/* The APIs above are designed to send error messages back to peers:
* we extract the raw string instead. */
if (errmsg) {
err = sanitize_error(tmpctx, errmsg, NULL);
tal_free(errmsg);
} else
/* Send empty string if no error. */
err = "";
err_extracted:
daemon_conn_send(daemon->master,
take(towire_gossipd_addgossip_reply(NULL, err)));
return daemon_conn_read_next(conn, daemon->master);
}
/*~ This is where lightningd tells us that a channel's funding transaction has /*~ This is where lightningd tells us that a channel's funding transaction has
* been spent. */ * been spent. */
static struct io_plan *handle_outpoint_spent(struct io_conn *conn, static struct io_plan *handle_outpoint_spent(struct io_conn *conn,
@ -1908,6 +1956,9 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
return new_blockheight(conn, daemon, msg); return new_blockheight(conn, daemon, msg);
case WIRE_GOSSIPD_ADDGOSSIP:
return inject_gossip(conn, daemon, msg);
#if DEVELOPER #if DEVELOPER
case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
return dev_set_max_scids_encode_size(conn, daemon, msg); return dev_set_max_scids_encode_size(conn, daemon, msg);
@ -1942,6 +1993,7 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY:
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD: case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
break; break;
} }

10
gossipd/gossipd_wire.csv

@ -161,3 +161,13 @@ msgdata,gossipd_send_onionmsg,id,node_id,
msgdata,gossipd_send_onionmsg,onion_len,u16, msgdata,gossipd_send_onionmsg,onion_len,u16,
msgdata,gossipd_send_onionmsg,onion,u8,onion_len msgdata,gossipd_send_onionmsg,onion,u8,onion_len
msgdata,gossipd_send_onionmsg,blinding,?pubkey, msgdata,gossipd_send_onionmsg,blinding,?pubkey,
# Lightningd tells us to inject a gossip message (for addgossip RPC)
msgtype,gossipd_addgossip,3044
msgdata,gossipd_addgossip,len,u16,
msgdata,gossipd_addgossip,msg,u8,len
# Empty string means no problem.
msgtype,gossipd_addgossip_reply,3144
msgdata,gossipd_addgossip_reply,err,wirestring,

Can't render this file because it has a wrong number of fields in line 7.

57
gossipd/gossipd_wiregen.c

@ -49,6 +49,8 @@ const char *gossipd_wire_name(int e)
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: return "WIRE_GOSSIPD_GOT_ONIONMSG_TO_US"; case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: return "WIRE_GOSSIPD_GOT_ONIONMSG_TO_US";
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD: return "WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD"; case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD: return "WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD";
case WIRE_GOSSIPD_SEND_ONIONMSG: return "WIRE_GOSSIPD_SEND_ONIONMSG"; case WIRE_GOSSIPD_SEND_ONIONMSG: return "WIRE_GOSSIPD_SEND_ONIONMSG";
case WIRE_GOSSIPD_ADDGOSSIP: return "WIRE_GOSSIPD_ADDGOSSIP";
case WIRE_GOSSIPD_ADDGOSSIP_REPLY: return "WIRE_GOSSIPD_ADDGOSSIP_REPLY";
} }
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -87,6 +89,8 @@ bool gossipd_wire_is_defined(u16 type)
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:; case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:;
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:; case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:;
case WIRE_GOSSIPD_SEND_ONIONMSG:; case WIRE_GOSSIPD_SEND_ONIONMSG:;
case WIRE_GOSSIPD_ADDGOSSIP:;
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:;
return true; return true;
} }
return false; return false;
@ -1033,4 +1037,55 @@ bool fromwire_gossipd_send_onionmsg(const tal_t *ctx, const void *p, struct node
} }
return cursor != NULL; return cursor != NULL;
} }
// SHA256STAMP:1da012a28ad84883f18920e51c39a0af77f85e309e981f9ea8d158d0698f6a59
/* WIRE: GOSSIPD_ADDGOSSIP */
/* Lightningd tells us to inject a gossip message (for addgossip RPC) */
u8 *towire_gossipd_addgossip(const tal_t *ctx, const u8 *msg)
{
u16 len = tal_count(msg);
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOSSIPD_ADDGOSSIP);
towire_u16(&p, len);
towire_u8_array(&p, msg, len);
return memcheck(p, tal_count(p));
}
bool fromwire_gossipd_addgossip(const tal_t *ctx, const void *p, u8 **msg)
{
u16 len;
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_ADDGOSSIP)
return false;
len = fromwire_u16(&cursor, &plen);
// 2nd case msg
*msg = len ? tal_arr(ctx, u8, len) : NULL;
fromwire_u8_array(&cursor, &plen, *msg, len);
return cursor != NULL;
}
/* WIRE: GOSSIPD_ADDGOSSIP_REPLY */
/* Empty string means no problem. */
u8 *towire_gossipd_addgossip_reply(const tal_t *ctx, const wirestring *err)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOSSIPD_ADDGOSSIP_REPLY);
towire_wirestring(&p, err);
return memcheck(p, tal_count(p));
}
bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestring **err)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_ADDGOSSIP_REPLY)
return false;
*err = fromwire_wirestring(ctx, &cursor, &plen);
return cursor != NULL;
}
// SHA256STAMP:e82edc5625085e21b02b27a2293d9d757556f3090a8a20b142dcb73411307a0c

16
gossipd/gossipd_wiregen.h

@ -65,6 +65,10 @@ enum gossipd_wire {
WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD = 3143, WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD = 3143,
/* Lightningd tells us to send a onion message. */ /* Lightningd tells us to send a onion message. */
WIRE_GOSSIPD_SEND_ONIONMSG = 3040, WIRE_GOSSIPD_SEND_ONIONMSG = 3040,
/* Lightningd tells us to inject a gossip message (for addgossip RPC) */
WIRE_GOSSIPD_ADDGOSSIP = 3044,
/* Empty string means no problem. */
WIRE_GOSSIPD_ADDGOSSIP_REPLY = 3144,
}; };
const char *gossipd_wire_name(int e); const char *gossipd_wire_name(int e);
@ -216,6 +220,16 @@ bool fromwire_gossipd_got_onionmsg_forward(const tal_t *ctx, const void *p, stru
u8 *towire_gossipd_send_onionmsg(const tal_t *ctx, const struct node_id *id, const u8 *onion, const struct pubkey *blinding); u8 *towire_gossipd_send_onionmsg(const tal_t *ctx, const struct node_id *id, const u8 *onion, const struct pubkey *blinding);
bool fromwire_gossipd_send_onionmsg(const tal_t *ctx, const void *p, struct node_id *id, u8 **onion, struct pubkey **blinding); bool fromwire_gossipd_send_onionmsg(const tal_t *ctx, const void *p, struct node_id *id, u8 **onion, struct pubkey **blinding);
/* WIRE: GOSSIPD_ADDGOSSIP */
/* Lightningd tells us to inject a gossip message (for addgossip RPC) */
u8 *towire_gossipd_addgossip(const tal_t *ctx, const u8 *msg);
bool fromwire_gossipd_addgossip(const tal_t *ctx, const void *p, u8 **msg);
/* WIRE: GOSSIPD_ADDGOSSIP_REPLY */
/* Empty string means no problem. */
u8 *towire_gossipd_addgossip_reply(const tal_t *ctx, const wirestring *err);
bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestring **err);
#endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */
// SHA256STAMP:1da012a28ad84883f18920e51c39a0af77f85e309e981f9ea8d158d0698f6a59 // SHA256STAMP:e82edc5625085e21b02b27a2293d9d757556f3090a8a20b142dcb73411307a0c

30
gossipd/routing.c

@ -1394,13 +1394,13 @@ static u8 *check_channel_update(const tal_t *ctx,
return towire_errorfmt(ctx, NULL, return towire_errorfmt(ctx, NULL,
"Bad signature for %s hash %s" "Bad signature for %s hash %s"
" on channel_update %s", " on channel_update %s",
type_to_string(ctx, type_to_string(tmpctx,
secp256k1_ecdsa_signature, secp256k1_ecdsa_signature,
node_sig), node_sig),
type_to_string(ctx, type_to_string(tmpctx,
struct sha256_double, struct sha256_double,
&hash), &hash),
tal_hex(ctx, update)); tal_hex(tmpctx, update));
return NULL; return NULL;
} }
@ -1422,49 +1422,49 @@ static u8 *check_channel_announcement(const tal_t *ctx,
return towire_errorfmt(ctx, NULL, return towire_errorfmt(ctx, NULL,
"Bad node_signature_1 %s hash %s" "Bad node_signature_1 %s hash %s"
" on channel_announcement %s", " on channel_announcement %s",
type_to_string(ctx, type_to_string(tmpctx,
secp256k1_ecdsa_signature, secp256k1_ecdsa_signature,
node1_sig), node1_sig),
type_to_string(ctx, type_to_string(tmpctx,
struct sha256_double, struct sha256_double,
&hash), &hash),
tal_hex(ctx, announcement)); tal_hex(tmpctx, announcement));
} }
if (!check_signed_hash_nodeid(&hash, node2_sig, node2_id)) { if (!check_signed_hash_nodeid(&hash, node2_sig, node2_id)) {
return towire_errorfmt(ctx, NULL, return towire_errorfmt(ctx, NULL,
"Bad node_signature_2 %s hash %s" "Bad node_signature_2 %s hash %s"
" on channel_announcement %s", " on channel_announcement %s",
type_to_string(ctx, type_to_string(tmpctx,
secp256k1_ecdsa_signature, secp256k1_ecdsa_signature,
node2_sig), node2_sig),
type_to_string(ctx, type_to_string(tmpctx,
struct sha256_double, struct sha256_double,
&hash), &hash),
tal_hex(ctx, announcement)); tal_hex(tmpctx, announcement));
} }
if (!check_signed_hash(&hash, bitcoin1_sig, bitcoin1_key)) { if (!check_signed_hash(&hash, bitcoin1_sig, bitcoin1_key)) {
return towire_errorfmt(ctx, NULL, return towire_errorfmt(ctx, NULL,
"Bad bitcoin_signature_1 %s hash %s" "Bad bitcoin_signature_1 %s hash %s"
" on channel_announcement %s", " on channel_announcement %s",
type_to_string(ctx, type_to_string(tmpctx,
secp256k1_ecdsa_signature, secp256k1_ecdsa_signature,
bitcoin1_sig), bitcoin1_sig),
type_to_string(ctx, type_to_string(tmpctx,
struct sha256_double, struct sha256_double,
&hash), &hash),
tal_hex(ctx, announcement)); tal_hex(tmpctx, announcement));
} }
if (!check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key)) { if (!check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key)) {
return towire_errorfmt(ctx, NULL, return towire_errorfmt(ctx, NULL,
"Bad bitcoin_signature_2 %s hash %s" "Bad bitcoin_signature_2 %s hash %s"
" on channel_announcement %s", " on channel_announcement %s",
type_to_string(ctx, type_to_string(tmpctx,
secp256k1_ecdsa_signature, secp256k1_ecdsa_signature,
bitcoin2_sig), bitcoin2_sig),
type_to_string(ctx, type_to_string(tmpctx,
struct sha256_double, struct sha256_double,
&hash), &hash),
tal_hex(ctx, announcement)); tal_hex(tmpctx, announcement));
} }
return NULL; return NULL;
} }

51
lightningd/gossip_control.c

@ -151,6 +151,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_DEV_SET_TIME: case WIRE_GOSSIPD_DEV_SET_TIME:
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_SEND_ONIONMSG:
case WIRE_GOSSIPD_ADDGOSSIP:
/* This is a reply, so never gets through to here. */ /* This is a reply, so never gets through to here. */
case WIRE_GOSSIPD_GETNODES_REPLY: case WIRE_GOSSIPD_GETNODES_REPLY:
case WIRE_GOSSIPD_GETROUTE_REPLY: case WIRE_GOSSIPD_GETROUTE_REPLY:
@ -159,6 +160,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY:
case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY:
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
break; break;
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
@ -576,6 +578,55 @@ static const struct json_command listchannels_command = {
}; };
AUTODATA(json_command, &listchannels_command); AUTODATA(json_command, &listchannels_command);
/* Called upon receiving a addgossip_reply from `gossipd` */
static void json_addgossip_reply(struct subd *gossip UNUSED, const u8 *reply,
const int *fds UNUSED,
struct command *cmd)
{
char *err;
if (!fromwire_gossipd_addgossip_reply(reply, reply, &err)) {
/* Shouldn't happen: just end json stream. */
log_broken(cmd->ld->log,
"Invalid addgossip_reply from gossipd: %s",
tal_hex(tmpctx, reply));
was_pending(command_fail(cmd, LIGHTNINGD,
"Invalid reply from gossipd"));
return;
}
if (strlen(err))
was_pending(command_fail(cmd, LIGHTNINGD, "%s", err));
else
was_pending(command_success(cmd, json_stream_success(cmd)));
}
static struct command_result *json_addgossip(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
u8 *req, *gossip_msg;
if (!param(cmd, buffer, params,
p_req("message", param_bin_from_hex, &gossip_msg),
NULL))
return command_param_failed();
req = towire_gossipd_addgossip(cmd, gossip_msg);
subd_req(cmd->ld->gossip, cmd->ld->gossip,
req, -1, 0, json_addgossip_reply, cmd);
return command_still_pending(cmd);
}
static const struct json_command addgossip_command = {
"addgossip",
"utility",
json_addgossip,
"Inject gossip {message} into gossipd"
};
AUTODATA(json_command, &addgossip_command);
#if DEVELOPER #if DEVELOPER
static struct command_result * static struct command_result *
json_dev_set_max_scids_encode_size(struct command *cmd, json_dev_set_max_scids_encode_size(struct command *cmd,

44
tests/test_gossip.py

@ -1799,3 +1799,47 @@ def test_routetool(node_factory):
l1.info['id'], l1.info['id'],
l2.info['id']], l2.info['id']],
check=True, timeout=TIMEOUT) check=True, timeout=TIMEOUT)
def test_addgossip(node_factory):
l1, l2 = node_factory.line_graph(2, fundchannel=True, wait_for_announce=True,
opts={'log-level': 'io'})
# We should get two node_announcements, one channel_announcement, and two
# channel_update.
l3 = node_factory.get_node()
# 0x0100 = channel_announcement
# 0x0102 = channel_update
# 0x0101 = node_announcement
ann = l1.daemon.is_in_log(r"\[OUT\] 0100.*")
if ann is None:
ann = l2.daemon.is_in_log(r"\[OUT\] 0100.*")
upd1 = l1.daemon.is_in_log(r"\[OUT\] 0102.*")
upd2 = l2.daemon.is_in_log(r"\[OUT\] 0102.*")
nann1 = l1.daemon.is_in_log(r"\[OUT\] 0101.*")
nann2 = l2.daemon.is_in_log(r"\[OUT\] 0101.*")
# Feed them to l3 (Each one starts with TIMESTAMP chanid-xxx: [OUT] ...)
l3.rpc.addgossip(ann.split()[3])
l3.rpc.addgossip(upd1.split()[3])
l3.rpc.addgossip(upd2.split()[3])
l3.rpc.addgossip(nann1.split()[3])
l3.rpc.addgossip(nann2.split()[3])
# In this case, it can actually have to wait, since it does scid lookup.
wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 2)
wait_for(lambda: len(l3.rpc.listnodes()['nodes']) == 2)
# Now corrupt an update
badupdate = upd1.split()[3]
if badupdate.endswith('f'):
badupdate = badupdate[:-1] + 'e'
else:
badupdate = badupdate[:-1] + 'f'
with pytest.raises(RpcError, match='Bad signature'):
l3.rpc.addgossip(badupdate)

Loading…
Cancel
Save