Skip to content

Commit 42c817a

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 ccb1884 commit 42c817a

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;
@@ -563,6 +573,19 @@ static void add_mpp(struct info *info,
563573
tal_free(mp);
564574
}
565575

576+
/* Mutual recursion via timer */
577+
struct delayed_forward {
578+
struct info *info;
579+
struct fake_htlc *htlc;
580+
struct amount_msat amount;
581+
u32 cltv_expiry;
582+
const u8 *onion_routing_packet;
583+
const struct pubkey *path_key;
584+
struct node_id expected;
585+
};
586+
587+
static void delayed_forward(struct delayed_forward *dfwd);
588+
566589
static void forward_htlc(struct info *info,
567590
struct fake_htlc *htlc,
568591
struct amount_msat amount,
@@ -580,6 +603,9 @@ static void forward_htlc(struct info *info,
580603
struct short_channel_id_dir scidd;
581604
struct amount_msat amt_expected, htlc_min, htlc_max;
582605
struct pubkey *next_path_key;
606+
struct oneshot *timer;
607+
struct delayed_forward *dfwd;
608+
unsigned int msec_delay;
583609

584610
/* Decode, and figure out who I am */
585611
payload = decode_onion(tmpctx,
@@ -689,14 +715,38 @@ static void forward_htlc(struct info *info,
689715
} else
690716
next_path_key = NULL;
691717

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

702752
static void handle_offer_htlc(struct info *info, const u8 *inmsg)
@@ -1126,8 +1176,12 @@ int main(int argc, char *argv[])
11261176
info->commit_num = 1;
11271177
info->fakesig.sighash_type = SIGHASH_ALL;
11281178
memset(&info->fakesig.s, 0, sizeof(info->fakesig.s));
1179+
memset(&info->seed, 0, sizeof(info->seed));
1180+
1181+
if (getenv("CHANNELD_FAKENET_SEED"))
1182+
info->seed.u.u64[0] = atol(getenv("CHANNELD_FAKENET_SEED"));
11291183

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

11321186
/* This loop never exits. io_loop() only returns if a timer has
11331187
* 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)