Ejemplo n.º 1
0
int main(int argc, char *argv[])
{
    plan_tests(12);

    /* --aaa without args. */
    opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", "");
    ok1(!parse_args(&argc, &argv, "--aaa", NULL));
    ok1(strstr(err_output, ": --aaa: requires an argument"));
    free(err_output);
    err_output = NULL;
    ok1(!parse_args(&argc, &argv, "-a", NULL));
    ok1(strstr(err_output, ": -a: requires an argument"));
    free(err_output);
    err_output = NULL;

    /* Multiple */
    opt_register_arg("--bbb|-b|-c|--ccc", test_arg, NULL, "aaa", "");
    ok1(!parse_args(&argc, &argv, "--bbb", NULL));
    ok1(strstr(err_output, ": --bbb: requires an argument"));
    free(err_output);
    err_output = NULL;
    ok1(!parse_args(&argc, &argv, "-b", NULL));
    ok1(strstr(err_output, ": -b: requires an argument"));
    free(err_output);
    err_output = NULL;
    ok1(!parse_args(&argc, &argv, "-c", NULL));
    ok1(strstr(err_output, ": -c: requires an argument"));
    free(err_output);
    err_output = NULL;
    ok1(!parse_args(&argc, &argv, "--ccc", NULL));
    ok1(strstr(err_output, ": --ccc: requires an argument"));
    free(err_output);
    err_output = NULL;

    /* parse_args allocates argv */
    free(argv);
    return exit_status();
}
Ejemplo n.º 2
0
int main(int argc, char *argv[])
{
	OpenChannel *o1, *o2;
	struct bitcoin_tx *anchor;
	const tal_t *ctx = tal_arr(NULL, char, 0);
	u64 anchor_fee, amount, total_in, change;
	struct input *in;
	u8 *redeemscript;
	size_t i;
	struct pubkey pubkey1, pubkey2;

	err_set_progname(argv[0]);

	anchor_fee = 10000;
	
	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "<open-channel-file1> <open-channel-file2> <amount> <changepubkey> <txid>/<outnum>/<satoshis>/<script-in-hex>/<privkey>...\n"
			   "A test program to create an anchor tx on stdout.",
			   "Print this message.");
	opt_register_arg("--anchor-fee=<bits>",
			 opt_set_bits, opt_show_bits, &anchor_fee,
			 "100's of satoshi to pay for anchor");
	opt_register_version();

 	opt_parse(&argc, argv, opt_log_stderr_exit);

	if (argc < 6)
		opt_usage_exit_fail("Expected 5 or more arguments");

	o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
	o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
	if (!proto_to_pubkey(o1->commit_key, &pubkey1))
		errx(1, "Invalid o1 commit_key");
	if (!proto_to_pubkey(o2->commit_key, &pubkey2))
		errx(1, "Invalid o2 commit_key");

	amount = atol(argv[3]);
	if (!amount)
		errx(1, "Invalid total: must be > 0");

	in = tal_arr(ctx, struct input, argc - 5);

	total_in = 0;
	for (i = 0; i < tal_count(in); i++) {
		parse_anchor_input(argv[5+i], &in[i]);
		total_in += in[i].in.input_amount;
	}

	if (total_in < amount + anchor_fee)
		errx(1, "Only %llu satoshi in, and %llu out (+%llu fee)",
		     (unsigned long long)total_in,
		     (unsigned long long)amount,
		     (unsigned long long)anchor_fee);

	change = total_in - (amount + anchor_fee);

	/* If there's change, we have an extra output. */
	anchor = bitcoin_tx(ctx, tal_count(in), change ? 2 : 1);
	anchor->fee = anchor_fee;

	/* Commitment redeems this via 2 of 2 payment. */
	redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);

	/* Set up outputs. */
	anchor->output[0].amount = amount;
	anchor->output[0].script = scriptpubkey_p2sh(anchor, redeemscript);
	anchor->output[0].script_length = tal_count(anchor->output[0].script);

	if (change) {
		struct pubkey change_key;

		if (!pubkey_from_hexstr(argv[4], &change_key))
			errx(1, "Invalid change key %s", argv[3]);

		redeemscript = bitcoin_redeem_single(anchor, &change_key);
		anchor->output[1].amount = change;
		anchor->output[1].script = scriptpubkey_p2sh(anchor,
							     redeemscript);
		anchor->output[1].script_length
			= tal_count(anchor->output[1].script);
	}

	/* Set up inputs (leaving scripts empty for signing) */
	for (i = 0; i < tal_count(in); i++) {
		anchor->input[i].input_amount = in[i].in.input_amount;
		anchor->input[i].txid = in[i].in.txid;
		anchor->input[i].index = in[i].in.index;
	}
	
	/* Now, sign each input. */
	for (i = 0; i < tal_count(in); i++) {
		in[i].sig.stype = SIGHASH_ALL;
		if (!sign_tx_input(ctx, anchor, i, in[i].in.script,
				   in[i].in.script_length,
				   &in[i].privkey, &in[i].pubkey,
				   &in[i].sig.sig))
			errx(1, "Error signing input %zi", i);
	}

	/* Finally, complete inputs using signatures. */
	for (i = 0; i < tal_count(in); i++) {
		if (!is_pay_to_pubkey_hash(in[i].in.script,
					   in[i].in.script_length))
			errx(1, "FIXME: Don't know how to handle input %zi", i);
		anchor->input[i].script
			= scriptsig_pay_to_pubkeyhash(anchor, &in[i].pubkey,
						      &in[i].sig);
		anchor->input[i].script_length
			= tal_count(anchor->input[i].script);
	}

	/* Print it out in hex. */
	if (!bitcoin_tx_write(STDOUT_FILENO, anchor))
		err(1, "Writing out transaction");

	tal_free(ctx);
	return 0;
}
Ejemplo n.º 3
0
int main(int argc, char *argv[])
{
	const tal_t *ctx = tal_arr(NULL, char, 0);
	OpenChannel *o1, *o2;
	OpenAnchor *a;
	struct bitcoin_tx *commit, *tx;
	struct bitcoin_signature sig;
	struct privkey privkey;
	bool testnet;
	struct pubkey pubkey1, pubkey2, outpubkey;
	u8 *redeemscript;
	struct sha256 rhash;
	size_t p2sh_out;
	u64 fee = 10000;
	u32 locktime;

	err_set_progname(argv[0]);

	/* FIXME: If we've updated channel since, we need the final
	 * revocation hash we sent (either update_accept or update_complete) */
	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "<commitment-tx> <open-channel-file1> <open-channel-file2> <open-anchor-file> <my-privoutkey> <someaddress> [previous-updates]\n"
			   "Create the transaction to spend our commit transaction",
			   "Print this message.");
	opt_register_arg("--fee=<bits>",
			 opt_set_bits, opt_show_bits, &fee,
			 "100's of satoshi to pay in transaction fee");
	opt_register_version();

 	opt_parse(&argc, argv, opt_log_stderr_exit);

	if (argc < 6)
		opt_usage_exit_fail("Expected 5+ arguments");

	commit = bitcoin_tx_from_file(ctx, argv[1]);

	o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
	o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
	a = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
	if (!proto_to_rel_locktime(o2->delay, &locktime))
		errx(1, "Invalid locktime in o2");

 	/* We need our private key to spend commit output. */
	if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
		errx(1, "Invalid private key '%s'", argv[5]);
	if (!testnet)
		errx(1, "Private key '%s' not on testnet!", argv[5]);

	if (!pubkey_from_hexstr(argv[6], &outpubkey))
		errx(1, "Invalid bitcoin pubkey '%s'", argv[6]);

	/* Get pubkeys */
	if (!proto_to_pubkey(o1->final_key, &pubkey2))
		errx(1, "Invalid o1 final pubkey");
	if (!pubkey_eq(&pubkey1, &pubkey2))
		errx(1, "o1 pubkey != this privkey");
	if (!proto_to_pubkey(o2->final_key, &pubkey2))
		errx(1, "Invalid o2 final pubkey");

	/* We use this simply to get final revocation hash. */
	gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 7,
		       NULL, &rhash, NULL, NULL);

	/* Create redeem script */
	redeemscript = bitcoin_redeem_secret_or_delay(ctx, &pubkey1, locktime,
						      &pubkey2, &rhash);

	/* Now, create transaction to spend it. */
	tx = bitcoin_tx(ctx, 1, 1);
	bitcoin_txid(commit, &tx->input[0].txid);
	p2sh_out = find_p2sh_out(commit, redeemscript);
	tx->input[0].index = p2sh_out;
	tx->input[0].input_amount = commit->output[p2sh_out].amount;
	tx->fee = fee;

	tx->input[0].sequence_number = bitcoin_nsequence(locktime);

	if (commit->output[p2sh_out].amount <= fee)
		errx(1, "Amount of %llu won't exceed fee",
		     (unsigned long long)commit->output[p2sh_out].amount);

	tx->output[0].amount = commit->output[p2sh_out].amount - fee;
	tx->output[0].script = scriptpubkey_p2sh(tx,
						 bitcoin_redeem_single(tx, &outpubkey));
	tx->output[0].script_length = tal_count(tx->output[0].script);

	/* Now get signature, to set up input script. */
	if (!sign_tx_input(tx, tx, 0, redeemscript, tal_count(redeemscript),
			   &privkey, &pubkey1, &sig.sig))
		errx(1, "Could not sign tx");
	sig.stype = SIGHASH_ALL;
	tx->input[0].script = scriptsig_p2sh_secret(tx, NULL, 0, &sig,
						    redeemscript,
						    tal_count(redeemscript));
	tx->input[0].script_length = tal_count(tx->input[0].script);

	/* Print it out in hex. */
	if (!bitcoin_tx_write(STDOUT_FILENO, tx))
		err(1, "Writing out transaction");

	tal_free(ctx);
	return 0;
}
Ejemplo n.º 4
0
int main(int argc, char *argv[])
{
	u8 version;
	beint16_t be_inlen;
	struct amount_sat sat;
	bool verbose = false;
	char *infile = NULL, *outfile = NULL, *scidfile = NULL, *csat = NULL;
	int infd = 0, outfd;
       	FILE * scidfd;
	struct scidsat * scids = NULL;
	unsigned max = -1U;

	setup_locale();

	opt_register_noarg("--verbose|-v", opt_set_bool, &verbose,
			   "Print progress to stderr");
	opt_register_arg("--output|-o", opt_set_charp, NULL, &outfile,
			 "Send output to this file instead of stdout");
	opt_register_arg("--input|-i", opt_set_charp, NULL, &infile,
			 "Read input from this file instead of stdin");
	opt_register_arg("--scidfile", opt_set_charp, NULL, &scidfile,
			 "Input for 'scid, satshis' csv");
	opt_register_arg("--sat", opt_set_charp, NULL, &csat,
			 "default satoshi value if --scidfile flag not present");
	opt_register_arg("--max", opt_set_uintval, opt_show_uintval, &max,
			 "maximum number of messages to read");
	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "Create gossip store, from be16 / input messages",
			   "Print this message.");

	opt_parse(&argc, argv, opt_log_stderr_exit);


        if (scidfile) {
		scidfd = fopen(scidfile, "r");
		if (scidfd < 0)
			err(1, "opening %s", scidfile);
                scids = load_scid_file(scidfd);
	        fclose(scidfd);
	}
	else if (csat) {
		if (!parse_amount_sat(&sat, csat, strlen(csat))) {
		        errx(1, "Invalid satoshi amount %s", csat);
		}
	}
	else {
		err(1, "must contain either --sat xor --scidfile");
	}

	if (infile) {
		infd = open(infile, O_RDONLY);
		if (infd < 0)
			err(1, "opening %s", infile);
	}

	if (outfile) {
		outfd = open(outfile, O_WRONLY|O_TRUNC|O_CREAT, 0666);
		if (outfd < 0)
			err(1, "opening %s", outfile);
	} else
		outfd = STDOUT_FILENO;

	version = GOSSIP_STORE_VERSION;
	if (!write_all(outfd, &version, sizeof(version)))
		err(1, "Writing version");

	int scidi = 0;
	int channels = 0;
	int nodes = 0;
	int updates = 0;
	while (read_all(infd, &be_inlen, sizeof(be_inlen))) {
		u32 msglen = be16_to_cpu(be_inlen);
		u8 *inmsg = tal_arr(NULL, u8, msglen), *outmsg;
		beint32_t be_outlen;
		beint32_t becsum;

		if (!read_all(infd, inmsg, msglen))
			err(1, "Only read partial message");

		switch (fromwire_peektype(inmsg)) {
		case WIRE_CHANNEL_ANNOUNCEMENT:
			if (scids) {
				sat = scids[scidi].sat;
				scidi += 1;
			}
			channels += 1;
			outmsg = towire_gossip_store_channel_announcement(inmsg, inmsg, sat);
			break;
		case WIRE_CHANNEL_UPDATE:
			outmsg = towire_gossip_store_channel_update(inmsg, inmsg);
			updates += 1;
			break;
		case WIRE_NODE_ANNOUNCEMENT:
			outmsg = towire_gossip_store_node_announcement(inmsg, inmsg);
			nodes += 1;
			break;
		default:
			warnx("Unknown message %u (%s)", fromwire_peektype(inmsg),
			      wire_type_name(fromwire_peektype(inmsg)));
			tal_free(inmsg);
			continue;
		}
		if (verbose)
			fprintf(stderr, "%s->%s\n",
				wire_type_name(fromwire_peektype(inmsg)),
				gossip_store_type_name(fromwire_peektype(outmsg)));

		becsum = cpu_to_be32(crc32c(0, outmsg, tal_count(outmsg)));
		be_outlen = cpu_to_be32(tal_count(outmsg));
		if (!write_all(outfd, &be_outlen, sizeof(be_outlen))
		    || !write_all(outfd, &becsum, sizeof(becsum))
		    || !write_all(outfd, outmsg, tal_count(outmsg))) {
			exit(1);
		}
		tal_free(inmsg);
		if (--max == 0)
			break;
	}
	fprintf(stderr, "channels %d, updates %d, nodes %d\n", channels, updates, nodes);
	free(scids);
	return 0;
}
Ejemplo n.º 5
0
/* Test helpers. */
int main(int argc, char *argv[])
{
	char *output;
	char *longname = strdup("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
	char *shortname = strdup("shortname");

	plan_tests(48);
	opt_register_table(subtables, NULL);
	opt_register_noarg("--kkk|-k", my_cb, NULL, "magic kkk option");
	opt_register_noarg("-?", opt_usage_and_exit, "<MyArgs>...",
			   "This message");
	opt_register_arg("--longname", opt_set_charp, opt_show_charp,
			 &longname, "a really long option default");
	opt_register_arg("--shortname", opt_set_charp, opt_show_charp,
			 &shortname, "a short option default");
	output = opt_usage("my name", "ExTrA Args");
	diag("%s", output);
	ok1(strstr(output, "Usage: my name"));
	ok1(strstr(output, "--jjj|-j|--lll|-l <arg>"));
	ok1(strstr(output, "ExTrA Args"));
	ok1(strstr(output, "-a "));
	ok1(strstr(output, " Description of a\n"));
	ok1(strstr(output, "-b <arg>"));
	ok1(strstr(output, " Description of b (default: b)\n"));
	ok1(strstr(output, "--ddd "));
	ok1(strstr(output, " Description of ddd\n"));
	ok1(strstr(output, "--eee <filename> "));
	ok1(strstr(output, " (default: eee)\n"));
	ok1(strstr(output, "long table options:\n"));
	ok1(strstr(output, "--ggg|-g "));
	ok1(strstr(output, " Description of ggg\n"));
	ok1(strstr(output, "-h|--hhh <arg>"));
	ok1(strstr(output, " Description of hhh\n"));
	ok1(strstr(output, "--kkk|-k"));
	ok1(strstr(output, "magic kkk option"));
	/* This entry is hidden. */
	ok1(!strstr(output, "--mmm|-m"));
	free(output);

	/* NULL should use string from registered options. */
	output = opt_usage("my name", NULL);
	diag("%s", output);
	ok1(strstr(output, "Usage: my name"));
	ok1(strstr(output, "--jjj|-j|--lll|-l <arg>"));
	ok1(strstr(output, "<MyArgs>..."));
	ok1(strstr(output, "-a "));
	ok1(strstr(output, " Description of a\n"));
	ok1(strstr(output, "-b <arg>"));
	ok1(strstr(output, " Description of b (default: b)\n"));
	ok1(strstr(output, "--ddd "));
	ok1(strstr(output, " Description of ddd\n"));
	ok1(strstr(output, "--eee <filename> "));
	ok1(strstr(output, " (default: eee)\n"));
	ok1(strstr(output, "long table options:\n"));
	ok1(strstr(output, "--ggg|-g "));
	ok1(strstr(output, " Description of ggg\n"));
	ok1(strstr(output, "-h|--hhh <arg>"));
	ok1(strstr(output, " Description of hhh\n"));
	ok1(strstr(output, "--kkk|-k"));
	ok1(strstr(output, "magic kkk option"));
	ok1(strstr(output, "--longname"));
	ok1(strstr(output, "a really long option default"));
	ok1(strstr(output, "(default: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"...)"));
	ok1(strstr(output, "--shortname"));
	ok1(strstr(output, "a short option default"));
	ok1(strstr(output, "(default: \"shortname\")"));
	/* This entry is hidden. */
	ok1(!strstr(output, "--mmm|-m"));
	free(output);

	reset_options();
	/* Empty table test. */
	output = opt_usage("nothing", NULL);
	ok1(strstr(output, "Usage: nothing \n"));
	free(output);

	/* No short args. */
	opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll");
	output = opt_usage("onearg", NULL);
	ok1(strstr(output, "Usage: onearg \n"));
	ok1(strstr(output, "--aaa"));
	ok1(strstr(output, "AAAAll"));
	free(output);

	free(shortname);
	free(longname);
	return exit_status();
}
Ejemplo n.º 6
0
int main(int argc, char *argv[])
{
	struct io_conn *conn = tal(NULL, struct io_conn);
	struct wireaddr_internal addr;
	int af = -1;
	struct pubkey us, them;
	const char *err_msg;
	const char *at;
	struct addrinfo *ai = NULL;

	setup_locale();
	secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
						 SECP256K1_CONTEXT_SIGN);

	opt_register_noarg("--initial-sync", opt_set_bool, &initial_sync,
			   "Stream complete gossip history at start");
	opt_register_arg("--max-messages", opt_set_ulongval, opt_show_ulongval,
			 &max_messages,
			 "Terminate after reading this many messages (> 0)");
	opt_register_noarg("--stdin", opt_set_bool, &stream_stdin,
			   "Stream gossip messages from stdin.");
	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "id@addr[:port] [hex-msg-tosend...]\n"
			   "Connect to a lightning peer and relay gossip messages from it",
			   "Print this message.");

	opt_parse(&argc, argv, opt_log_stderr_exit);
	if (argc < 2)
		opt_usage_exit_fail("Need an id@addr to connect to");
	at = strchr(argv[1], '@');
	if (!at)
		opt_usage_exit_fail("Need id@addr");

	if (!pubkey_from_hexstr(argv[1], at - argv[1], &them))
		opt_usage_exit_fail("Invalid id %.*s",
				    (int)(at - argv[1]), argv[1]);

	if (!parse_wireaddr_internal(at+1, &addr, DEFAULT_PORT, NULL,
				     true, false, &err_msg))
		opt_usage_exit_fail("%s '%s'", err_msg, argv[1]);

	switch (addr.itype) {
	case ADDR_INTERNAL_SOCKNAME:
		af = AF_LOCAL;
		ai = wireaddr_internal_to_addrinfo(conn, &addr);
		break;
	case ADDR_INTERNAL_ALLPROTO:
	case ADDR_INTERNAL_AUTOTOR:
	case ADDR_INTERNAL_FORPROXY:
		opt_usage_exit_fail("Don't support proxy use");

	case ADDR_INTERNAL_WIREADDR:
		switch (addr.u.wireaddr.type) {
		case ADDR_TYPE_TOR_V2:
		case ADDR_TYPE_TOR_V3:
			opt_usage_exit_fail("Don't support proxy use");
			break;
		case ADDR_TYPE_IPV4:
			af = AF_INET;
			break;
		case ADDR_TYPE_IPV6:
			af = AF_INET6;
			break;
		}
		ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr);
	}

	if (af == -1 || ai == NULL)
		err(1, "Initializing socket");

	conn->fd = socket(af, SOCK_STREAM, 0);
	if (conn->fd < 0)
		err(1, "Creating socket");

	memset(&notsosecret, 0x42, sizeof(notsosecret));
	if (!pubkey_from_secret(&notsosecret, &us))
		errx(1, "Creating pubkey");

	if (connect(conn->fd, ai->ai_addr, ai->ai_addrlen) != 0)
		err(1, "Connecting to %s", at+1);

	initiator_handshake(conn, &us, &them, &addr, handshake_success, argv+2);
	exit(0);
}
Ejemplo n.º 7
0
int main(int argc, char *argv[])
{
	const char *myname = argv[0];

	plan_tests(215);

	/* Simple short arg.*/
	opt_register_noarg("-a", test_noarg, NULL, "All");
	ok1(parse_args(&argc, &argv, "-a", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 1);

	/* Simple long arg. */
	opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll");
	ok1(parse_args(&argc, &argv, "--aaa", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 2);

	/* Both long and short args. */
	opt_register_noarg("--aaa|-a", test_noarg, NULL, "AAAAAAll");
	ok1(parse_args(&argc, &argv, "--aaa", "-a", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 4);

	/* Extra arguments preserved. */
	ok1(parse_args(&argc, &argv, "--aaa", "-a", "extra", "args", NULL));
	ok1(argc == 3);
	ok1(argv[0] == myname);
	ok1(strcmp(argv[1], "extra") == 0);
	ok1(strcmp(argv[2], "args") == 0);
	ok1(test_cb_called == 6);

	/* Malformed versions. */
	ok1(!parse_args(&argc, &argv, "--aaa=arg", NULL));
	ok1(strstr(err_output, ": --aaa: doesn't allow an argument"));
	ok1(!parse_args(&argc, &argv, "--aa", NULL));
	ok1(strstr(err_output, ": --aa: unrecognized option"));
	ok1(!parse_args(&argc, &argv, "--aaargh", NULL));
	ok1(strstr(err_output, ": --aaargh: unrecognized option"));

	/* Argument variants. */
	reset_options();
	test_cb_called = 0;
	opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", "AAAAAAll");
	ok1(parse_args(&argc, &argv, "--aaa", "aaa", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(test_cb_called == 1);

	ok1(parse_args(&argc, &argv, "--aaa=aaa", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(test_cb_called == 2);

	ok1(parse_args(&argc, &argv, "-a", "aaa", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(test_cb_called == 3);

	/* Malformed versions. */
	ok1(!parse_args(&argc, &argv, "-a", NULL));
	ok1(strstr(err_output, ": -a: requires an argument"));
	ok1(!parse_args(&argc, &argv, "--aaa", NULL));
	ok1(strstr(err_output, ": --aaa: requires an argument"));
	ok1(!parse_args(&argc, &argv, "--aa", NULL));
	ok1(strstr(err_output, ": --aa: unrecognized option"));
	ok1(!parse_args(&argc, &argv, "--aaargh", NULL));
	ok1(strstr(err_output, ": --aaargh: unrecognized option"));

	/* Now, tables. */
	/* Short table: */
	reset_options();
	test_cb_called = 0;
	opt_register_table(short_table, NULL);
	ok1(parse_args(&argc, &argv, "-a", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 1);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "-b", NULL) == false);
	ok1(test_cb_called == 1);
	ok1(parse_args(&argc, &argv, "-b", "b", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 2);

	/* Long table: */
	reset_options();
	test_cb_called = 0;
	opt_register_table(long_table, NULL);
	ok1(parse_args(&argc, &argv, "--ddd", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 1);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "--eee", NULL) == false);
	ok1(test_cb_called == 1);
	ok1(parse_args(&argc, &argv, "--eee", "eee", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 2);

	/* Short and long, both. */
	reset_options();
	test_cb_called = 0;
	opt_register_table(long_and_short_table, NULL);
	ok1(parse_args(&argc, &argv, "-g", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 1);
	ok1(parse_args(&argc, &argv, "--ggg", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 2);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "-h", NULL) == false);
	ok1(test_cb_called == 2);
	ok1(parse_args(&argc, &argv, "-h", "hhh", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 3);
	ok1(parse_args(&argc, &argv, "--hhh", NULL) == false);
	ok1(test_cb_called == 3);
	ok1(parse_args(&argc, &argv, "--hhh", "hhh", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 4);

	/* Those will all work as tables. */
	test_cb_called = 0;
	reset_options();
	opt_register_table(subtables, NULL);
	ok1(parse_args(&argc, &argv, "-a", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 1);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "-b", NULL) == false);
	ok1(test_cb_called == 1);
	ok1(parse_args(&argc, &argv, "-b", "b", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 2);

	ok1(parse_args(&argc, &argv, "--ddd", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 3);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "--eee", NULL) == false);
	ok1(test_cb_called == 3);
	ok1(parse_args(&argc, &argv, "--eee", "eee", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 4);

	/* Short and long, both. */
	ok1(parse_args(&argc, &argv, "-g", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 5);
	ok1(parse_args(&argc, &argv, "--ggg", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 6);
	/* This one needs an arg. */
	ok1(parse_args(&argc, &argv, "-h", NULL) == false);
	ok1(test_cb_called == 6);
	ok1(parse_args(&argc, &argv, "-h", "hhh", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 7);
	ok1(parse_args(&argc, &argv, "--hhh", NULL) == false);
	ok1(test_cb_called == 7);
	ok1(parse_args(&argc, &argv, "--hhh", "hhh", NULL));
	ok1(argc == 1);
	ok1(argv[0] == myname);
	ok1(argv[1] == NULL);
	ok1(test_cb_called == 8);

	/* Now the tricky one: -? must not be confused with an unknown option */
	test_cb_called = 0;
	reset_options();

	/* glibc's getopt does not handle ? with arguments. */
	opt_register_noarg("-?", test_noarg, NULL, "Help");
	ok1(parse_args(&argc, &argv, "-?", NULL));
	ok1(test_cb_called == 1);
	ok1(parse_args(&argc, &argv, "-a", NULL) == false);
	ok1(test_cb_called == 1);
	ok1(strstr(err_output, ": -a: unrecognized option"));
	ok1(parse_args(&argc, &argv, "--aaaa", NULL) == false);
	ok1(test_cb_called == 1);
	ok1(strstr(err_output, ": --aaaa: unrecognized option"));

	test_cb_called = 0;
	reset_options();

	/* Corner cases involving short arg parsing weirdness. */
	opt_register_noarg("-a|--aaa", test_noarg, NULL, "a");
	opt_register_arg("-b|--bbb", test_arg, NULL, "bbb", "b");
	opt_register_arg("-c|--ccc", test_arg, NULL, "aaa", "c");
	/* -aa == -a -a */
	ok1(parse_args(&argc, &argv, "-aa", NULL));
	ok1(test_cb_called == 2);
	ok1(parse_args(&argc, &argv, "-aab", NULL) == false);
	ok1(test_cb_called == 4);
	ok1(strstr(err_output, ": -b: requires an argument"));
	ok1(parse_args(&argc, &argv, "-bbbb", NULL));
	ok1(test_cb_called == 5);
	ok1(parse_args(&argc, &argv, "-aabbbb", NULL));
	ok1(test_cb_called == 8);
	ok1(parse_args(&argc, &argv, "-aabbbb", "-b", "bbb", NULL));
	ok1(test_cb_called == 12);
	ok1(parse_args(&argc, &argv, "-aabbbb", "--bbb", "bbb", NULL));
	ok1(test_cb_called == 16);
	ok1(parse_args(&argc, &argv, "-aabbbb", "--bbb=bbb", NULL));
	ok1(test_cb_called == 20);
	ok1(parse_args(&argc, &argv, "-aacaaa", NULL));
	ok1(test_cb_called == 23);
	ok1(parse_args(&argc, &argv, "-aacaaa", "-a", NULL));
	ok1(test_cb_called == 27);
	ok1(parse_args(&argc, &argv, "-aacaaa", "--bbb", "bbb", "-aacaaa",
		       NULL));
	ok1(test_cb_called == 34);

	test_cb_called = 0;
	reset_options();

	/* -- and POSIXLY_CORRECT */
	opt_register_noarg("-a|--aaa", test_noarg, NULL, "a");
	ok1(parse_args(&argc, &argv, "-a", "--", "-a", NULL));
	ok1(test_cb_called == 1);
	ok1(argc == 2);
	ok1(strcmp(argv[1], "-a") == 0);
	ok1(!argv[2]);

	unsetenv("POSIXLY_CORRECT");
	ok1(parse_args(&argc, &argv, "-a", "somearg", "-a", "--", "-a", NULL));
	ok1(test_cb_called == 3);
	ok1(argc == 3);
	ok1(strcmp(argv[1], "somearg") == 0);
	ok1(strcmp(argv[2], "-a") == 0);
	ok1(!argv[3]);

	setenv("POSIXLY_CORRECT", "1", 1);
	ok1(parse_args(&argc, &argv, "-a", "somearg", "-a", "--", "-a", NULL));
	ok1(test_cb_called == 4);
	ok1(argc == 5);
	ok1(strcmp(argv[1], "somearg") == 0);
	ok1(strcmp(argv[2], "-a") == 0);
	ok1(strcmp(argv[3], "--") == 0);
	ok1(strcmp(argv[4], "-a") == 0);
	ok1(!argv[5]);

	/* parse_args allocates argv */
	free(argv);
	return exit_status();
}
Ejemplo n.º 8
0
int main(int argc, char *argv[])
{
	const tal_t *ctx = tal_arr(NULL, char, 0);
	OpenChannel *o1, *o2;
	OpenAnchor *a;
	struct bitcoin_tx *close_tx;
	struct pkt *pkt;
	struct signature sig;
	struct privkey privkey;
	bool testnet;
	struct pubkey pubkey1, pubkey2;
	u8 *redeemscript;
	char *close_file = NULL;
	u64 close_fee = 10000;
	struct channel_state *cstate;

	err_set_progname(argv[0]);

	opt_register_arg("--complete=<close-msg-file>",
			 opt_set_charp, NULL, &close_file,
			 "Create a close_transaction_complete msg instead");
	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "<open-channel-file1> <open-channel-file2> <anchor-file> <commit-privkey> [{+/-}update-protobuf]...\n"
			   "Create the signature needed for the close transaction",
			   "Print this message.");
	opt_register_arg("--close-fee=<bits>",
			 opt_set_bits, opt_show_bits, &close_fee,
			 "100's of satoshi to pay for close tx");
	opt_register_version();

 	opt_parse(&argc, argv, opt_log_stderr_exit);

	if (argc < 5)
		opt_usage_exit_fail("Expected 4+ arguments");

	o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
	o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
	a = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;

	if (!key_from_base58(argv[4], strlen(argv[4]), &testnet, &privkey, &pubkey1))
		errx(1, "Invalid private key '%s'", argv[4]);
	if (!testnet)
		errx(1, "Private key '%s' not on testnet!", argv[4]);

	if (close_file) {
		CloseChannel *c;
		c = pkt_from_file(close_file, PKT__PKT_CLOSE)->close;
		close_fee = c->close_fee;
	}
	
	cstate = gather_updates(ctx, o1, o2, a, close_fee, argv + 5, NULL,
		       NULL, NULL, NULL);

	/* Get pubkeys */
	if (!proto_to_pubkey(o1->commit_key, &pubkey2))
		errx(1, "Invalid o1 commit pubkey");
	if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2)
	    || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0)
		errx(1, "o1 pubkey != this privkey");
	if (!proto_to_pubkey(o2->commit_key, &pubkey2))
		errx(1, "Invalid o2 commit pubkey");

	/* This is what the anchor pays to. */
	redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);

	close_tx = create_close_tx(ctx, o1, o2, a, cstate->a.pay, cstate->b.pay);

	/* Sign it for them. */
	sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript),
		      &privkey, &pubkey1, &sig);

	if (close_file)
		pkt = close_channel_complete_pkt(ctx, &sig);
	else
		pkt = close_channel_pkt(ctx, close_fee, &sig);
	if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
		err(1, "Writing out packet");

	tal_free(ctx);
	return 0;
}