Skip to content

Commit a818bd2

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 8a0e473 commit a818bd2

File tree

1 file changed

+155
-3
lines changed

1 file changed

+155
-3
lines changed
Lines changed: 155 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,163 @@
78

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

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

168+
cleanup:
17169
clean_tmpctx();
18170
}

0 commit comments

Comments
 (0)