Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions bitcoin/short_channel_id.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <bitcoin/short_channel_id.h>
#include <ccan/tal/str/str.h>
#include <common/randbytes.h>
#include <common/utils.h>
#include <stdio.h>
#include <wire/wire.h>

Expand Down Expand Up @@ -40,17 +41,27 @@ bool mk_short_channel_id(struct short_channel_id *scid,
bool short_channel_id_from_str(const char *str, size_t strlen,
struct short_channel_id *dst)
{
u32 blocknum, txnum;
u16 outnum;
int matches;
const char *x1, *x2;
u64 blocknum, txnum, outnum;

char buf[strlen + 1];
memcpy(buf, str, strlen);
buf[strlen] = 0;
x1 = memchr(str, 'x', strlen);
if (!x1)
return false;

x2 = memchr(x1 + 1, 'x', strlen - (x1 + 1 - str));
if (!x2)
return false;

if (!str_to_u64(str, x1 - str, &blocknum))
return false;

if (!str_to_u64(x1 + 1, x2 - (x1 + 1), &txnum))
return false;

if (!str_to_u64(x2 + 1, (str + strlen) - (x2 + 1), &outnum))
return false;

matches = sscanf(buf, "%ux%ux%hu", &blocknum, &txnum, &outnum);
return matches == 3
&& mk_short_channel_id(dst, blocknum, txnum, outnum);
return mk_short_channel_id(dst, blocknum, txnum, outnum);
}

char *fmt_short_channel_id(const tal_t *ctx, struct short_channel_id scid)
Expand Down
109 changes: 109 additions & 0 deletions bitcoin/test/run-short_channel_id.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "config.h"
#include "../short_channel_id.c"
#include <assert.h>
#include <common/setup.h>
#include <stdio.h>

/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for randbytes_ */
void randbytes_(void *bytes UNNEEDED, size_t num_bytes UNNEEDED, u64 *offset UNNEEDED)
{ fprintf(stderr, "randbytes_ called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

int main(int argc, char *argv[])
{
struct short_channel_id scid, exp;
struct short_channel_id_dir scidd;

common_setup(argv[0]);

/* Valid canonical short_channel_id strings */
assert(short_channel_id_from_str("539268x845x1", strlen("539268x845x1"), &scid));
assert(mk_short_channel_id(&exp, 539268, 845, 1));
assert(scid.u64 == exp.u64);
assert(short_channel_id_blocknum(scid) == 539268);
assert(short_channel_id_txnum(scid) == 845);
assert(short_channel_id_outnum(scid) == 1);

/* Boundary valid values */
assert(short_channel_id_from_str("0x0x0", strlen("0x0x0"), &scid));
assert(mk_short_channel_id(&exp, 0, 0, 0));
assert(scid.u64 == exp.u64);

assert(short_channel_id_from_str("16777215x16777215x65535",
strlen("16777215x16777215x65535"), &scid));
assert(mk_short_channel_id(&exp, 16777215, 16777215, 65535));
assert(scid.u64 == exp.u64);

/* Formatting */
char *str = fmt_short_channel_id(tmpctx, scid);
assert(streq(str, "16777215x16777215x65535"));

/* Valid short_channel_id_dir strings */
assert(mk_short_channel_id(&exp, 539268, 845, 1));
assert(short_channel_id_dir_from_str("539268x845x1/0", strlen("539268x845x1/0"), &scidd));
assert(scidd.scid.u64 == exp.u64);
assert(scidd.dir == 0);

assert(short_channel_id_dir_from_str("539268x845x1/1", strlen("539268x845x1/1"), &scidd));
assert(scidd.dir == 1);

/* Invalid trailing garbage */
assert(!short_channel_id_from_str("1x2x3garbage", strlen("1x2x3garbage"), &scid));
assert(!short_channel_id_from_str("1x2x3/0", strlen("1x2x3/0"), &scid));
assert(!short_channel_id_from_str("1x2x3x4", strlen("1x2x3x4"), &scid));
assert(!short_channel_id_from_str("1x2x3 4", strlen("1x2x3 4"), &scid));

/* Invalid signs and negative components */
assert(!short_channel_id_from_str("1x2x-1", strlen("1x2x-1"), &scid));
assert(!short_channel_id_from_str("-1x2x3", strlen("-1x2x3"), &scid));
assert(!short_channel_id_from_str("1x-2x3", strlen("1x-2x3"), &scid));
assert(!short_channel_id_from_str("+1x2x3", strlen("+1x2x3"), &scid));
assert(!short_channel_id_from_str("1x+2x3", strlen("1x+2x3"), &scid));
assert(!short_channel_id_from_str("1x2x+3", strlen("1x2x+3"), &scid));

/* Invalid whitespace */
assert(!short_channel_id_from_str(" 1x2x3", strlen(" 1x2x3"), &scid));
assert(!short_channel_id_from_str("1x2x3 ", strlen("1x2x3 "), &scid));
assert(!short_channel_id_from_str("1x 2x3", strlen("1x 2x3"), &scid));
assert(!short_channel_id_from_str("1x2x 3", strlen("1x2x 3"), &scid));

/* Incomplete or empty */
assert(!short_channel_id_from_str("", 0, &scid));
assert(!short_channel_id_from_str("1", 1, &scid));
assert(!short_channel_id_from_str("1x", 2, &scid));
assert(!short_channel_id_from_str("1x2", 3, &scid));
assert(!short_channel_id_from_str("1x2x", 4, &scid));
assert(!short_channel_id_from_str("x2x3", 4, &scid));
assert(!short_channel_id_from_str("1xx3", 4, &scid));

/* Out of range components (including > 2^16, > 2^32, > 2^64) */
assert(!short_channel_id_from_str("16777216x1x1", strlen("16777216x1x1"), &scid));
assert(!short_channel_id_from_str("1x16777216x1", strlen("1x16777216x1"), &scid));
assert(!short_channel_id_from_str("1x1x65536", strlen("1x1x65536"), &scid));
assert(!short_channel_id_from_str("1x1x65537", strlen("1x1x65537"), &scid));
assert(!short_channel_id_from_str("4294967296x1x1", strlen("4294967296x1x1"), &scid));
assert(!short_channel_id_from_str("4294967297x1x1", strlen("4294967297x1x1"), &scid));
assert(!short_channel_id_from_str("1x4294967296x1", strlen("1x4294967296x1"), &scid));
assert(!short_channel_id_from_str("1x4294967297x1", strlen("1x4294967297x1"), &scid));
assert(!short_channel_id_from_str("1x1x4294967296", strlen("1x1x4294967296"), &scid));
assert(!short_channel_id_from_str("18446744073709551616x1x1", strlen("18446744073709551616x1x1"), &scid));
assert(!short_channel_id_from_str("1x18446744073709551616x1", strlen("1x18446744073709551616x1"), &scid));
assert(!short_channel_id_from_str("1x1x18446744073709551616", strlen("1x1x18446744073709551616"), &scid));
assert(!short_channel_id_from_str("99999999999999999999x1x1", strlen("99999999999999999999x1x1"), &scid));

/* Invalid short_channel_id_dir */
assert(!short_channel_id_dir_from_str("1x2x3garbage/0", strlen("1x2x3garbage/0"), &scidd));
assert(!short_channel_id_dir_from_str("1x2x3/2", strlen("1x2x3/2"), &scidd));
assert(!short_channel_id_dir_from_str("1x2x3/", strlen("1x2x3/"), &scidd));
assert(!short_channel_id_dir_from_str("1x2x3/00", strlen("1x2x3/00"), &scidd));

common_shutdown();
return 0;
}
Loading