mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-07 06:19:27 +01:00
7283efa5b5
Currently the only source for amount_asset is the value getter on a tx output, and we don't hand it too far around (mainly ignoring it if it isn't the chain's main currency). Eventually we could bubble them up to the wallet, use them to select outputs or actually support assets in the channels. Since we don't hand them around too widely I thought it was ok for them to be pass-by-value rather than having to allocate them and pass them around by reference. They're just 41 bytes currently so the overhead should be ok. Signed-off-by: Christian Decker <@cdecker>
294 lines
7.2 KiB
C
294 lines
7.2 KiB
C
#include <ccan/array_size/array_size.h>
|
|
#include <ccan/str/hex/hex.h>
|
|
#include <ccan/tal/grab_file/grab_file.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <common/json.c>
|
|
#include <common/utils.h>
|
|
#include <wire/wire.h>
|
|
|
|
static const char *reason;
|
|
#define SUPERVERBOSE(r) do { if (!reason) reason = (r); } while(0)
|
|
|
|
#include <common/bigsize.c>
|
|
|
|
/* AUTOGENERATED MOCKS START */
|
|
/* Generated stub for amount_asset_is_main */
|
|
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
|
|
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
|
|
/* Generated stub for amount_asset_to_sat */
|
|
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
|
|
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
|
|
/* Generated stub for amount_sat_add */
|
|
bool amount_sat_add(struct amount_sat *val UNNEEDED,
|
|
struct amount_sat a UNNEEDED,
|
|
struct amount_sat b UNNEEDED)
|
|
{ fprintf(stderr, "amount_sat_add called!\n"); abort(); }
|
|
/* Generated stub for amount_sat_eq */
|
|
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
|
|
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
|
|
/* Generated stub for amount_sat_sub */
|
|
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
|
|
struct amount_sat a UNNEEDED,
|
|
struct amount_sat b UNNEEDED)
|
|
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
|
|
/* Generated stub for fromwire_fail */
|
|
const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
|
|
/* AUTOGENERATED MOCKS END */
|
|
|
|
/* BOLT #1:
|
|
*
|
|
* A correct implementation should pass against these test vectors:
|
|
* ```json
|
|
* [
|
|
* {
|
|
* "name": "zero",
|
|
* "value": 0,
|
|
* "bytes": "00"
|
|
* },
|
|
* {
|
|
* "name": "one byte high",
|
|
* "value": 252,
|
|
* "bytes": "fc"
|
|
* },
|
|
* {
|
|
* "name": "two byte low",
|
|
* "value": 253,
|
|
* "bytes": "fd00fd"
|
|
* },
|
|
* {
|
|
* "name": "two byte high",
|
|
* "value": 65535,
|
|
* "bytes": "fdffff"
|
|
* },
|
|
* {
|
|
* "name": "four byte low",
|
|
* "value": 65536,
|
|
* "bytes": "fe00010000"
|
|
* },
|
|
* {
|
|
* "name": "four byte high",
|
|
* "value": 4294967295,
|
|
* "bytes": "feffffffff"
|
|
* },
|
|
* {
|
|
* "name": "eight byte low",
|
|
* "value": 4294967296,
|
|
* "bytes": "ff0000000100000000"
|
|
* },
|
|
* {
|
|
* "name": "eight byte high",
|
|
* "value": 18446744073709551615,
|
|
* "bytes": "ffffffffffffffffff"
|
|
* },
|
|
* {
|
|
* "name": "two byte not canonical",
|
|
* "value": 0,
|
|
* "bytes": "fd00fc",
|
|
* "exp_error": "decoded varint is not canonical"
|
|
* },
|
|
* {
|
|
* "name": "four byte not canonical",
|
|
* "value": 0,
|
|
* "bytes": "fe0000ffff",
|
|
* "exp_error": "decoded varint is not canonical"
|
|
* },
|
|
* {
|
|
* "name": "eight byte not canonical",
|
|
* "value": 0,
|
|
* "bytes": "ff00000000ffffffff",
|
|
* "exp_error": "decoded varint is not canonical"
|
|
* },
|
|
* {
|
|
* "name": "two byte short read",
|
|
* "value": 0,
|
|
* "bytes": "fd00",
|
|
* "exp_error": "unexpected EOF"
|
|
* },
|
|
* {
|
|
* "name": "four byte short read",
|
|
* "value": 0,
|
|
* "bytes": "feffff",
|
|
* "exp_error": "unexpected EOF"
|
|
* },
|
|
* {
|
|
* "name": "eight byte short read",
|
|
* "value": 0,
|
|
* "bytes": "ffffffffff",
|
|
* "exp_error": "unexpected EOF"
|
|
* },
|
|
* {
|
|
* "name": "one byte no read",
|
|
* "value": 0,
|
|
* "bytes": "",
|
|
* "exp_error": "EOF"
|
|
* },
|
|
* {
|
|
* "name": "two byte no read",
|
|
* "value": 0,
|
|
* "bytes": "fd",
|
|
* "exp_error": "unexpected EOF"
|
|
* },
|
|
* {
|
|
* "name": "four byte no read",
|
|
* "value": 0,
|
|
* "bytes": "fe",
|
|
* "exp_error": "unexpected EOF"
|
|
* },
|
|
* {
|
|
* "name": "eight byte no read",
|
|
* "value": 0,
|
|
* "bytes": "ff",
|
|
* "exp_error": "unexpected EOF"
|
|
* }
|
|
* ]
|
|
* ```
|
|
*/
|
|
static void test_decode(const char *json, const jsmntok_t toks[])
|
|
{
|
|
size_t i;
|
|
const jsmntok_t *t;
|
|
|
|
json_for_each_arr(i, t, toks) {
|
|
const jsmntok_t *err = json_get_member(json, t, "exp_error");
|
|
const jsmntok_t *bytes = json_get_member(json, t, "bytes");
|
|
u64 num, expect;
|
|
const u8 *b;
|
|
size_t len;
|
|
|
|
if (!json_to_u64(json, json_get_member(json, t, "value"),
|
|
&expect))
|
|
abort();
|
|
b = tal_hexdata(tmpctx, json + bytes->start,
|
|
bytes->end - bytes->start);
|
|
|
|
reason = NULL;
|
|
len = bigsize_get(b, tal_bytelen(b), &num);
|
|
if (err) {
|
|
assert(len == 0);
|
|
assert(json_tok_streq(json, err, reason));
|
|
} else {
|
|
assert(len == tal_bytelen(b));
|
|
assert(num == expect);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* BOLT #1:
|
|
*
|
|
* A correct implementation should pass against the following test vectors:
|
|
* ```json
|
|
* [
|
|
* {
|
|
* "name": "zero",
|
|
* "value": 0,
|
|
* "bytes": "00"
|
|
* },
|
|
* {
|
|
* "name": "one byte high",
|
|
* "value": 252,
|
|
* "bytes": "fc"
|
|
* },
|
|
* {
|
|
* "name": "two byte low",
|
|
* "value": 253,
|
|
* "bytes": "fd00fd"
|
|
* },
|
|
* {
|
|
* "name": "two byte high",
|
|
* "value": 65535,
|
|
* "bytes": "fdffff"
|
|
* },
|
|
* {
|
|
* "name": "four byte low",
|
|
* "value": 65536,
|
|
* "bytes": "fe00010000"
|
|
* },
|
|
* {
|
|
* "name": "four byte high",
|
|
* "value": 4294967295,
|
|
* "bytes": "feffffffff"
|
|
* },
|
|
* {
|
|
* "name": "eight byte low",
|
|
* "value": 4294967296,
|
|
* "bytes": "ff0000000100000000"
|
|
* },
|
|
* {
|
|
* "name": "eight byte high",
|
|
* "value": 18446744073709551615,
|
|
* "bytes": "ffffffffffffffffff"
|
|
* }
|
|
* ]
|
|
* ```
|
|
*/
|
|
static void test_encode(const char *json, const jsmntok_t toks[])
|
|
{
|
|
size_t i;
|
|
const jsmntok_t *t;
|
|
u8 buf[BIGSIZE_MAX_LEN];
|
|
|
|
json_for_each_arr(i, t, toks) {
|
|
const jsmntok_t *bytes = json_get_member(json, t, "bytes");
|
|
u64 num;
|
|
const u8 *expect;
|
|
size_t len;
|
|
|
|
if (!json_to_u64(json, json_get_member(json, t, "value"),
|
|
&num))
|
|
abort();
|
|
expect = tal_hexdata(tmpctx, json + bytes->start,
|
|
bytes->end - bytes->start);
|
|
|
|
len = bigsize_put(buf, num);
|
|
assert(memeq(buf, len, expect, tal_bytelen(expect)));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char **lines, *json = NULL;
|
|
int test_count = 0;
|
|
|
|
setup_locale();
|
|
setup_tmpctx();
|
|
|
|
lines = tal_strsplit(tmpctx, grab_file(tmpctx, tal_fmt(tmpctx, "%s.c",
|
|
argv[0])),
|
|
"\n", STR_NO_EMPTY);
|
|
|
|
for (size_t i = 0; lines[i]; i++) {
|
|
const char *l = lines[i];
|
|
if (!strstarts(l, " * "))
|
|
continue;
|
|
l += 3;
|
|
if (streq(l, "```json"))
|
|
json = tal_strdup(tmpctx, "");
|
|
else if (streq(l, "```")) {
|
|
jsmn_parser parser;
|
|
jsmntok_t toks[500];
|
|
|
|
jsmn_init(&parser);
|
|
if (jsmn_parse(&parser, json, strlen(json),
|
|
toks, ARRAY_SIZE(toks)) < 0)
|
|
abort();
|
|
|
|
switch (test_count) {
|
|
case 0:
|
|
test_decode(json, toks);
|
|
break;
|
|
case 1:
|
|
test_encode(json, toks);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
test_count++;
|
|
json = NULL;
|
|
} else if (json)
|
|
tal_append_fmt(&json, "%s", l);
|
|
}
|
|
assert(test_count == 2);
|
|
tal_free(tmpctx);
|
|
}
|