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]); }
int main(void) { jsmntok_t *toks_arr, *toks_obj, *arg1, *arg2, *arg3, *arg4, *arg5; const jsmntok_t *arr_params, *obj_params; void *ctx; bool valid; char *cmd_arr, *cmd_obj; struct protocol_double_sha sha; ctx = tal(NULL, char); cmd_arr = tal_strdup(ctx, "{ \"method\" : \"dev-echo\", " "\"params\" : [ null, [ 1, 2, 3 ], { \"one\" : 1 }, \"four\" ], " "\"id\" : \"1\" }"); cmd_obj = tal_strdup(ctx, "{ \"method\" : \"dev-echo\", " "\"params\" : { \"arg2\" : [ 1, 2, 3 ]," " \"arg3\" : { \"one\" : 1 }," " \"arg4\" : \"four\" }, " "\"id\" : \"1\" }"); /* Partial id we skip } */ toks_arr = json_parse_input(cmd_arr, strlen(cmd_arr) - 1, &valid); assert(!toks_arr); assert(valid); toks_obj = json_parse_input(cmd_obj, strlen(cmd_obj) - 1, &valid); assert(!toks_obj); assert(valid); /* This should work */ toks_arr = json_parse_input(cmd_arr, strlen(cmd_arr), &valid); assert(toks_arr); assert(tal_count(toks_arr) == 17); assert(valid); toks_obj = json_parse_input(cmd_obj, strlen(cmd_obj), &valid); assert(toks_obj); assert(tal_count(toks_obj) == 19); assert(valid); assert(toks_arr[0].type == JSMN_OBJECT); assert(json_tok_len(toks_arr) == strlen(cmd_arr)); assert(strncmp(json_tok_contents(cmd_arr, toks_arr), cmd_arr, json_tok_len(toks_arr)) == 0); assert(toks_obj[0].type == JSMN_OBJECT); assert(json_tok_len(toks_obj) == strlen(cmd_obj)); assert(strncmp(json_tok_contents(cmd_obj, toks_obj), cmd_obj, json_tok_len(toks_obj)) == 0); /* It's not a string, so this will fail. */ assert(!json_tok_streq(cmd_arr, toks_arr, cmd_obj)); assert(json_tok_streq(cmd_arr, toks_arr+1, "method")); assert(json_tok_streq(cmd_obj, toks_obj+1, "method")); assert(json_tok_is_null(cmd_arr, toks_arr + 5)); assert(!json_tok_is_null(cmd_arr, toks_arr + 6)); assert(!json_tok_is_null(cmd_arr, toks_arr + 7)); assert(json_get_member(cmd_arr, toks_arr, "method") == toks_arr+2); assert(json_get_member(cmd_obj, toks_obj, "method") == toks_obj+2); assert(!json_get_member(cmd_arr, toks_arr, "dev-echo")); assert(!json_get_member(cmd_obj, toks_obj, "arg2")); arr_params = json_get_member(cmd_arr, toks_arr, "params"); assert(arr_params == toks_arr+4); assert(arr_params->type == JSMN_ARRAY); obj_params = json_get_member(cmd_obj, toks_obj, "params"); assert(obj_params == toks_obj+4); assert(obj_params->type == JSMN_OBJECT); assert(json_get_member(cmd_arr, toks_arr, "id") == toks_arr+15); assert(json_get_member(cmd_obj, toks_obj, "id") == toks_obj+17); /* get_member works in sub objects */ assert(json_get_member(cmd_obj, obj_params, "arg4") == toks_obj + 15); json_get_params(cmd_arr, arr_params, "arg1", &arg1, "arg2", &arg2, "arg3", &arg3, "arg4", &arg4, "arg5", &arg5, NULL); assert(arg1 == NULL); assert(arg2 == toks_arr + 6); assert(arg2->type == JSMN_ARRAY); assert(arg3 == toks_arr + 10); assert(arg3->type == JSMN_OBJECT); assert(arg4 == toks_arr + 13); assert(arg4->type == JSMN_STRING); assert(arg5 == NULL); json_get_params(cmd_obj, obj_params, "arg1", &arg1, "arg2", &arg2, "arg3", &arg3, "arg4", &arg4, "arg5", &arg5, NULL); assert(arg1 == NULL); assert(arg2 == toks_obj + 6); assert(arg2->type == JSMN_ARRAY); assert(arg3 == toks_obj + 11); assert(arg3->type == JSMN_OBJECT); assert(arg4 == toks_obj + 15); assert(arg4->type == JSMN_STRING); assert(arg5 == NULL); /* Test json_delve() */ assert(json_delve(cmd_arr, toks_arr, ".method") == toks_arr + 2); assert(json_delve(cmd_arr, toks_arr, ".params[0]") == toks_arr + 5); assert(json_delve(cmd_arr, toks_arr, ".params[1]") == toks_arr + 6); assert(json_delve(cmd_arr, toks_arr, ".params[2]") == toks_arr + 10); assert(json_delve(cmd_arr, toks_arr, ".params[1][2]") == toks_arr + 9); assert(json_delve(cmd_arr, toks_arr, ".params[4]") == NULL); assert(json_delve(cmd_arr, toks_arr, ".params[1][4]") == NULL); assert(json_delve(cmd_arr, toks_arr, ".params[3][4]") == NULL); assert(json_delve(cmd_arr, toks_arr, ".unknown") == NULL); assert(json_delve(cmd_arr, toks_arr, ".unknown[1]") == NULL); assert(json_delve(cmd_arr, toks_arr, ".param") == NULL); assert(json_delve(cmd_arr, toks_arr, ".params\"") == NULL); assert(json_delve(cmd_arr, toks_arr, ".dev-echo") == NULL); assert(json_delve(cmd_arr, toks_arr, ".id[0]") == NULL); assert(json_delve(cmd_obj, toks_obj, ".params.arg3.one") == toks_obj + 13); /* More exotic object creation */ cmd_arr = tal_arr(ctx, char, 0); json_add_object(&cmd_arr, "arg2", JSMN_ARRAY, "[ 1, 2, 3 ]", "arg3", JSMN_OBJECT, "{ \"one\" : 1 }", "arg4", JSMN_STRING, "four", NULL); assert(streq(cmd_arr, "{ \"arg2\" : [ 1, 2, 3 ]," " \"arg3\" : { \"one\" : 1 }," " \"arg4\" : \"four\" }")); cmd_arr = tal_arr(ctx, char, 0); json_object_start(&cmd_arr, NULL); json_add_pubkey(&cmd_arr, "key", helper_public_key(0)); memset(&sha, 42, sizeof(sha)); json_add_double_sha(&cmd_arr, "sha", &sha); json_add_address(&cmd_arr, "test-address", true, helper_addr(0)); json_add_address(&cmd_arr, "address", false, helper_addr(0)); json_object_end(&cmd_arr); assert(streq(cmd_arr, "{ \"key\" : \"0214f24666a59e62c8b92a0b4b58f2a1cdeb573ea377e42f411be028292ff81926\"," " \"sha\" : \"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\"," " \"test-address\" : \"qKCafy33t92L9Nmoxx8H6NHDuiyGViqWBZ\"," " \"address\" : \"PZZyf1xcSbNFodrGQ6ot4LrsdSUu1bgmkc\" }")); tal_free(ctx); return 0; }
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); }