Nobody ever runs `make check-includes` with fuzzing enabled. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
168 lines
5.5 KiB
C
168 lines
5.5 KiB
C
#include "config.h"
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <common/setup.h>
|
|
#include <stdio.h>
|
|
#include <tests/fuzz/libfuzz.h>
|
|
#include <wire/wire.h>
|
|
|
|
#include "../../plugins/funder_policy.c"
|
|
|
|
/* AUTOGENERATED MOCKS START */
|
|
/* Generated stub for json_add_string */
|
|
void json_add_string(struct json_stream *js UNNEEDED,
|
|
const char *fieldname UNNEEDED,
|
|
const char *str TAKES UNNEEDED)
|
|
{ fprintf(stderr, "json_add_string called!\n"); abort(); }
|
|
/* AUTOGENERATED MOCKS END */
|
|
|
|
#define MAX_SATS ((u64)WALLY_SATOSHI_PER_BTC * WALLY_BTC_MAX)
|
|
|
|
struct test_case {
|
|
struct amount_sat their_funds;
|
|
struct amount_sat available_funds;
|
|
struct amount_sat *our_last_funds;
|
|
struct amount_sat max_channel_size;
|
|
struct amount_sat lease_request;
|
|
struct funder_policy policy;
|
|
};
|
|
|
|
static struct amount_sat fromwire_amount_sat_bounded(const u8 **cursor, size_t *max)
|
|
{
|
|
struct amount_sat amt = fromwire_amount_sat(cursor, max);
|
|
amt.satoshis %= (MAX_SATS + 1); /* Raw: fuzzing */
|
|
return amt;
|
|
}
|
|
|
|
static struct test_case *new_test_case(const tal_t *ctx, const u8 **cursor, size_t *max)
|
|
{
|
|
struct test_case *tcase = tal(ctx, struct test_case);
|
|
tcase->their_funds = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->available_funds = fromwire_amount_sat_bounded(cursor, max);
|
|
|
|
/* Read flag for our_last_funds */
|
|
u8 flag = fromwire_u8(cursor, max);
|
|
|
|
/* Handle our_last_funds conditionally */
|
|
struct amount_sat *our_last_funds_val = tal(ctx, struct amount_sat);
|
|
if (flag)
|
|
{
|
|
*our_last_funds_val = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->our_last_funds = our_last_funds_val;
|
|
}
|
|
else
|
|
tcase->our_last_funds = NULL;
|
|
|
|
tcase->max_channel_size = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->lease_request = fromwire_amount_sat_bounded(cursor, max);
|
|
|
|
tcase->policy.opt = (enum funder_opt)(fromwire_u8(cursor, max) % 3);
|
|
tcase->policy.mod = fromwire_u64(cursor, max);
|
|
switch (tcase->policy.opt)
|
|
{
|
|
case MATCH:
|
|
tcase->policy.mod %= 201;
|
|
break;
|
|
case AVAILABLE:
|
|
tcase->policy.mod %= 101;
|
|
break;
|
|
case FIXED:
|
|
tcase->policy.mod %= MAX_SATS + 1;
|
|
break;
|
|
default:
|
|
assert(false && "invalid policy");
|
|
}
|
|
tcase->policy.min_their_funding = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->policy.max_their_funding = fromwire_amount_sat_bounded(cursor, max);
|
|
|
|
if (amount_sat_greater(tcase->policy.min_their_funding, tcase->policy.max_their_funding)) {
|
|
struct amount_sat tmp = tcase->policy.min_their_funding;
|
|
tcase->policy.min_their_funding = tcase->policy.max_their_funding;
|
|
tcase->policy.max_their_funding = tmp;
|
|
}
|
|
|
|
tcase->policy.per_channel_max = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->policy.per_channel_min = fromwire_amount_sat_bounded(cursor, max);
|
|
|
|
if (amount_sat_greater(tcase->policy.per_channel_min, tcase->policy.per_channel_max)) {
|
|
struct amount_sat tmp = tcase->policy.per_channel_min;
|
|
tcase->policy.per_channel_min = tcase->policy.per_channel_max;
|
|
tcase->policy.per_channel_max = tmp;
|
|
}
|
|
|
|
tcase->policy.fuzz_factor = fromwire_u8(cursor, max) % 101;
|
|
tcase->policy.reserve_tank = fromwire_amount_sat_bounded(cursor, max);
|
|
tcase->policy.fund_probability = fromwire_u8(cursor, max) % 101;
|
|
tcase->policy.leases_only = fromwire_u8(cursor, max) & 1;
|
|
|
|
return tcase;
|
|
}
|
|
|
|
void init(int *argc, char ***argv)
|
|
{}
|
|
|
|
void run(const u8 *data, size_t size)
|
|
{
|
|
struct test_case *tcase = new_test_case(tmpctx, &data, &size);
|
|
|
|
struct node_id id;
|
|
memset(&id, 1, sizeof(id));
|
|
const char *err;
|
|
struct amount_sat our_funds;
|
|
|
|
/* Call the function under test */
|
|
err = calculate_our_funding(&tcase->policy, id,
|
|
tcase->their_funds,
|
|
tcase->our_last_funds,
|
|
tcase->available_funds,
|
|
tcase->max_channel_size,
|
|
tcase->lease_request,
|
|
&our_funds);
|
|
|
|
/* Validate invariants */
|
|
if (!err)
|
|
{
|
|
/* Check total doesn't exceed max_channel_size */
|
|
struct amount_sat total;
|
|
if (!amount_sat_add(&total, tcase->their_funds, our_funds)) {
|
|
fprintf(stderr, "Overflow in total channel capacity\n");
|
|
abort();
|
|
}
|
|
if (amount_sat_greater(total, tcase->max_channel_size)) {
|
|
fprintf(stderr, "Total channel capacity %"PRIu64" exceeds size %"PRIu64"\n",
|
|
total.satoshis, tcase->max_channel_size.satoshis); /* Raw: fuzzing */
|
|
abort();
|
|
}
|
|
|
|
/* Check our_funds is within per-channel limits */
|
|
if (amount_sat_less(our_funds, tcase->policy.per_channel_min) &&
|
|
!amount_sat_is_zero(our_funds)) {
|
|
fprintf(stderr, "our_funds %"PRIu64" < per_channel_min %"PRIu64"\n",
|
|
our_funds.satoshis, tcase->policy.per_channel_min.satoshis); /* Raw: fuzzing */
|
|
abort();
|
|
}
|
|
if (amount_sat_greater(our_funds, tcase->policy.per_channel_max)) {
|
|
fprintf(stderr, "our_funds %"PRIu64" > per_max_channel_size %"PRIu64"\n",
|
|
our_funds.satoshis, tcase->policy.per_channel_max.satoshis); /* Raw: fuzzing */
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/* Check available funds constraint */
|
|
struct amount_sat available_minus_reserve;
|
|
if (amount_sat_sub(&available_minus_reserve, tcase->available_funds, tcase->policy.reserve_tank)) {
|
|
if (amount_sat_greater(our_funds, available_minus_reserve)) {
|
|
fprintf(stderr, "our_funds %"PRIu64" > available %"PRIu64" - reserve %"PRIu64"\n",
|
|
our_funds.satoshis, tcase->available_funds.satoshis, /* Raw: fuzzing */
|
|
tcase->policy.reserve_tank.satoshis); /* Raw: fuzzing */
|
|
abort();
|
|
}
|
|
} else if (!amount_sat_eq(our_funds, AMOUNT_SAT(0))) {
|
|
fprintf(stderr, "Reserve %"PRIu64" >= available %"PRIu64" but our_funds %"PRIu64" != 0\n",
|
|
tcase->policy.reserve_tank.satoshis, tcase->available_funds.satoshis, /* Raw: fuzzing */
|
|
our_funds.satoshis); /* Raw: fuzzing */
|
|
abort();
|
|
}
|
|
|
|
clean_tmpctx();
|
|
}
|