Skip to content

Commit af9fa71

Browse files
author
Chandra Pratap
committed
fuzz-tests: Make fuzz-bolt12-invrequest-decode roundrip
Changelog-None: Currently, the `BOLT #12` invrequest parsing test only tests the invrequest decode function. Add a test for the encoding function as well by making the test roundtrip.
1 parent 725c417 commit af9fa71

File tree

1 file changed

+187
-3
lines changed

1 file changed

+187
-3
lines changed
Lines changed: 187 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "config.h"
2+
#include <ccan/mem/mem.h>
23
#include <common/bolt12.h>
34
#include <common/utils.h>
45
#include <stddef.h>
@@ -7,12 +8,195 @@
78

89
const char *bech32_hrp = "lnr";
910

11+
static bool sciddir_or_pubkey_eq(const struct sciddir_or_pubkey *a,
12+
const struct sciddir_or_pubkey *b)
13+
{
14+
if (a->is_pubkey != b->is_pubkey)
15+
return false;
16+
if (a->is_pubkey)
17+
return pubkey_eq(&a->pubkey, &b->pubkey);
18+
else
19+
return short_channel_id_dir_eq(&a->scidd, &b->scidd);
20+
}
21+
22+
static bool recurrence_eq(const struct recurrence *a, const struct recurrence *b)
23+
{
24+
return a->time_unit == b->time_unit && a->period == b->period;
25+
}
26+
27+
static bool recurrence_paywindow_eq(const struct recurrence_paywindow *a,
28+
const struct recurrence_paywindow *b)
29+
{
30+
return a->seconds_before == b->seconds_before &&
31+
a->proportional_amount == b->proportional_amount &&
32+
a->seconds_after == b->seconds_after;
33+
}
34+
35+
static bool recurrence_base_eq(const struct recurrence_base *a,
36+
const struct recurrence_base *b)
37+
{
38+
return a->start_any_period == b->start_any_period &&
39+
a->basetime == b->basetime;
40+
}
41+
42+
static bool bip340sig_eq(const struct bip340sig *a, const struct bip340sig *b)
43+
{
44+
return !memcmp(a, b, sizeof(struct bip340sig));
45+
}
46+
47+
static bool blinded_path_eq(const struct blinded_path *a, const struct blinded_path *b)
48+
{
49+
if (!sciddir_or_pubkey_eq(&a->first_node_id, &b->first_node_id))
50+
return false;
51+
if (!pubkey_eq(&a->first_path_key, &b->first_path_key))
52+
return false;
53+
if (tal_count(a->path) != tal_count(b->path))
54+
return false;
55+
for (size_t i = 0; i < tal_count(a->path); i++) {
56+
const struct blinded_path_hop *h1 = a->path[i];
57+
const struct blinded_path_hop *h2 = b->path[i];
58+
if (h1 == h2)
59+
continue;
60+
if (!h1 || !h2)
61+
return false;
62+
if (!pubkey_eq(&h1->blinded_node_id, &h2->blinded_node_id))
63+
return false;
64+
if (tal_bytelen(h1->encrypted_recipient_data) !=
65+
tal_bytelen(h2->encrypted_recipient_data))
66+
return false;
67+
if (memcmp(h1->encrypted_recipient_data, h2->encrypted_recipient_data,
68+
tal_bytelen(h1->encrypted_recipient_data)) != 0)
69+
return false;
70+
}
71+
return true;
72+
}
73+
74+
static bool invreq_bip_353_name_eq(const struct tlv_invoice_request_invreq_bip_353_name *a,
75+
const struct tlv_invoice_request_invreq_bip_353_name *b)
76+
{
77+
if (a == b)
78+
return true;
79+
if (!a || !b)
80+
return false;
81+
if (!memeq(a->name, tal_bytelen(a->name), b->name, tal_bytelen(b->name)))
82+
return false;
83+
if (!memeq(a->domain, tal_bytelen(a->domain), b->domain, tal_bytelen(b->domain)))
84+
return false;
85+
return true;
86+
}
87+
88+
static bool tlv_invoice_request_eq(const struct tlv_invoice_request *a, const struct tlv_invoice_request *b)
89+
{
90+
91+
#define PTR_EQ(field, eqfn) \
92+
do { \
93+
if (a->field != b->field) { \
94+
if (!a->field || !b->field) \
95+
return false; \
96+
if (!eqfn(a->field, b->field)) \
97+
return false; \
98+
} \
99+
} while (0)
100+
101+
#define MEM_EQ(field) \
102+
do { \
103+
if (a->field != b->field) { \
104+
if (!a->field || !b->field) \
105+
return false; \
106+
if (tal_bytelen(a->field) != tal_bytelen(b->field)) \
107+
return false; \
108+
if (memcmp(a->field, b->field, tal_bytelen(a->field)) != 0) \
109+
return false; \
110+
} \
111+
} while (0)
112+
113+
#define VAL_EQ(field) \
114+
do { \
115+
if (a->field != b->field) { \
116+
if (!a->field || !b->field) \
117+
return false; \
118+
if (*a->field != *b->field) \
119+
return false; \
120+
} \
121+
} while (0)
122+
123+
#define ARR_EQ(field, eqfn) \
124+
do { \
125+
if (a->field != b->field) { \
126+
if (!a->field || !b->field) \
127+
return false; \
128+
if (tal_count(a->field) != tal_count(b->field)) \
129+
return false; \
130+
for (size_t i = 0; i < tal_count(a->field); i++) { \
131+
if (!eqfn(&a->field[i], &b->field[i])) \
132+
return false; \
133+
} \
134+
} \
135+
} while (0)
136+
137+
#define PTR_ARR_EQ(field, eqfn) \
138+
do { \
139+
if (a->field != b->field) { \
140+
if (!a->field || !b->field) \
141+
return false; \
142+
if (tal_count(a->field) != tal_count(b->field)) \
143+
return false; \
144+
for (size_t i = 0; i < tal_count(a->field); i++) { \
145+
if (!eqfn(a->field[i], b->field[i])) \
146+
return false; \
147+
} \
148+
} \
149+
} while (0)
150+
151+
MEM_EQ(invreq_metadata);
152+
ARR_EQ(offer_chains, bitcoin_blkid_eq);
153+
MEM_EQ(offer_metadata);
154+
MEM_EQ(offer_currency);
155+
VAL_EQ(offer_amount);
156+
MEM_EQ(offer_description);
157+
MEM_EQ(offer_features);
158+
VAL_EQ(offer_absolute_expiry);
159+
PTR_ARR_EQ(offer_paths, blinded_path_eq);
160+
MEM_EQ(offer_issuer);
161+
VAL_EQ(offer_quantity_max);
162+
PTR_EQ(offer_issuer_id, pubkey_eq);
163+
PTR_EQ(offer_recurrence, recurrence_eq);
164+
PTR_EQ(offer_recurrence_paywindow, recurrence_paywindow_eq);
165+
VAL_EQ(offer_recurrence_limit);
166+
PTR_EQ(offer_recurrence_base, recurrence_base_eq);
167+
PTR_EQ(invreq_chain, bitcoin_blkid_eq);
168+
VAL_EQ(invreq_amount);
169+
MEM_EQ(invreq_features);
170+
VAL_EQ(invreq_quantity);
171+
PTR_EQ(invreq_payer_id, pubkey_eq);
172+
MEM_EQ(invreq_payer_note);
173+
PTR_ARR_EQ(invreq_paths, blinded_path_eq);
174+
PTR_EQ(invreq_bip_353_name, invreq_bip_353_name_eq);
175+
VAL_EQ(invreq_recurrence_counter);
176+
VAL_EQ(invreq_recurrence_start);
177+
PTR_EQ(signature, bip340sig_eq);
178+
179+
return true;
180+
}
181+
10182
void run(const u8 *data, size_t size)
11183
{
12-
char *fail;
184+
struct tlv_invoice_request *invreq, *decoded_invreq;
185+
char *fail = NULL, *encoded_invreq;
186+
187+
invreq = invrequest_decode(tmpctx, (const char *)data, size,
188+
/*feature_set=*/NULL, /*must_be_chain=*/NULL, &fail);
189+
if (!invreq)
190+
goto cleanup;
191+
192+
encoded_invreq = invrequest_encode(tmpctx, invreq);
13193

14-
invrequest_decode(tmpctx, (const char *)data, size,
15-
/*feature_set=*/NULL, /*must_be_chain=*/NULL, &fail);
194+
decoded_invreq = invrequest_decode(tmpctx, encoded_invreq, strlen(encoded_invreq),
195+
NULL, NULL, &fail);
196+
assert(!fail);
197+
assert(decoded_invreq);
198+
assert(tlv_invoice_request_eq(invreq, decoded_invreq));
16199

200+
cleanup:
17201
clean_tmpctx();
18202
}

0 commit comments

Comments
 (0)