Skip to content

Commit 72220bc

Browse files
committed
channeld_fakenet: add deterministic delays.
100ms to 1 second per hop. We don't do delays on the way back though! Signed-off-by: Rusty Russell <[email protected]>
1 parent d0e312e commit 72220bc

File tree

2 files changed

+67
-12
lines changed

2 files changed

+67
-12
lines changed

tests/plugins/channeld_fakenet.c

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ struct info {
5656
size_t commit_num;
5757
/* MPP parts we've gathered */
5858
struct multi_payment **multi_payments;
59-
/* For MPP timers */
59+
/* For MPP timers, delay timers */
6060
struct timers timers;
61+
/* Seed for channel feature determination (e.g. delay time) */
62+
struct siphash_seed seed;
6163

6264
/* Fake stuff we feed into lightningd */
6365
struct fee_states *fee_states;
@@ -130,6 +132,14 @@ static const char *fmt_nodeidx(const tal_t *ctx, size_t idx)
130132
return tal_fmt(ctx, "gossmap-node-%zu", idx >> 1);
131133
}
132134

135+
/* Return deterministic value >= min < max for this channel */
136+
static u64 channel_range(const struct info *info,
137+
const struct short_channel_id_dir *scidd,
138+
u64 min, u64 max)
139+
{
140+
return min + (siphash24(&info->seed, scidd, sizeof(scidd)) % max);
141+
}
142+
133143
void ecdh(const struct pubkey *point, struct secret *ss)
134144
{
135145
struct privkey pk;
@@ -559,6 +569,19 @@ static void add_mpp(struct info *info,
559569
tal_free(mp);
560570
}
561571

572+
/* Mutual recursion via timer */
573+
struct delayed_forward {
574+
struct info *info;
575+
struct fake_htlc *htlc;
576+
struct amount_msat amount;
577+
u32 cltv_expiry;
578+
const u8 *onion_routing_packet;
579+
const struct pubkey *path_key;
580+
struct node_id expected;
581+
};
582+
583+
static void delayed_forward(struct delayed_forward *dfwd);
584+
562585
static void forward_htlc(struct info *info,
563586
struct fake_htlc *htlc,
564587
struct amount_msat amount,
@@ -576,6 +599,9 @@ static void forward_htlc(struct info *info,
576599
struct short_channel_id_dir scidd;
577600
struct amount_msat amt_expected, htlc_min, htlc_max;
578601
struct pubkey *next_path_key;
602+
struct oneshot *timer;
603+
struct delayed_forward *dfwd;
604+
unsigned int msec_delay;
579605

580606
/* Decode, and figure out who I am */
581607
payload = decode_onion(tmpctx,
@@ -685,14 +711,38 @@ static void forward_htlc(struct info *info,
685711
} else
686712
next_path_key = NULL;
687713

688-
/* Limited recursion for the "next node" */
689-
forward_htlc(info,
690-
htlc,
691-
payload->amt_to_forward,
692-
payload->outgoing_cltv,
693-
next_onion_packet,
694-
next_path_key,
695-
&next);
714+
dfwd = tal(NULL, struct delayed_forward);
715+
dfwd->info = info;
716+
dfwd->htlc = htlc;
717+
dfwd->amount = payload->amt_to_forward;
718+
dfwd->cltv_expiry = payload->outgoing_cltv;
719+
dfwd->onion_routing_packet = tal_steal(dfwd, next_onion_packet);
720+
dfwd->path_key = tal_steal(dfwd, next_path_key);
721+
dfwd->expected = next;
722+
723+
/* Delay 0.1 - 1 seconds, but skewed lower */
724+
msec_delay = channel_range(info, &scidd, 0, 900);
725+
msec_delay = 100 + channel_range(info, &scidd, 0, msec_delay);
726+
727+
status_debug("Delaying %u msec for %s",
728+
msec_delay, fmt_short_channel_id_dir(tmpctx, &scidd));
729+
timer = new_reltimer(&info->timers,
730+
info,
731+
time_from_msec(msec_delay),
732+
delayed_forward, dfwd);
733+
/* Free dfwd after timer expires */
734+
tal_steal(timer, dfwd);
735+
}
736+
737+
static void delayed_forward(struct delayed_forward *dfwd)
738+
{
739+
forward_htlc(dfwd->info,
740+
dfwd->htlc,
741+
dfwd->amount,
742+
dfwd->cltv_expiry,
743+
dfwd->onion_routing_packet,
744+
dfwd->path_key,
745+
&dfwd->expected);
696746
}
697747

698748
static void handle_offer_htlc(struct info *info, const u8 *inmsg)
@@ -1122,8 +1172,12 @@ int main(int argc, char *argv[])
11221172
info->commit_num = 1;
11231173
info->fakesig.sighash_type = SIGHASH_ALL;
11241174
memset(&info->fakesig.s, 0, sizeof(info->fakesig.s));
1175+
memset(&info->seed, 0, sizeof(info->seed));
1176+
1177+
if (getenv("CHANNELD_FAKENET_SEED"))
1178+
info->seed.u.u64[0] = atol(getenv("CHANNELD_FAKENET_SEED"));
11251179

1126-
status_debug("Waiting for init...");
1180+
status_debug("channeld_fakenet seed is %"PRIu64, info->seed.u.u64[0]);
11271181

11281182
/* This loop never exits. io_loop() only returns if a timer has
11291183
* expired, or io_break() is called, or all fds are closed. We don't

tests/test_askrene.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,5 +1054,6 @@ def test_askrene_fake_channeld(node_factory, bitcoind):
10541054
payment_secret='00' * 32,
10551055
partid=i + 1, groupid=1)
10561056

1057-
for i, _ in enumerate(routes['routes']):
1058-
assert l1.rpc.waitsendpay(hash_hex, timeout=TIMEOUT, partid=i + 1, groupid=1)['payment_preimage'] == preimage_hex
1057+
for i, r in enumerate(routes['routes']):
1058+
# Worst-case timeout is 1 second per hop.
1059+
assert l1.rpc.waitsendpay(hash_hex, timeout=TIMEOUT + len(r['path']), partid=i + 1, groupid=1)['payment_preimage'] == preimage_hex

0 commit comments

Comments
 (0)