Skip to content

Commit 50a59c5

Browse files
author
Chandra Pratap
committed
fuzz-tests: add test for amount-{sat, msat} arithmetic
The fuzz-amount test doesn't fuzz the arithmetic operations for `struct amount_sat` and `struct amount_msat`. Add a test for the same.
1 parent 44972b2 commit 50a59c5

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed

tests/fuzz/fuzz-amount-arith.c

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#include "config.h"
2+
#include <assert.h>
3+
#include <math.h>
4+
#include <common/amount.h>
5+
#include <tests/fuzz/libfuzz.h>
6+
7+
void init(int *argc, char ***argv) {}
8+
9+
enum op {
10+
OP_MSAT_ADD,
11+
OP_MSAT_SUB,
12+
OP_MSAT_MUL,
13+
OP_MSAT_DIV,
14+
OP_MSAT_RATIO,
15+
OP_MSAT_RATIO_FLOOR,
16+
OP_MSAT_RATIO_CEIL,
17+
OP_MSAT_SCALE,
18+
OP_MSAT_ADD_SAT,
19+
OP_MSAT_SUB_SAT,
20+
OP_SAT_ADD,
21+
OP_SAT_SUB,
22+
OP_SAT_MUL,
23+
OP_SAT_DIV,
24+
OP_SAT_SCALE,
25+
OP_FEE,
26+
OP_ADD_FEE,
27+
OP_SUB_FEE,
28+
OP_TX_FEE,
29+
OP_FEERATE,
30+
OP_COUNT
31+
};
32+
33+
void run(const uint8_t *data, size_t size) {
34+
if (size < sizeof(uint8_t) + 2 * sizeof(struct amount_msat) + sizeof(double))
35+
return;
36+
37+
uint8_t op = *data++ % OP_COUNT;
38+
39+
struct amount_msat a = fromwire_amount_msat(&data, &size);
40+
struct amount_msat b = fromwire_amount_msat(&data, &size);
41+
42+
double f;
43+
memcpy(&f, data, sizeof(f));
44+
data += sizeof(f);
45+
46+
struct amount_sat sa = amount_msat_to_sat_round_down(a);
47+
struct amount_sat sb = amount_msat_to_sat_round_down(b);
48+
49+
u64 u64_param;
50+
memcpy(&u64_param, &f, sizeof(u64_param));
51+
52+
struct amount_msat out_ms;
53+
struct amount_sat out_s;
54+
55+
switch (op) {
56+
case OP_MSAT_ADD:
57+
{
58+
if (amount_msat_add(&out_ms, a, b)) {
59+
assert(out_ms.millisatoshis == a.millisatoshis + b.millisatoshis);
60+
}
61+
break;
62+
}
63+
64+
case OP_MSAT_SUB:
65+
{
66+
if (amount_msat_sub(&out_ms, a, b)) {
67+
assert(out_ms.millisatoshis + b.millisatoshis == a.millisatoshis);
68+
}
69+
break;
70+
}
71+
72+
case OP_MSAT_MUL:
73+
{
74+
if (amount_msat_mul(&out_ms, a, u64_param)) {
75+
assert(out_ms.millisatoshis == a.millisatoshis * u64_param);
76+
}
77+
break;
78+
}
79+
80+
case OP_MSAT_DIV:
81+
{
82+
if (u64_param == 0)
83+
break;
84+
out_ms = amount_msat_div(a, u64_param);
85+
assert(out_ms.millisatoshis == a.millisatoshis / u64_param);
86+
break;
87+
}
88+
89+
case OP_MSAT_RATIO:
90+
{
91+
if (b.millisatoshis == 0)
92+
break;
93+
double ratio = amount_msat_ratio(a, b);
94+
double expected = (double)a.millisatoshis / b.millisatoshis;
95+
assert(ratio == expected);
96+
break;
97+
}
98+
99+
case OP_MSAT_RATIO_FLOOR:
100+
{
101+
if (b.millisatoshis == 0)
102+
break;
103+
u64 floor = amount_msat_ratio_floor(a, b);
104+
assert(floor == a.millisatoshis / b.millisatoshis);
105+
break;
106+
}
107+
108+
case OP_MSAT_RATIO_CEIL:
109+
{
110+
if (b.millisatoshis == 0)
111+
break;
112+
u64 ceil = amount_msat_ratio_ceil(a, b);
113+
u64 quotient = a.millisatoshis / b.millisatoshis;
114+
u64 remainder = a.millisatoshis % b.millisatoshis;
115+
assert(ceil == quotient + (remainder != 0));
116+
break;
117+
}
118+
119+
case OP_MSAT_SCALE:
120+
{
121+
if (amount_msat_scale(&out_ms, a, f)) {
122+
double expect = (double)a.millisatoshis * f;
123+
assert(fabs((double)out_ms.millisatoshis - expect) < 1.0);
124+
}
125+
break;
126+
}
127+
128+
case OP_MSAT_ADD_SAT:
129+
{
130+
if (amount_msat_add_sat(&out_ms, a, sa)) {
131+
assert(out_ms.millisatoshis == sa.satoshis * MSAT_PER_SAT + a.millisatoshis);
132+
}
133+
break;
134+
}
135+
136+
case OP_MSAT_SUB_SAT:
137+
{
138+
if (amount_msat_sub_sat(&out_ms, a, sa)) {
139+
assert(out_ms.millisatoshis + sa.satoshis * MSAT_PER_SAT == a.millisatoshis);
140+
}
141+
break;
142+
}
143+
144+
case OP_SAT_ADD:
145+
{
146+
if (amount_sat_add(&out_s, sa, sb)) {
147+
assert(out_s.satoshis == sa.satoshis + sb.satoshis);
148+
}
149+
break;
150+
}
151+
152+
case OP_SAT_SUB:
153+
{
154+
if (amount_sat_sub(&out_s, sa, sb)) {
155+
assert(out_s.satoshis == sa.satoshis - sb.satoshis);
156+
}
157+
break;
158+
}
159+
160+
case OP_SAT_MUL:
161+
{
162+
if (amount_sat_mul(&out_s, sa, u64_param)) {
163+
assert(out_s.satoshis == sa.satoshis * u64_param);
164+
}
165+
break;
166+
}
167+
168+
case OP_SAT_DIV:
169+
{
170+
if (u64_param == 0)
171+
break;
172+
out_s = amount_sat_div(sa, u64_param);
173+
assert(out_s.satoshis == sa.satoshis / u64_param);
174+
break;
175+
}
176+
177+
case OP_SAT_SCALE:
178+
{
179+
if (amount_sat_scale(&out_s, sa, f)) {
180+
double expect = sa.satoshis * f;
181+
assert(fabs((double)out_s.satoshis - expect) < 1.0);
182+
}
183+
break;
184+
}
185+
186+
case OP_FEE:
187+
{
188+
if (amount_msat_fee(&out_ms, a, (u32)(a.millisatoshis & UINT32_MAX), (u32)(b.millisatoshis & UINT32_MAX))) {
189+
assert(out_ms.millisatoshis >= (a.millisatoshis & UINT32_MAX));
190+
}
191+
break;
192+
}
193+
194+
case OP_ADD_FEE:
195+
{
196+
u32 fee_base = (u32)(a.millisatoshis & UINT32_MAX);
197+
u32 fee_prop = (u32)(b.millisatoshis & UINT32_MAX);
198+
if (amount_msat_add_fee(&a, fee_base, fee_prop)) {
199+
struct amount_msat fee;
200+
if (amount_msat_fee(&fee, a, fee_base, fee_prop)) {
201+
assert(amount_msat_greater_eq(a, fee));
202+
}
203+
}
204+
break;
205+
}
206+
207+
case OP_SUB_FEE:
208+
{
209+
u32 fee_base = (u32)(a.millisatoshis & UINT32_MAX);
210+
u32 fee_prop = (u32)(b.millisatoshis & UINT32_MAX);
211+
struct amount_msat input = a;
212+
struct amount_msat output = amount_msat_sub_fee(input, fee_base, fee_prop);
213+
struct amount_msat fee;
214+
if (amount_msat_fee(&fee, input, fee_base, fee_prop)) {
215+
struct amount_msat sum;
216+
if (amount_msat_add(&sum, output, fee)) {
217+
assert(amount_msat_less_eq(sum, input));
218+
}
219+
}
220+
break;
221+
}
222+
223+
case OP_TX_FEE:
224+
{
225+
if (b.millisatoshis > SIZE_MAX)
226+
break;
227+
u32 fee_per_kw = (u32)(a.millisatoshis & UINT32_MAX);
228+
size_t weight = (size_t)(b.millisatoshis);
229+
struct amount_sat fee = amount_tx_fee(fee_per_kw, weight);
230+
u64 expected = (fee_per_kw * weight) / MSAT_PER_SAT;
231+
assert(fee.satoshis == expected);
232+
break;
233+
}
234+
235+
case OP_FEERATE:
236+
{
237+
struct amount_sat fee = amount_msat_to_sat_round_down(a);
238+
size_t weight = (size_t)(b.millisatoshis);
239+
u32 feerate;
240+
if (amount_feerate(&feerate, fee, weight)) {
241+
u64 expected = (fee.satoshis * MSAT_PER_SAT) / weight;
242+
assert(feerate == expected);
243+
}
244+
break;
245+
}
246+
247+
default:
248+
assert(false && "unknown operation");
249+
}
250+
}

0 commit comments

Comments
 (0)