Skip to content

Commit 0023f88

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

File tree

1 file changed

+157
-4
lines changed

1 file changed

+157
-4
lines changed
Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,171 @@
11
#include "config.h"
2+
#include <assert.h>
3+
#include <stddef.h>
4+
#include <ccan/mem/mem.h>
25
#include <common/bolt12.h>
36
#include <common/utils.h>
4-
#include <stddef.h>
57
#include <tests/fuzz/bolt12.h>
68
#include <tests/fuzz/libfuzz.h>
79

810
const char *bech32_hrp = "lno";
911

12+
static bool sciddir_or_pubkey_eq(const struct sciddir_or_pubkey *a,
13+
const struct sciddir_or_pubkey *b)
14+
{
15+
if (a->is_pubkey != b->is_pubkey)
16+
return false;
17+
if (a->is_pubkey)
18+
return pubkey_eq(&a->pubkey, &b->pubkey);
19+
else
20+
return short_channel_id_dir_eq(&a->scidd, &b->scidd);
21+
}
22+
23+
static bool recurrence_eq(const struct recurrence *a, const struct recurrence *b)
24+
{
25+
return a->time_unit == b->time_unit && a->period == b->period;
26+
}
27+
28+
static bool recurrence_paywindow_eq(const struct recurrence_paywindow *a,
29+
const struct recurrence_paywindow *b)
30+
{
31+
return a->seconds_before == b->seconds_before && a->seconds_after == b->seconds_after;
32+
}
33+
34+
static bool recurrence_base_eq(const struct recurrence_base *a,
35+
const struct recurrence_base *b)
36+
{
37+
return a->basetime == b->basetime && a->proportional_amount == b->proportional_amount;
38+
}
39+
40+
static bool blinded_path_eq(const struct blinded_path *a,
41+
const struct blinded_path *b)
42+
{
43+
if (!sciddir_or_pubkey_eq(&a->first_node_id, &b->first_node_id))
44+
return false;
45+
if (!pubkey_eq(&a->first_path_key, &b->first_path_key))
46+
return false;
47+
if (tal_count(a->path) != tal_count(b->path))
48+
return false;
49+
for (size_t i = 0; i < tal_count(a->path); i++) {
50+
const struct blinded_path_hop *h1 = a->path[i];
51+
const struct blinded_path_hop *h2 = b->path[i];
52+
if (h1 == h2)
53+
continue;
54+
if (!h1 || !h2)
55+
return false;
56+
if (!pubkey_eq(&h1->blinded_node_id, &h2->blinded_node_id))
57+
return false;
58+
if (tal_bytelen(h1->encrypted_recipient_data) !=
59+
tal_bytelen(h2->encrypted_recipient_data))
60+
return false;
61+
if (memcmp(h1->encrypted_recipient_data, h2->encrypted_recipient_data,
62+
tal_bytelen(h1->encrypted_recipient_data)) != 0)
63+
return false;
64+
}
65+
return true;
66+
}
67+
68+
static bool tlv_offer_eq(const struct tlv_offer *a, const struct tlv_offer *b)
69+
{
70+
71+
#define PTR_EQ(field, eqfn) \
72+
do { \
73+
if (a->field != b->field) { \
74+
if (!a->field || !b->field) \
75+
return false; \
76+
if (!eqfn(a->field, b->field)) \
77+
return false; \
78+
} \
79+
} while (0)
80+
81+
#define MEM_EQ(field) \
82+
do { \
83+
if (a->field != b->field) { \
84+
if (!a->field || !b->field) \
85+
return false; \
86+
if (tal_bytelen(a->field) != tal_bytelen(b->field)) \
87+
return false; \
88+
if (memcmp(a->field, b->field, tal_bytelen(a->field)) != 0) \
89+
return false; \
90+
} \
91+
} while (0)
92+
93+
#define VAL_EQ(field) \
94+
do { \
95+
if (a->field != b->field) { \
96+
if (!a->field || !b->field) \
97+
return false; \
98+
if (*a->field != *b->field) \
99+
return false; \
100+
} \
101+
} while (0)
102+
103+
#define ARR_EQ(field, eqfn) \
104+
do { \
105+
if (a->field != b->field) { \
106+
if (!a->field || !b->field) \
107+
return false; \
108+
if (tal_count(a->field) != tal_count(b->field)) \
109+
return false; \
110+
for (size_t i = 0; i < tal_count(a->field); i++) { \
111+
if (!eqfn(&a->field[i], &b->field[i])) \
112+
return false; \
113+
} \
114+
} \
115+
} while (0)
116+
117+
#define PTR_ARR_EQ(field, eqfn) \
118+
do { \
119+
if (a->field != b->field) { \
120+
if (!a->field || !b->field) \
121+
return false; \
122+
if (tal_count(a->field) != tal_count(b->field)) \
123+
return false; \
124+
for (size_t i = 0; i < tal_count(a->field); i++) { \
125+
if (!eqfn(a->field[i], b->field[i])) \
126+
return false; \
127+
} \
128+
} \
129+
} while (0)
130+
131+
ARR_EQ(offer_chains, bitcoin_blkid_eq);
132+
MEM_EQ(offer_metadata);
133+
MEM_EQ(offer_currency);
134+
VAL_EQ(offer_amount);
135+
MEM_EQ(offer_description);
136+
MEM_EQ(offer_features);
137+
VAL_EQ(offer_absolute_expiry);
138+
PTR_ARR_EQ(offer_paths, blinded_path_eq);
139+
MEM_EQ(offer_issuer);
140+
VAL_EQ(offer_quantity_max);
141+
PTR_EQ(offer_issuer_id, pubkey_eq);
142+
PTR_EQ(offer_recurrence_compulsory, recurrence_eq);
143+
PTR_EQ(offer_recurrence_optional, recurrence_eq);
144+
PTR_EQ(offer_recurrence_base, recurrence_base_eq);
145+
PTR_EQ(offer_recurrence_paywindow, recurrence_paywindow_eq);
146+
VAL_EQ(offer_recurrence_limit);
147+
148+
return true;
149+
}
150+
10151
void run(const u8 *data, size_t size)
11152
{
12-
char *fail;
153+
struct tlv_offer *offer, *decoded_offer;
154+
char *fail = NULL, *encoded_offer;
155+
156+
offer = offer_decode(tmpctx, (const char *)data, size,
157+
/*feature_set=*/NULL, /*must_be_chain=*/NULL, &fail);
158+
if (!offer)
159+
goto cleanup;
160+
161+
encoded_offer = offer_encode(tmpctx, offer);
13162

14-
offer_decode(tmpctx, (const char *)data, size, /*feature_set=*/NULL,
15-
/*must_be_chain=*/NULL, &fail);
163+
decoded_offer = offer_decode(tmpctx, encoded_offer, strlen(encoded_offer),
164+
NULL, NULL, &fail);
165+
assert(!fail);
166+
assert(decoded_offer);
167+
assert(tlv_offer_eq(offer, decoded_offer));
16168

169+
cleanup:
17170
clean_tmpctx();
18171
}

0 commit comments

Comments
 (0)