/* Creates and adds an example file. */ static char *add_example(struct manifest *m, struct ccan_file *source, struct doc_section *example) { char *name, *linemarker; unsigned int i; int fd; struct ccan_file *f; name = tal_fmt(m, "example-%s-%s", source->name, example->function); /* example->function == 'struct foo' */ while (strchr(name, ' ')) *strchr(name, ' ') = '_'; name = temp_file(m, ".c", take(name)); f = new_ccan_file(m, take(path_dirname(m, name)), take(path_basename(m, name))); tal_steal(f, name); list_add_tail(&m->examples, &f->list); fd = open(f->fullname, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) return tal_fmt(m, "Creating temporary file %s: %s", f->fullname, strerror(errno)); /* Add #line to demark where we are from, so errors are correct! */ linemarker = tal_fmt(f, "#line %i \"%s\"\n", example->srcline+2, source->fullname); if (write(fd, linemarker, strlen(linemarker)) != (int)strlen(linemarker)) { close(fd); return cast_const(char *, "Failure writing to temporary file"); }
/* See "https://en.bitcoin.it/wiki/Proper_Money_Handling_(JSON-RPC)" */ static bool pettycoin_tx(const tal_t *ctx, const char *privkey, const char *destaddr, const char *amount, size_t amount_len) { char *out, *end, *amountstr, *pettyaddr; u64 amt; /* We expect <number>.<number>. */ amt = strtoul(amount, &end, 10) * (u64)100000000; if (end >= amount + amount_len || *end != '.') errx(1, "Bad amount '%.*s'", (int)amount_len, amount); amt += strtoul(end + 1, &end, 10); if (end != amount + amount_len) errx(1, "Bad amount '%.*s'", (int)amount_len, amount); amountstr = tal_fmt(ctx, "%llu", (unsigned long long)amt); pettyaddr = tal_fmt(ctx, "P-%s", destaddr); out = ask_process(ctx, "pettycoin-tx", "--no-fee", "from-gateway", privkey, pettyaddr, amountstr); if (!out) return false; out = ask_process(ctx, "pettycoin-query", "sendrawtransaction", out, NULL, NULL, NULL); if (!out) return false; printf("Injected gateway tx %s\n", out); return true; }
/* FIXME: only print full analysis if verbose >= 2. */ static char *get_trailing_whitespace(const tal_t *ctx, const char *line) { const char *e = strchr(line, 0); while (e>line && (e[-1]==' ' || e[-1]=='\t')) e--; if (*e == 0) return NULL; //there were no trailing spaces if (e == line) return NULL; //the line only consists of spaces if (strlen(line) > 20) return tal_fmt(ctx, "...'%s'", line + strlen(line) - 20); return tal_fmt(ctx, "'%s'", line); }
/* Be careful about trying to compile over running programs (parallel make). * temp_file helps here. */ char *compile_info(const void *ctx, const char *dir) { char *info_c_file, *info, *compiled, *output; int fd; /* Copy it to a file with proper .c suffix. */ info = grab_file(ctx, tal_fmt(ctx, "%s/_info", dir)); if (!info) return NULL; info_c_file = temp_file(ctx, ".c", "_info"); fd = open(info_c_file, O_WRONLY|O_CREAT|O_EXCL, 0600); if (fd < 0) return NULL; if (!write_all(fd, info, tal_count(info)-1)) return NULL; if (close(fd) != 0) return NULL; compiled = temp_file(ctx, "", "info"); if (compile_and_link(ctx, info_c_file, find_ccan_dir(dir), "", compiler, cflags, "", compiled, &output)) return compiled; return NULL; }
static char *get_leaks(char *lines[], char **errs) { char *leaks = tal_strdup(lines, ""); unsigned int i; for (i = 0; i < tal_count(lines) - 1; i++) { if (strstr(lines[i], " lost ")) { /* A leak... */ if (strstr(lines[i], " definitely lost ")) { /* Definite leak, report. */ while (lines[i] && !blank_line(lines[i])) { tal_append_fmt(&leaks, "%s\n", lines[i]); i++; } } else /* Not definite, ignore. */ while (lines[i] && !blank_line(lines[i])) i++; } else { /* A real error. */ while (lines[i] && !blank_line(lines[i])) { if (!*errs) *errs = tal_fmt(NULL, "%s\n", lines[i]); else tal_append_fmt(errs, "%s\n", lines[i]); i++; } } } return leaks; }
static void add_dep(struct manifest ***deps, const char *modname) { unsigned int i; struct manifest *m; char *errstr; if (have_mod(*deps, modname)) return; m = get_manifest(*deps, tal_fmt(*deps, "%s/ccan/%s", ccan_dir, modname)); errstr = build_submodule(m, cflags, COMPILE_NORMAL); if (errstr) errx(1, "%s", errstr); add_mod(deps, m); /* Get that modules depends as well... */ assert(!safe_mode); if (m->info_file) { char **infodeps; infodeps = get_deps(m, m->dir, "depends", false, get_or_compile_info); for (i = 0; infodeps[i]; i++) { if (strstarts(infodeps[i], "ccan/")) add_dep(deps, infodeps[i] + strlen("ccan/")); } } }
void command_fail(struct command *cmd, const char *fmt, ...) { char *quote, *error; struct json_connection *jcon = cmd->jcon; va_list ap; if (!jcon) { log_unusual(cmd->dstate->base_log, "Command failed after jcon close"); tal_free(cmd); return; } va_start(ap, fmt); error = tal_vfmt(cmd, fmt, ap); va_end(ap); log_debug(jcon->log, "Failing: %s", error); /* Remove " */ while ((quote = strchr(error, '"')) != NULL) *quote = '\''; /* Now surround in quotes. */ quote = tal_fmt(cmd, "\"%s\"", error); assert(jcon->current == cmd); json_result(jcon, cmd->id, "null", quote); jcon->current = tal_free(cmd); }
char *short_channel_id_to_str(const tal_t *ctx, const struct short_channel_id *scid) { return tal_fmt(ctx, "%dx%dx%d", short_channel_id_blocknum(scid), short_channel_id_txnum(scid), short_channel_id_outnum(scid)); }
char *short_channel_id_dir_to_str(const tal_t *ctx, const struct short_channel_id_dir *scidd) { char *str, *scidstr = short_channel_id_to_str(NULL, &scidd->scid); str = tal_fmt(ctx, "%s/%u", scidstr, scidd->dir); tal_free(scidstr); return str; }
static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) { return tal_fmt(ctx, "{ feerate_per_kw=%"PRIu32"," " owed_local=%"PRIu64"," " owed_remote=%"PRIu64" }", view->feerate_per_kw, view->owed_msat[LOCAL], view->owed_msat[REMOTE]); }
/* FIXME: This should reference HTLCs somehow. */ static char *fmt_channel(const tal_t *ctx, const struct channel *channel) { return tal_fmt(ctx, "{ funding_msat=%"PRIu64"," " funder=%s," " local=%s," " remote=%s }", channel->funding_msat, side_to_str(channel->funder), fmt_channel_view(ctx, &channel->view[LOCAL]), fmt_channel_view(ctx, &channel->view[REMOTE])); }
static struct command_result *waitsendpay_error(struct command *cmd, const char *buf, const jsmntok_t *error, struct pay_command *pc) { const jsmntok_t *codetok, *scidtok, *dirtok; int code; attempt_failed_tok(pc, "waitsendpay", buf, error); codetok = json_get_member(buf, error, "code"); if (!json_to_int(buf, codetok, &code)) plugin_err("waitsendpay error gave no 'code'? '%.*s'", error->end - error->start, buf + error->start); /* FIXME: Handle PAY_UNPARSEABLE_ONION! */ /* Many error codes are final. */ if (code != PAY_TRY_OTHER_ROUTE) { return forward_error(cmd, buf, error, pc); } scidtok = json_delve(buf, error, ".data.erring_channel"); if (!scidtok) plugin_err("waitsendpay error no erring_channel '%.*s'", error->end - error->start, buf + error->start); dirtok = json_delve(buf, error, ".data.erring_direction"); if (!dirtok) plugin_err("waitsendpay error no erring_direction '%.*s'", error->end - error->start, buf + error->start); if (time_after(time_now(), pc->stoptime)) { return waitsendpay_expired(cmd, pc); } /* If failure is in routehint part, try next one */ if (channel_in_routehint(pc->current_routehint, buf, scidtok)) return next_routehint(cmd, pc); /* Otherwise, add erring channel to exclusion list. */ tal_arr_expand(&pc->excludes, tal_fmt(pc->excludes, "%.*s/%c", scidtok->end - scidtok->start, buf + scidtok->start, buf[dirtok->start])); /* Try again. */ return start_pay_attempt(cmd, pc, "Excluded channel %s", pc->excludes[tal_count(pc->excludes)-1]); }
static void json_result(struct json_connection *jcon, const char *id, const char *res, const char *err) { struct json_output *out = tal(jcon, struct json_output); out->json = tal_fmt(out, "{ \"result\" : %s," " \"error\" : %s," " \"id\" : %s }\n", res, err, id); /* Queue for writing, and wake writer (and maybe reader). */ list_add_tail(&jcon->output, &out->list); io_wake(jcon); }
char *netaddr_name(const tal_t *ctx, const struct netaddr *a) { char name[INET6_ADDRSTRLEN]; const void *sockaddr; uint16_t port; switch (a->saddr.s.sa_family) { case AF_INET: sockaddr = &a->saddr.ipv4.sin_addr; port = ntohs(a->saddr.ipv4.sin_port); break; case AF_INET6: sockaddr = &a->saddr.ipv6.sin6_addr; port = ntohs(a->saddr.ipv6.sin6_port); break; default: return tal_fmt(ctx, "Unknown protocol %u", a->saddr.s.sa_family); } if (!inet_ntop(a->saddr.s.sa_family, sockaddr, name, sizeof(name))) sprintf(name, "Unprintable-%u-address", a->saddr.s.sa_family); return tal_fmt(ctx, "%s:%u", name, port); }
static void dump_htlc(const struct htlc *htlc, const char *prefix) { enum htlc_state remote_state; if (htlc->state <= RCVD_REMOVE_ACK_REVOCATION) remote_state = htlc->state + 10; else remote_state = htlc->state - 10; status_trace("%s: HTLC %s %"PRIu64" = %s/%s %s", prefix, htlc_owner(htlc) == LOCAL ? "LOCAL" : "REMOTE", htlc->id, htlc_state_name(htlc->state), htlc_state_name(remote_state), htlc->r ? "FULFILLED" : htlc->fail ? "FAILED" : htlc->failcode ? tal_fmt(tmpctx, "FAILCODE:%u", htlc->failcode) : ""); }
static void handle_license_link(struct manifest *m, struct score *score) { struct doc_section *d = find_license_tag(m); const char *prefix = link_prefix(m); const char *link = path_join(m, m->dir, "LICENSE"); const char *ldest = expected_link(score, prefix, m->license); char *q; printf( "Most modules want a copy of their license, so usually we create a\n" "LICENSE symlink into %s to avoid too many copies.\n", prefix); /* FIXME: make ask printf-like */ q = tal_fmt(m, "Set up link to %s (license is %s)?", ldest, d->lines[0]); if (ask(q)) { if (symlink(ldest, link) != 0) err(1, "Creating symlink %s -> %s", link, ldest); } }
static struct command_result *waitsendpay_expired(struct command *cmd, struct pay_command *pc) { char *errmsg, *data; errmsg = tal_fmt(pc, "Gave up after %zu attempts", tal_count(pc->ps->attempts)); data = tal_strdup(pc, "'attempts': [ "); for (size_t i = 0; i < tal_count(pc->ps->attempts); i++) { if (pc->ps->attempts[i].route) tal_append_fmt(&data, "%s { 'route': %s,\n 'failure': %s\n }", i == 0 ? "" : ",", pc->ps->attempts[i].route, pc->ps->attempts[i].failure); else tal_append_fmt(&data, "%s { 'failure': %s\n }", i == 0 ? "" : ",", pc->ps->attempts[i].failure); } tal_append_fmt(&data, "]"); return command_done_err(cmd, PAY_STOPPED_RETRYING, errmsg, data); }
/* We only handle simple function definitions here. */ static char *add_func(const tal_t *ctx, char *others, const char *line) { const char *p, *end = strchr(line, '(') - 1; char *use; while (cisspace(*end)) { end--; if (end == line) return others; } for (p = end; cisalnum(*p) || *p == '_'; p--) { if (p == line) return others; } use = tal_fmt(ctx, "printf(\"%%p\", %.*s);\n", (unsigned)(end - p), p+1); if (others) use = tal_strcat(ctx, take(others), take(use)); return use; }
int main(int argc, char *argv[]) { size_t i, j, num; struct timeabs start, stop; char **w; ENTRY *words, *misswords; w = tal_strsplit(NULL, grab_file(NULL, argv[1] ? argv[1] : "/usr/share/dict/words"), "\n", STR_NO_EMPTY); num = tal_count(w) - 1; printf("%zu words\n", num); hcreate(num+num/3); words = tal_arr(w, ENTRY, num); for (i = 0; i < num; i++) { words[i].key = w[i]; words[i].data = words[i].key; } /* Append and prepend last char for miss testing. */ misswords = tal_arr(w, ENTRY, num); for (i = 0; i < num; i++) { char lastc; if (strlen(w[i])) lastc = w[i][strlen(w[i])-1]; else lastc = 'z'; misswords[i].key = tal_fmt(misswords, "%c%s%c%c", lastc, w[i], lastc, lastc); } printf("#01: Initial insert: "); fflush(stdout); start = time_now(); for (i = 0; i < num; i++) hsearch(words[i], ENTER); stop = time_now(); printf(" %zu ns\n", normalize(&start, &stop, num)); printf("#02: Initial lookup (match): "); fflush(stdout); start = time_now(); for (i = 0; i < num; i++) if (hsearch(words[i], FIND)->data != words[i].data) abort(); stop = time_now(); printf(" %zu ns\n", normalize(&start, &stop, num)); printf("#03: Initial lookup (miss): "); fflush(stdout); start = time_now(); for (i = 0; i < num; i++) { if (hsearch(misswords[i], FIND)) abort(); } stop = time_now(); printf(" %zu ns\n", normalize(&start, &stop, num)); /* Lookups in order are very cache-friendly for judy; try random */ printf("#04: Initial lookup (random): "); fflush(stdout); start = time_now(); for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num) if (hsearch(words[i], FIND)->data != words[i].data) abort(); stop = time_now(); printf(" %zu ns\n", normalize(&start, &stop, num)); return 0; }
static char *ask_process(const tal_t *ctx, const char *name, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *arg5) { struct json_result *response = new_json_result(ctx); if (streq(name, "bitcoind")) { assert(streq(arg1, "-testnet")); if (streq(arg2, "listtransactions")) { unsigned int i, num, skip; assert(streq(arg3, "gateway")); num = atoi(arg4 ? arg4 : "10"); assert(num); skip = atoi(arg5 ? arg5 : "0"); json_array_start(response, NULL); /* Like bitcoind, list oldest first. */ for (i = skip; i < skip+num; i++) { unsigned int confs; if (i >= ARRAY_SIZE(listtxs_response)) break; /* We only show one the first time. */ if (i > sleeps) break; /* First one is 16 confs, then 4, 1, then 0, * plus one each time you ask. */ confs = (1 << ((ARRAY_SIZE(listtxs_response) - i) * 2)) + sleeps; result_append_fmt(response, listtxs_response[i], confs); } json_array_end(response); assert(!response->indent); return response->s; } else if (streq(arg2, "getrawtransaction")) { unsigned int i; /* We only do verbose mode */ assert(streq(arg4, "1")); assert(arg5 == NULL); /* Search through responses for this txid */ for (i = 0; i < ARRAY_SIZE(getrawtxs_response); i++) { const char *p; p = strstr(getrawtxs_response[i], " \"txid\" : \""); if (strstarts(p + strlen(" \"txid\" : \""), arg3)) return tal_strdup(ctx, getrawtxs_response[i]); } } else if (streq(arg2, "getinfo")) { return tal_strdup(ctx, getinfo_response); } else if (streq(arg2, "sendtoaddress")) { if (mark_off_payment(arg3, amount_in_satoshis(arg4, strlen(arg4)))) return tal_strdup(ctx, "some-new-bitcoin-txid"); } } else if (streq(name, "pettycoin-tx")) { assert(streq(arg1, "--no-fee")); assert(streq(arg2, "from-gateway")); assert(streq(arg3, "FAKE-gateway-privkey")); if (mark_off_payment(arg4, atol(arg5))) return tal_fmt(ctx, "raw-transaction-%s", arg4); } else if (streq(name, "pettycoin-query")) { assert(streq(arg1, "sendrawtransaction")); assert(strstarts(arg2, "raw-transaction-")); assert(arg3 == NULL); assert(arg4 == NULL); assert(arg5 == NULL); return tal_fmt(ctx, "txid for %s", arg2); } printf("ask_process: name=%s arg1=%s arg2=%s arg3=%s arg4=%s arg5=%s", name, arg1, arg2, arg3, arg4, arg5); return NULL; }
int main(void) { char *parent, *c; plan_tests(43); parent = tal(NULL, char); ok1(parent); c = tal_strdup(parent, "hello"); ok1(strcmp(c, "hello") == 0); ok1(tal_parent(c) == parent); ok1(tal_count(c) == strlen(c) + 1); tal_free(c); c = tal_strndup(parent, "hello", 3); ok1(strcmp(c, "hel") == 0); ok1(tal_parent(c) == parent); ok1(tal_count(c) == strlen(c) + 1); tal_free(c); #ifdef TAL_USE_TALLOC c = tal_talloc_typechk_(parent, char *); #else c = tal_typechk_(parent, char *); #endif c = tal_dup_arr(parent, char, "hello", 6, 0); ok1(strcmp(c, "hello") == 0); ok1(strcmp(tal_name(c), "char[]") == 0); ok1(tal_count(c) == 6); ok1(tal_parent(c) == parent); tal_free(c); /* Now with an extra byte. */ c = tal_dup_arr(parent, char, "hello", 6, 1); ok1(strcmp(c, "hello") == 0); ok1(strcmp(tal_name(c), "char[]") == 0); ok1(tal_count(c) == 7); ok1(tal_parent(c) == parent); strcat(c, "x"); tal_free(c); c = tal_fmt(parent, "hello %s", "there"); ok1(strcmp(c, "hello there") == 0); ok1(tal_count(c) == strlen(c) + 1); ok1(tal_parent(c) == parent); tal_free(c); c = tal_strcat(parent, "hello ", "there"); ok1(strcmp(c, "hello there") == 0); ok1(tal_count(c) == strlen(c) + 1); ok1(tal_parent(c) == parent); /* Make sure take works correctly. */ c = tal_strcat(parent, take(c), " again"); ok1(strcmp(c, "hello there again") == 0); ok1(tal_count(c) == strlen(c) + 1); ok1(tal_parent(c) == parent); ok1(single_child(parent, c)); c = tal_strcat(parent, "And ", take(c)); ok1(tal_count(c) == strlen(c) + 1); ok1(strcmp(c, "And hello there again") == 0); ok1(tal_parent(c) == parent); ok1(single_child(parent, c)); /* NULL pass through works... */ c = tal_strcat(parent, take(NULL), take(c)); ok1(!c); ok1(no_children(parent)); c = tal_strcat(parent, take(tal_strdup(parent, "hi")), take(NULL)); ok1(!c); ok1(no_children(parent)); c = tal_strcat(parent, take(NULL), take(NULL)); ok1(!c); ok1(no_children(parent)); /* Appending formatted strings. */ c = tal_strdup(parent, "hi"); ok1(tal_count(c) == strlen(c) + 1); ok1(tal_append_fmt(&c, "%s %s", "there", "world")); ok1(strcmp(c, "hithere world") == 0); ok1(tal_count(c) == strlen(c) + 1); ok1(tal_parent(c) == parent); ok1(!tal_append_fmt(&c, take(NULL), "there", "world")); ok1(strcmp(c, "hithere world") == 0); ok1(tal_count(c) == strlen(c) + 1); tal_free(parent); return exit_status(); }
int main(void) { struct amount_msat msat; struct amount_sat sat; setup_locale(); setup_tmpctx(); /* Grossly malformed */ FAIL_MSAT(&msat, "x"); FAIL_MSAT(&msat, "x100"); PASS_MSAT(&msat, "0", 0); PASS_MSAT(&msat, "1", 1); PASS_MSAT(&msat, "2100000000000000000", 2100000000000000000ULL); FAIL_MSAT(&msat, "0.0"); FAIL_MSAT(&msat, "0.00000000"); FAIL_MSAT(&msat, "0.00000000000"); FAIL_MSAT(&msat, "0.00000000msat"); FAIL_MSAT(&msat, "-1"); PASS_MSAT(&msat, "0msat", 0); PASS_MSAT(&msat, "1msat", 1); PASS_MSAT(&msat, "2100000000000000000msat", 2100000000000000000ULL); FAIL_MSAT(&msat, "-1msat"); PASS_MSAT(&msat, "0sat", 0); PASS_MSAT(&msat, "1sat", 1000); PASS_MSAT(&msat, "2100000000000000sat", 2100000000000000000ULL); FAIL_MSAT(&msat, "-1sat"); PASS_MSAT(&msat, "0.00000000btc", 0); PASS_MSAT(&msat, "0.00000000000btc", 0); PASS_MSAT(&msat, "0.00000001btc", 1000); PASS_MSAT(&msat, "0.00000000001btc", 1); PASS_MSAT(&msat, "1.2btc", 120000000000); PASS_MSAT(&msat, "1.23btc", 123000000000); PASS_MSAT(&msat, "1.234btc", 123400000000); PASS_MSAT(&msat, "1.2345btc", 123450000000); PASS_MSAT(&msat, "1.23456btc", 123456000000); PASS_MSAT(&msat, "1.234567btc", 123456700000); PASS_MSAT(&msat, "1.2345678btc", 123456780000); PASS_MSAT(&msat, "1.23456789btc", 123456789000); PASS_MSAT(&msat, "1.234567890btc", 123456789000); PASS_MSAT(&msat, "1.2345678901btc", 123456789010); PASS_MSAT(&msat, "1.23456789012btc", 123456789012); FAIL_MSAT(&msat, "1btc"); FAIL_MSAT(&msat, "1.000000000000btc"); FAIL_MSAT(&msat, "-1.23456789btc"); FAIL_MSAT(&msat, "-1.23456789012btc"); /* Overflowingly big. */ FAIL_MSAT(&msat, "21000000000000000000000000.00000000btc"); /* Grossly malformed */ FAIL_SAT(&sat, "x"); FAIL_SAT(&sat, "x100"); PASS_SAT(&sat, "0", 0); PASS_SAT(&sat, "1", 1); PASS_SAT(&sat, "2100000000000000", 2100000000000000ULL); FAIL_SAT(&sat, "0.0"); FAIL_SAT(&sat, "0.00000000"); FAIL_SAT(&sat, "0.00000000000"); FAIL_SAT(&sat, "0.00000000sat"); FAIL_SAT(&sat, "0.00000000000msat"); FAIL_SAT(&sat, "-1"); PASS_SAT(&sat, "0sat", 0); PASS_SAT(&sat, "1sat", 1); PASS_SAT(&sat, "2100000000000000sat", 2100000000000000ULL); FAIL_SAT(&sat, "-1sat"); PASS_SAT(&sat, "1000msat", 1); PASS_SAT(&sat, "1000000msat", 1000); PASS_SAT(&sat, "2100000000000000000msat", 2100000000000000ULL); FAIL_SAT(&sat, "0msat"); FAIL_SAT(&sat, "100msat"); FAIL_SAT(&sat, "2000000000000000999msat"); FAIL_SAT(&sat, "-1000msat"); PASS_SAT(&sat, "0.00000000btc", 0); FAIL_SAT(&sat, "0.00000000000btc"); PASS_SAT(&sat, "0.00000001btc", 1); FAIL_SAT(&sat, "0.00000000001btc"); PASS_SAT(&sat, "1.23456789btc", 123456789); PASS_SAT(&sat, "1.2btc", 120000000); PASS_SAT(&sat, "1.23btc", 123000000); PASS_SAT(&sat, "1.234btc", 123400000); PASS_SAT(&sat, "1.2345btc", 123450000); PASS_SAT(&sat, "1.23456btc", 123456000); PASS_SAT(&sat, "1.234567btc", 123456700); PASS_SAT(&sat, "1.2345678btc", 123456780); PASS_SAT(&sat, "1.23456789btc", 123456789); FAIL_SAT(&sat, "1.234567890btc"); FAIL_SAT(&sat, "1btc"); FAIL_SAT(&sat, "-1.23456789btc"); /* Overflowingly big. */ FAIL_SAT(&sat, "21000000000000000000000000.00000000btc"); /* Test fmt_amount_msat_btc, fmt_amount_msat */ for (u64 i = 0; i <= UINT64_MAX / 10; i = i ? i * 10 : 1) { const char *with, *without; msat.millisatoshis = i; with = fmt_amount_msat_btc(tmpctx, &msat, true); without = fmt_amount_msat_btc(tmpctx, &msat, false); assert(strends(with, "btc")); assert(strlen(with) == strlen(without) + 3); assert(strncmp(with, without, strlen(without)) == 0); /* Make sure it overwrites. */ msat.millisatoshis++; assert(parse_amount_msat(&msat, with, strlen(with))); assert(msat.millisatoshis == i); with = fmt_amount_msat(tmpctx, &msat); without = tal_fmt(tmpctx, "%"PRIu64, msat.millisatoshis); assert(strends(with, "msat")); assert(strlen(with) == strlen(without) + 4); assert(strncmp(with, without, strlen(without)) == 0); /* Make sure it overwrites. */ msat.millisatoshis++; assert(parse_amount_msat(&msat, with, strlen(with))); assert(msat.millisatoshis == i); } /* Test fmt_amount_sat_btc, fmt_amount_sat */ for (u64 i = 0; i <= UINT64_MAX / 10; i = i ? i * 10 : 1) { const char *with, *without; sat.satoshis = i; with = fmt_amount_sat_btc(tmpctx, &sat, true); without = fmt_amount_sat_btc(tmpctx, &sat, false); assert(strends(with, "btc")); assert(strlen(with) == strlen(without) + 3); assert(strncmp(with, without, strlen(without)) == 0); /* Make sure it overwrites. */ sat.satoshis++; assert(parse_amount_sat(&sat, with, strlen(with))); assert(sat.satoshis == i); with = fmt_amount_sat(tmpctx, &sat); without = tal_fmt(tmpctx, "%"PRIu64, sat.satoshis); assert(strends(with, "sat")); assert(strlen(with) == strlen(without) + 3); assert(strncmp(with, without, strlen(without)) == 0); /* Make sure it overwrites. */ sat.satoshis++; assert(parse_amount_sat(&sat, with, strlen(with))); assert(sat.satoshis == i); } tal_free(tmpctx); }
/* Note: we already test safe_mode in run_tests.c */ static const char *can_run_vg(struct manifest *m) { if (!do_valgrind) return tal_fmt(m, "No valgrind support"); return NULL; }
/* Simple test code to create a gateway transaction */ int main(int argc, char *argv[]) { int fd, i, off; const char *method; char *cmd, *resp, *idstr, *rpc_filename; char *result_end; struct sockaddr_un addr; jsmntok_t *toks; const jsmntok_t *result, *error, *id; char *pettycoin_dir; const tal_t *ctx = tal(NULL, char); size_t num_opens, num_closes; bool valid; err_set_progname(argv[0]); opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); pettycoin_dir_register_opts(ctx, &pettycoin_dir, &rpc_filename); opt_register_noarg("--help|-h", opt_usage_and_exit, "<command> [<params>...]", "Show this message"); opt_register_noarg("--version|-V", opt_version_and_exit, VERSION, "Display version and exit"); opt_early_parse(argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit); method = argv[1]; if (!method) errx(ERROR_USAGE, "Need at least one argument\n%s", opt_usage(argv[0], NULL)); if (chdir(pettycoin_dir) != 0) err(ERROR_TALKING_TO_PETTYCOIN, "Moving into '%s'", pettycoin_dir); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (strlen(rpc_filename) + 1 > sizeof(addr.sun_path)) errx(ERROR_USAGE, "rpc filename '%s' too long", rpc_filename); strcpy(addr.sun_path, rpc_filename); addr.sun_family = AF_UNIX; if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) err(ERROR_TALKING_TO_PETTYCOIN, "Connecting to '%s'", rpc_filename); idstr = tal_fmt(ctx, "pettycoin_query-%i", getpid()); cmd = tal_fmt(ctx, "{ \"method\" : \"%s\", \"id\" : \"%s\", \"params\" : [ ", method, idstr); for (i = 2; i < argc; i++) { /* Numbers are left unquoted, and quoted things left alone. */ if (strspn(argv[i], "0123456789") == strlen(argv[i]) || argv[i][0] == '"') tal_append_fmt(&cmd, "%s", argv[i]); else tal_append_fmt(&cmd, "\"%s\"", argv[i]); if (i != argc - 1) tal_append_fmt(&cmd, ", "); } tal_append_fmt(&cmd, "] }"); if (!write_all(fd, cmd, strlen(cmd))) err(ERROR_TALKING_TO_PETTYCOIN, "Writing command"); resp = tal_arr(cmd, char, 100); off = 0; num_opens = num_closes = 0; while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) { resp[off + i] = '\0'; num_opens += strcount(resp + off, "{"); num_closes += strcount(resp + off, "}"); off += i; if (off == tal_count(resp) - 1) tal_resize(&resp, tal_count(resp) * 2); /* parsing huge outputs is slow: do quick check first. */ if (num_opens == num_closes && strstr(resp, "\"result\"")) break; } if (i < 0) err(ERROR_TALKING_TO_PETTYCOIN, "reading response"); /* Parsing huge results is too slow, so hack fastpath common case */ result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n", idstr); if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) { /* Result is OK, so dump it */ resp += strlen("{ \"result\" : "); printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp); tal_free(ctx); return 0; } toks = json_parse_input(resp, off, &valid); if (!toks || !valid) errx(ERROR_TALKING_TO_PETTYCOIN, "Malformed response '%s'", resp); result = json_get_member(resp, toks, "result"); if (!result) errx(ERROR_TALKING_TO_PETTYCOIN, "Missing 'result' in response '%s'", resp); error = json_get_member(resp, toks, "error"); if (!error) errx(ERROR_TALKING_TO_PETTYCOIN, "Missing 'error' in response '%s'", resp); id = json_get_member(resp, toks, "id"); if (!id) errx(ERROR_TALKING_TO_PETTYCOIN, "Missing 'id' in response '%s'", resp); if (!json_tok_streq(resp, id, idstr)) errx(ERROR_TALKING_TO_PETTYCOIN, "Incorrect 'id' in response: %.*s", json_tok_len(id), json_tok_contents(resp, id)); if (json_tok_is_null(resp, error)) { printf("%.*s\n", json_tok_len(result), json_tok_contents(resp, result)); tal_free(ctx); return 0; } printf("%.*s\n", json_tok_len(error), json_tok_contents(resp, error)); tal_free(ctx); return 1; }
static void check_has_license(struct manifest *m, unsigned int *timeleft, struct score *score) { char buf[PATH_MAX]; ssize_t len; char *license = path_join(m, m->dir, "LICENSE"); const char *expected; struct doc_section *d; const char *prefix = link_prefix(m); d = find_license_tag(m); if (!d) { score->error = tal_strdup(score, "No License: tag in _info"); return; } m->license = which_license(d); if (m->license == LICENSE_UNKNOWN) { score_file_error(score, m->info_file, d->srcline, "WARNING: unknown License: in _info: %s", d->lines[0]); /* FIXME: For historical reasons, don't fail here. */ score->pass = true; return; } /* If they have a license tag at all, we pass. */ score->pass = true; expected = expected_link(m, prefix, m->license); len = readlink(license, buf, sizeof(buf)); if (len < 0) { /* Could be a real file... OK if not a standard license. */ if (errno == EINVAL) { if (!expected) { score->score = score->total; return; } score->error = tal_fmt(score, "License in _info is '%s'," " expect LICENSE symlink '%s'", d->lines[0], expected); return; } if (errno == ENOENT) { /* Public domain doesn't really need a file. */ if (m->license == LICENSE_PUBLIC_DOMAIN) { score->score = score->total; return; } score->error = tal_strdup(score, "LICENSE does not exist"); if (expected) license_exists.handle = handle_license_link; return; } err(1, "readlink on %s", license); } if (len >= sizeof(buf)) errx(1, "Reading symlink %s gave huge result", license); buf[len] = '\0'; if (!strstarts(buf, prefix)) { score->error = tal_fmt(score, "Expected symlink into %s not %s", prefix, buf); return; } if (!expected) { score->error = tal_fmt(score, "License in _info is unknown '%s'," " but LICENSE symlink is '%s'", d->lines[0], buf); return; } if (!streq(buf, expected)) { score->error = tal_fmt(score, "Expected symlink to %s not %s", expected, buf); return; } score->pass = true; score->score = score->total; }
static const char *get_first_input_addr(const tal_t *ctx, const char *buffer, const jsmntok_t *txid) { const jsmntok_t *toks, *intxid, *onum, *type, *address; unsigned int outnum; const char *delve, *txstr; /* eg: getrawtransaction e84b0c87934a146d211fcaa6f1ec187da33e205fb250400cf66620a82a9111a0 1 { "hex" : "010000000193721eadf1bb2a40498b41ca6be2adaddf4c1780884637fedf05cf37015ac508000000006b4830450221008ce700a0c872af67612e5d5226f1e8bdcb2329549883b8fa02df002409f54c43022029b10a885ca3c5103574f06ab90e6f5a7c9c2cafe6e583f17316c967d678bab4012103c511c82cf0aae4541c026eee5d9f738dc1cb4a2114e20b3f5710a22dc94825ceffffffff02d0f88774030000001976a9144e81b0986efad3643012783f016ec10a9c3d35cd88ac005a6202000000001976a91434f89b68a07bd841bbca98f9b7b1521ce1a3d17688ac00000000", "txid" : "e84b0c87934a146d211fcaa6f1ec187da33e205fb250400cf66620a82a9111a0", "version" : 1, "locktime" : 0, "vin" : [ { "txid" : "08c55a0137cf05dffe37468880174cdfadade26bca418b49402abbf1ad1e7293", "vout" : 0, "scriptSig" : { "asm" : "30450221008ce700a0c872af67612e5d5226f1e8bdcb2329549883b8fa02df002409f54c43022029b10a885ca3c5103574f06ab90e6f5a7c9c2cafe6e583f17316c967d678bab401 03c511c82cf0aae4541c026eee5d9f738dc1cb4a2114e20b3f5710a22dc94825ce", "hex" : "4830450221008ce700a0c872af67612e5d5226f1e8bdcb2329549883b8fa02df002409f54c43022029b10a885ca3c5103574f06ab90e6f5a7c9c2cafe6e583f17316c967d678bab4012103c511c82cf0aae4541c026eee5d9f738dc1cb4a2114e20b3f5710a22dc94825ce" }, "sequence" : 4294967295 } ], "vout" : [ { "value" : 148.39970000, "n" : 0, "scriptPubKey" : { "asm" : "OP_DUP OP_HASH160 4e81b0986efad3643012783f016ec10a9c3d35cd OP_EQUALVERIFY OP_CHECKSIG", "hex" : "76a9144e81b0986efad3643012783f016ec10a9c3d35cd88ac", "reqSigs" : 1, "type" : "pubkeyhash", "addresses" : [ "mng4N2LZqin7joL7GAjs4tp8WNNt8GjcYz" ] } }, { "value" : 0.40000000, "n" : 1, "scriptPubKey" : { "asm" : "OP_DUP OP_HASH160 34f89b68a07bd841bbca98f9b7b1521ce1a3d176 OP_EQUALVERIFY OP_CHECKSIG", "hex" : "76a91434f89b68a07bd841bbca98f9b7b1521ce1a3d17688ac", "reqSigs" : 1, "type" : "pubkeyhash", "addresses" : [ "mkM3FYuYoKFiXS3YL99JdJEdPM5HVGpZTj" ] } } ], "blockhash" : "0000000022a3a02881f56c24bbe7556eef98b1e29267b4015a4fbfc83bab5735", "confirmations" : 14, "time" : 1406252550, "blocktime" : 1406252550 } */ txstr = tal_fmt(ctx, "%.*s", (int)(txid->end - txid->start), buffer + txid->start); toks = json_bitcoind(ctx, &buffer, "getrawtransaction", txstr, "1", NULL); if (!toks) err(1, "getrawtransaction of tx %s", txstr); /* This can happen in if someone aims their block reward at the gateway. */ intxid = json_delve(buffer, toks, ".vin[0].txid"); onum = json_delve(buffer, toks, ".vin[0].vout"); if (!intxid || !onum) errx(1, "Missing txid/vout in '%s'", buffer); /* Get this before we replace buffer. */ outnum = num_of(buffer, onum); /* Get details of *that* tx. */ txstr = tal_fmt(ctx, "%.*s", (int)(intxid->end - intxid->start), buffer + intxid->start); toks = json_bitcoind(ctx, &buffer, "getrawtransaction", txstr, "1", NULL); if (!toks) err(1, "getrawtransaction of input tx %s", txstr); /* make sure it's a pubkeyhash */ delve = tal_fmt(ctx, ".vout[%u].scriptPubKey.type", outnum); type = json_delve(buffer, toks, delve); if (!type || !json_tok_streq(buffer, type, "pubkeyhash")) errx(1, "'%s' was not a pubkeyhash in '%s'", delve, buffer); delve = tal_fmt(ctx, ".vout[%u].scriptPubKey.addresses[0]", outnum); address = json_delve(buffer, toks, delve); if (!address) errx(1, "Can't find %s in '%s'", delve, buffer); return tal_strndup(ctx, buffer + address->start, address->end - address->start); }