Skip to content

Commit 7e9ce0e

Browse files
author
Chandra Pratap
committed
fuzz-tests: Add a wire test for struct tlv_invoice_request
Changelog-None: `tlv_invoice_request` is a type of message sent and received over the wire. Since there currently exists no test for this message type, add a roundtrip wire test for it.
1 parent 2b8b709 commit 7e9ce0e

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#include "config.h"
2+
#include <ccan/mem/mem.h>
3+
#include <wire/bolt12_wiregen.h>
4+
#include <common/setup.h>
5+
#include <tests/fuzz/libfuzz.h>
6+
#include <wire/peer_wire.h>
7+
8+
static bool sciddir_or_pubkey_eq(const struct sciddir_or_pubkey *a,
9+
const struct sciddir_or_pubkey *b)
10+
{
11+
return memcmp(a, b, sizeof(*a)) == 0;
12+
}
13+
14+
static bool blinded_path_eq(const struct blinded_path *a,
15+
const struct blinded_path *b)
16+
{
17+
if (!sciddir_or_pubkey_eq(&a->first_node_id, &b->first_node_id))
18+
return false;
19+
if (!pubkey_eq(&a->first_path_key, &b->first_path_key))
20+
return false;
21+
if (tal_count(a->path) != tal_count(b->path))
22+
return false;
23+
for (size_t i = 0; i < tal_count(a->path); i++) {
24+
const struct blinded_path_hop *h1 = a->path[i];
25+
const struct blinded_path_hop *h2 = b->path[i];
26+
if (h1 == h2)
27+
continue;
28+
if (!h1 || !h2)
29+
return false;
30+
if (!pubkey_eq(&h1->blinded_node_id, &h2->blinded_node_id))
31+
return false;
32+
if (tal_bytelen(h1->encrypted_recipient_data) !=
33+
tal_bytelen(h2->encrypted_recipient_data))
34+
return false;
35+
if (memcmp(h1->encrypted_recipient_data, h2->encrypted_recipient_data,
36+
tal_bytelen(h1->encrypted_recipient_data)) != 0)
37+
return false;
38+
}
39+
return true;
40+
}
41+
42+
static bool invreq_bip_353_name_eq(const struct tlv_invoice_request_invreq_bip_353_name *a,
43+
const struct tlv_invoice_request_invreq_bip_353_name *b)
44+
{
45+
if (a == b)
46+
return true;
47+
if (!a || !b)
48+
return false;
49+
if (!memeq(a->name, tal_bytelen(a->name), b->name, tal_bytelen(b->name)))
50+
return false;
51+
if (!memeq(a->domain, tal_bytelen(a->domain), b->domain, tal_bytelen(b->domain)))
52+
return false;
53+
return true;
54+
}
55+
56+
static bool tlv_invoice_request_eq(const struct tlv_invoice_request *a, const struct tlv_invoice_request *b)
57+
{
58+
59+
#define PTR_EQ(field, eqfn) \
60+
do { \
61+
if (a->field != b->field) { \
62+
if (!a->field || !b->field) \
63+
return false; \
64+
if (!eqfn(a->field, b->field)) \
65+
return false; \
66+
} \
67+
} while (0)
68+
69+
#define MEM_EQ(field) \
70+
do { \
71+
if (a->field != b->field) { \
72+
if (!a->field || !b->field) \
73+
return false; \
74+
if (tal_bytelen(a->field) != tal_bytelen(b->field)) \
75+
return false; \
76+
if (memcmp(a->field, b->field, tal_bytelen(a->field)) != 0) \
77+
return false; \
78+
} \
79+
} while (0)
80+
81+
#define VAL_EQ(field) \
82+
do { \
83+
if (a->field != b->field) { \
84+
if (!a->field || !b->field) \
85+
return false; \
86+
if (*a->field != *b->field) \
87+
return false; \
88+
} \
89+
} while (0)
90+
91+
#define ARR_EQ(field, eqfn) \
92+
do { \
93+
if (a->field != b->field) { \
94+
if (!a->field || !b->field) \
95+
return false; \
96+
if (tal_count(a->field) != tal_count(b->field)) \
97+
return false; \
98+
for (size_t i = 0; i < tal_count(a->field); i++) { \
99+
if (!eqfn(&a->field[i], &b->field[i])) \
100+
return false; \
101+
} \
102+
} \
103+
} while (0)
104+
105+
#define PTR_ARR_EQ(field, eqfn) \
106+
do { \
107+
if (a->field != b->field) { \
108+
if (!a->field || !b->field) \
109+
return false; \
110+
if (tal_count(a->field) != tal_count(b->field)) \
111+
return false; \
112+
for (size_t i = 0; i < tal_count(a->field); i++) { \
113+
if (!eqfn(a->field[i], b->field[i])) \
114+
return false; \
115+
} \
116+
} \
117+
} while (0)
118+
119+
#define STRUCT_EQ(field, type) \
120+
do { \
121+
if (a->field != b->field) { \
122+
if (!a->field || !b->field) \
123+
return false; \
124+
if (memcmp(a->field, b->field, sizeof(type)) != 0) \
125+
return false; \
126+
} \
127+
} while (0)
128+
129+
MEM_EQ(invreq_metadata);
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+
STRUCT_EQ(offer_recurrence, struct recurrence);
142+
STRUCT_EQ(offer_recurrence_paywindow, struct recurrence_paywindow);
143+
VAL_EQ(offer_recurrence_limit);
144+
STRUCT_EQ(offer_recurrence_base, struct recurrence_base);
145+
PTR_EQ(invreq_chain, bitcoin_blkid_eq);
146+
VAL_EQ(invreq_amount);
147+
MEM_EQ(invreq_features);
148+
VAL_EQ(invreq_quantity);
149+
PTR_EQ(invreq_payer_id, pubkey_eq);
150+
MEM_EQ(invreq_payer_note);
151+
PTR_ARR_EQ(invreq_paths, blinded_path_eq);
152+
PTR_EQ(invreq_bip_353_name, invreq_bip_353_name_eq);
153+
VAL_EQ(invreq_recurrence_counter);
154+
VAL_EQ(invreq_recurrence_start);
155+
STRUCT_EQ(signature, struct bip340sig);
156+
157+
return true;
158+
}
159+
160+
161+
void init(int *argc, char ***argv)
162+
{
163+
common_setup("fuzzer");
164+
}
165+
166+
void run(const u8 *data, size_t size)
167+
{
168+
if (size < sizeof(struct tlv_invoice_request))
169+
return;
170+
171+
struct tlv_invoice_request *invreq = fromwire_tlv_invoice_request(tmpctx, &data, &size);
172+
173+
if (!invreq)
174+
return;
175+
176+
u8 *output_buffer = tal_arr(tmpctx, u8, 0);
177+
towire_tlv_invoice_request(&output_buffer, invreq);
178+
size_t len = tal_bytelen(output_buffer);
179+
180+
struct tlv_invoice_request *decoded_invreq = fromwire_tlv_invoice_request(tmpctx, (const u8 **) &output_buffer, &len);
181+
182+
assert(len == 0);
183+
assert(tlv_invoice_request_eq(invreq, decoded_invreq));
184+
185+
clean_tmpctx();
186+
}
187+

0 commit comments

Comments
 (0)