mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-06 14:44:22 +01:00
Move hacky command line utils out to test-cli subdir.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
74
test-cli/check-anchor-scriptsigs.c
Normal file
74
test-cli/check-anchor-scriptsigs.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/* My example:
|
||||
* ./check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb > A-anchor.tx
|
||||
* ./check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb > B-anchor.tx
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
OpenAnchorScriptsigs *ss1, *ss2;
|
||||
struct bitcoin_tx *anchor;
|
||||
struct sha256_double txid;
|
||||
u8 *tx_arr;
|
||||
size_t *inmap, *outmap;
|
||||
char *tx_hex;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-channel-file1> <open-channel-file2> <anchor-sig2-1> <anchor-sigs2>\n"
|
||||
"Output the anchor transaction by merging the scriptsigs",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 5)
|
||||
opt_usage_exit_fail("Expected 6 arguments");
|
||||
|
||||
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
|
||||
ss1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS)
|
||||
->open_anchor_scriptsigs;
|
||||
ss2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS)
|
||||
->open_anchor_scriptsigs;
|
||||
|
||||
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap);
|
||||
if (!anchor)
|
||||
errx(1, "Failed transaction merge");
|
||||
if (!anchor_add_scriptsigs(anchor, ss1, ss2, inmap))
|
||||
errx(1, "Wrong number of scriptsigs");
|
||||
|
||||
bitcoin_txid(anchor, &txid);
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, anchor);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out anchor transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
119
test-cli/check-commit-sig.c
Normal file
119
test-cli/check-commit-sig.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/* My example:
|
||||
* ./check-commit-sig A-open.pb B-open.pb A-commit-sig.pb B-commit-sig.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC A-leak-anchor-sigs.pb B-leak-anchor-sigs.pb > A-commit.tx
|
||||
* ./check-commit-sig B-open.pb A-open.pb B-commit-sig.pb A-commit-sig.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC B-leak-anchor-sigs.pb A-leak-anchor-sigs.pb > B-commit.tx
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
OpenCommitSig *cs2;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct sha256_double txid;
|
||||
u8 *tx_arr, *subscript;
|
||||
size_t *inmap, *outmap;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
struct bitcoin_signature sig1, sig2;
|
||||
char *tx_hex;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct sha256 rhash;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-channel-file1> <open-channel-file2> <commit-sig-2> <commit-key1> <leak-anchor-sigs1> <leak-anchor-sigs2>\n"
|
||||
"Output the commitment transaction if both signatures are valid",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 7)
|
||||
opt_usage_exit_fail("Expected 6 arguments");
|
||||
|
||||
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
|
||||
cs2 = pkt_from_file(argv[3], PKT__PKT_OPEN_COMMIT_SIG)->open_commit_sig;
|
||||
|
||||
privkey = key_from_base58(argv[4], strlen(argv[4]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[4]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[4]);
|
||||
|
||||
/* Pubkey well-formed? */
|
||||
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid anchor-2 key");
|
||||
|
||||
/* Get the transaction ID of the anchor. */
|
||||
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap);
|
||||
if (!anchor)
|
||||
errx(1, "Failed transaction merge");
|
||||
anchor_txid(anchor, argv[5], argv[6], inmap, &txid);
|
||||
|
||||
/* Now create our commitment tx. */
|
||||
proto_to_sha256(o1->revocation_hash, &rhash);
|
||||
commit = create_commit_tx(ctx, o1, o2, &rhash, 0, &txid, outmap[0]);
|
||||
|
||||
/* If contributions don't exceed fees, this fails. */
|
||||
if (!commit)
|
||||
errx(1, "Contributions %llu & %llu vs fees %llu & %llu",
|
||||
(long long)o1->anchor->total,
|
||||
(long long)o2->anchor->total,
|
||||
(long long)o1->commitment_fee,
|
||||
(long long)o2->commitment_fee);
|
||||
|
||||
/* FIXME: Creating out signature just to check the script we create
|
||||
* is overkill: if their signature and pubkey signed the commit txin,
|
||||
* we're happy. */
|
||||
sig1.stype = SIGHASH_ALL;
|
||||
subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript),
|
||||
privkey, &pubkey1, &sig1.sig);
|
||||
|
||||
/* Signatures well-formed? */
|
||||
if (!proto_to_signature(cs2->sig, &sig2.sig))
|
||||
errx(1, "Invalid commit-sig-2");
|
||||
sig2.stype = SIGHASH_ALL;
|
||||
|
||||
/* Combined signatures must validate correctly. */
|
||||
if (!check_2of2_sig(commit, 0, subscript, tal_count(subscript),
|
||||
&pubkey1, &pubkey2, &sig1, &sig2))
|
||||
errx(1, "Signature failed");
|
||||
|
||||
/* Create p2sh input for commit */
|
||||
commit->input[0].script = scriptsig_p2sh_2of2(commit, &sig1, &sig2,
|
||||
&pubkey1, &pubkey2);
|
||||
commit->input[0].script_length = tal_count(commit->input[0].script);
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, commit);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
108
test-cli/close-channel.c
Normal file
108
test-cli/close-channel.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* My example:
|
||||
* ./close-channel A-anchor.tx A-open.pb B-open.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC > A-close.pb
|
||||
* ./close-channel --complete A-anchor.tx B-open.pb A-open.pb cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi > B-close-complete.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "close_tx.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
struct bitcoin_tx *anchor, *close_tx;
|
||||
struct sha256_double anchor_txid;
|
||||
struct pkt *pkt;
|
||||
struct signature sig;
|
||||
EC_KEY *privkey;
|
||||
bool testnet, complete = false;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *redeemscript;
|
||||
int64_t delta;
|
||||
size_t i;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
/* FIXME: Take update.pbs to adjust channel */
|
||||
opt_register_noarg("--complete", opt_set_bool, &complete,
|
||||
"Create a close_transaction_complete msg instead");
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<anchor-tx> <open-channel-file1> <open-channel-file2> <commit-privkey> [update-protobuf]...\n"
|
||||
"Create the signature needed for the close transaction",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 5)
|
||||
opt_usage_exit_fail("Expected 4+ arguments");
|
||||
|
||||
anchor = 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;
|
||||
|
||||
privkey = key_from_base58(argv[4], strlen(argv[4]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[4]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[4]);
|
||||
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
|
||||
/* Get delta by accumulting all the updates. */
|
||||
delta = 0;
|
||||
for (i = 5; i < argc; i++) {
|
||||
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
|
||||
delta += u->delta;
|
||||
}
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &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->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* This is what the anchor pays to; figure out whick output. */
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
|
||||
/* Now create the close tx to spend 2/2 output of anchor. */
|
||||
/* Assumes that updates are all from closer -> closee */
|
||||
close_tx = create_close_tx(ctx, o1, o2, complete ? -delta : delta,
|
||||
&anchor_txid,
|
||||
find_p2sh_out(anchor, redeemscript));
|
||||
|
||||
/* Sign it for them. */
|
||||
sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript),
|
||||
privkey, &pubkey1, &sig);
|
||||
|
||||
if (complete)
|
||||
pkt = close_channel_complete_pkt(ctx, &sig);
|
||||
else
|
||||
pkt = close_channel_pkt(ctx, &sig);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
108
test-cli/create-close-tx.c
Normal file
108
test-cli/create-close-tx.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* My example:
|
||||
* ./create-close-tx A-anchor.tx A-open.pb B-open.pb A-close.pb B-close-complete.pb > A-close.tx
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "close_tx.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
struct bitcoin_tx *anchor, *close_tx;
|
||||
struct sha256_double anchor_txid;
|
||||
struct bitcoin_signature sig1, sig2;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *redeemscript, *tx_arr;
|
||||
char *tx_hex;
|
||||
CloseChannel *close;
|
||||
CloseChannelComplete *closecomplete;
|
||||
size_t i;
|
||||
int64_t delta;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
/* FIXME: Take update.pbs to adjust channel */
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<anchor-tx> <open-channel-file1> <open-channel-file2> <close-protobuf> <close-complete-protobuf> [update-protobuf]...\n"
|
||||
"Create the close transaction from the signatures",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 6)
|
||||
opt_usage_exit_fail("Expected 5+ arguments");
|
||||
|
||||
anchor = 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;
|
||||
close = pkt_from_file(argv[4], PKT__PKT_CLOSE)->close;
|
||||
closecomplete = pkt_from_file(argv[5], PKT__PKT_CLOSE_COMPLETE)->close_complete;
|
||||
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
|
||||
/* Pubkeys well-formed? */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1))
|
||||
errx(1, "Invalid anchor-1 key");
|
||||
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid anchor-2 key");
|
||||
|
||||
/* Get delta by accumulting all the updates. */
|
||||
delta = 0;
|
||||
for (i = 6; i < argc; i++) {
|
||||
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
|
||||
delta += u->delta;
|
||||
}
|
||||
|
||||
/* This is what the anchor pays to; figure out which output. */
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
|
||||
/* Now create the close tx to spend 2/2 output of anchor. */
|
||||
close_tx = create_close_tx(ctx, o1, o2, delta, &anchor_txid,
|
||||
find_p2sh_out(anchor, redeemscript));
|
||||
|
||||
/* Signatures well-formed? */
|
||||
sig1.stype = sig2.stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(close->sig, &sig1.sig))
|
||||
errx(1, "Invalid close-packet");
|
||||
if (!proto_to_signature(closecomplete->sig, &sig2.sig))
|
||||
errx(1, "Invalid closecomplete-packet");
|
||||
|
||||
/* Combined signatures must validate correctly. */
|
||||
if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript),
|
||||
&pubkey1, &pubkey2, &sig1, &sig2))
|
||||
errx(1, "Signature failed");
|
||||
|
||||
/* Create p2sh input for close_tx */
|
||||
close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, &sig1, &sig2,
|
||||
&pubkey1, &pubkey2);
|
||||
close_tx->input[0].script_length = tal_count(close_tx->input[0].script);
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, close_tx);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
127
test-cli/create-commit-spend-tx.c
Normal file
127
test-cli/create-commit-spend-tx.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/* My example:
|
||||
* ./create-commit-spend-tx A-commit.tx A-open.pb B-open.pb cTJtiQKZLTufMhhRhxUdbZ2oKJY2MU6sLDEk62mSGoe4NEubLN2e 039bda7e7063afd6aba752b33ca9ae455c4e8d7297b8db01bb06879e0036bde27f > A-spend.tx
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "bitcoin/address.h"
|
||||
#include "opt_bits.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
struct bitcoin_tx *commit, *tx;
|
||||
struct bitcoin_signature sig;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct pubkey pubkey1, pubkey2, outpubkey;
|
||||
u8 *redeemscript, *tx_arr;
|
||||
char *tx_hex;
|
||||
struct sha256 rhash;
|
||||
size_t p2sh_out;
|
||||
u64 fee = 10000;
|
||||
|
||||
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> <my-privoutkey> <someaddress>\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_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;
|
||||
|
||||
/* We need our private key to spend commit output. */
|
||||
privkey = key_from_base58(argv[4], strlen(argv[4]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[4]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[4]);
|
||||
|
||||
if (!pubkey_from_hexstr(argv[5], &outpubkey))
|
||||
errx(1, "Invalid bitcoin pubkey '%s'", argv[5]);
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->final, &pubkey2))
|
||||
errx(1, "Invalid o1 final 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->final, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* o1 gives us the revocation hash */
|
||||
proto_to_sha256(o1->revocation_hash, &rhash);
|
||||
|
||||
/* Create redeem script */
|
||||
redeemscript = bitcoin_redeem_revocable(ctx, &pubkey1,
|
||||
o2->locktime_seconds,
|
||||
&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;
|
||||
|
||||
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 = cpu_to_le32(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_single_sig(tx, redeemscript,
|
||||
tal_count(redeemscript),
|
||||
&sig);
|
||||
tx->input[0].script_length = cpu_to_le32(tal_count(tx->input[0].script));
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, tx);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
126
test-cli/create-commit-tx.c
Normal file
126
test-cli/create-commit-tx.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/* My example:
|
||||
* ./open-commit-sig A-open.pb B-open.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC A-leak-anchor-sigs.pb B-leak-anchor-sigs.pb > A-commit-sig.pb
|
||||
* ./open-commit-sig B-open.pb A-open.pb cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi B-leak-anchor-sigs.pb A-leak-anchor-sigs.pb > B-commit-sig.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
Update *update;
|
||||
UpdateAccept *update_acc;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct sha256_double anchor_txid;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct bitcoin_signature sig1, sig2;
|
||||
size_t i;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *redeemscript, *tx_arr;
|
||||
char *tx_hex;
|
||||
int64_t delta;
|
||||
struct sha256 rhash;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<anchor-tx> <open-channel-file1> <open-channel-file2> <final-update> <final-update-accept> <commit-privkey> [<previous-updates>]\n"
|
||||
"Create the signature needed for the commit transaction",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 7)
|
||||
opt_usage_exit_fail("Expected 6+ arguments");
|
||||
|
||||
anchor = bitcoin_tx_from_file(ctx, argv[1]);
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
|
||||
|
||||
update = pkt_from_file(argv[4], PKT__PKT_UPDATE)->update;
|
||||
update_acc = pkt_from_file(argv[5], PKT__PKT_UPDATE_ACCEPT)->update_accept;
|
||||
|
||||
privkey = key_from_base58(argv[6], strlen(argv[6]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[6]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[6]);
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o1 anchor 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->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o2 anchor pubkey");
|
||||
|
||||
/* Figure out cumulative delta since anchor. */
|
||||
delta = update->delta;
|
||||
for (i = 7; i < argc; i++) {
|
||||
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
|
||||
delta += u->delta;
|
||||
}
|
||||
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
|
||||
/* Now create commitment tx to spend 2/2 output of anchor. */
|
||||
proto_to_sha256(update->revocation_hash, &rhash);
|
||||
commit = create_commit_tx(ctx, o1, o2, &rhash, delta, &anchor_txid,
|
||||
find_p2sh_out(anchor, redeemscript));
|
||||
|
||||
/* If contributions don't exceed fees, this fails. */
|
||||
if (!commit)
|
||||
errx(1, "Bad commit amounts");
|
||||
|
||||
/* We generate our signature. */
|
||||
sig1.stype = SIGHASH_ALL;
|
||||
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript),
|
||||
privkey, &pubkey1, &sig1.sig);
|
||||
|
||||
/* Their signatures comes from the update_accept packet. */
|
||||
sig2.stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(update_acc->sig, &sig2.sig))
|
||||
errx(1, "Invalid update-accept sig");
|
||||
|
||||
if (!check_2of2_sig(commit, 0, redeemscript, tal_count(redeemscript),
|
||||
&pubkey1, &pubkey2, &sig1, &sig2))
|
||||
errx(1, "Signature failed");
|
||||
|
||||
/* Create p2sh input for commit */
|
||||
commit->input[0].script = scriptsig_p2sh_2of2(commit, &sig1, &sig2,
|
||||
&pubkey1, &pubkey2);
|
||||
commit->input[0].script_length = tal_count(commit->input[0].script);
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, commit);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
135
test-cli/create-steal-tx.c
Normal file
135
test-cli/create-steal-tx.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/* My example:
|
||||
* ./check-commit-sig A-open.pb B-open.pb A-commit-sig.pb B-commit-sig.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC A-leak-anchor-sigs.pb B-leak-anchor-sigs.pb > A-commit.tx
|
||||
* ./check-commit-sig B-open.pb A-open.pb B-commit-sig.pb A-commit-sig.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC B-leak-anchor-sigs.pb A-leak-anchor-sigs.pb > B-commit.tx
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct sha256 revoke_preimage, revoke_hash;
|
||||
OpenChannel *o1, *o2;
|
||||
Pkt *pkt;
|
||||
struct bitcoin_tx *commit, *tx;
|
||||
u8 *tx_arr, *redeemscript, *p2sh;
|
||||
size_t i;
|
||||
struct pubkey pubkey1, pubkey2, outpubkey;
|
||||
struct bitcoin_signature sig;
|
||||
char *tx_hex;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<commit-tx> <revocation-preimage> <final-privkey> <open-channel-file1> <open-channel-file2> <outpubkey>\n"
|
||||
"Create a transaction which spends commit-tx's revocable output, and sends it P2SH to outpubkey",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 7)
|
||||
opt_usage_exit_fail("Expected 6 arguments");
|
||||
|
||||
commit = bitcoin_tx_from_file(ctx, argv[1]);
|
||||
|
||||
pkt = any_pkt_from_file(argv[2]);
|
||||
switch (pkt->pkt_case) {
|
||||
case PKT__PKT_UPDATE_SIGNATURE:
|
||||
proto_to_sha256(pkt->update_signature->revocation_preimage,
|
||||
&revoke_preimage);
|
||||
break;
|
||||
case PKT__PKT_UPDATE_COMPLETE:
|
||||
proto_to_sha256(pkt->update_complete->revocation_preimage,
|
||||
&revoke_preimage);
|
||||
break;
|
||||
default:
|
||||
errx(1, "Expected update or update-complete in %s", argv[2]);
|
||||
}
|
||||
|
||||
privkey = key_from_base58(argv[3], strlen(argv[3]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[3]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[3]);
|
||||
|
||||
o1 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[5], PKT__PKT_OPEN)->open;
|
||||
|
||||
if (!pubkey_from_hexstr(argv[6], &outpubkey))
|
||||
errx(1, "Invalid bitcoin pubkey '%s'", argv[6]);
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->final, &pubkey2))
|
||||
errx(1, "Invalid o1 final 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->final, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* Now, which commit output? Match redeem script. */
|
||||
sha256(&revoke_hash, &revoke_preimage, sizeof(revoke_preimage));
|
||||
redeemscript = bitcoin_redeem_revocable(ctx, &pubkey2,
|
||||
o2->locktime_seconds,
|
||||
&pubkey1, &revoke_hash);
|
||||
p2sh = scriptpubkey_p2sh(ctx, redeemscript);
|
||||
|
||||
for (i = 0; i < commit->output_count; i++) {
|
||||
if (commit->output[i].script_length != tal_count(p2sh))
|
||||
continue;
|
||||
if (memcmp(commit->output[i].script, p2sh, tal_count(p2sh)) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == commit->output_count)
|
||||
errx(1, "No matching output in %s", argv[1]);
|
||||
|
||||
tx = bitcoin_tx(ctx, 1, 1);
|
||||
bitcoin_txid(commit, &tx->input[0].txid);
|
||||
tx->input[0].index = i;
|
||||
|
||||
tx->output[0].amount = commit->output[i].amount;
|
||||
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_revoke(tx, &revoke_preimage, &sig,
|
||||
redeemscript,
|
||||
tal_count(redeemscript));
|
||||
tx->input[0].script_length = tal_count(tx->input[0].script);
|
||||
|
||||
/* Print it out in hex. */
|
||||
tx_arr = linearize_tx(ctx, commit);
|
||||
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
|
||||
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
|
||||
|
||||
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
|
||||
err(1, "Writing out transaction");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
47
test-cli/get-anchor-depth.c
Normal file
47
test-cli/get-anchor-depth.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/* My example:
|
||||
* while [ 0$(bitcoin-cli -testnet getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(./get-anchor-depth A-open.pb) ]; do sleep 60; done
|
||||
* while [ 0$(bitcoin-cli -testnet getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(./get-anchor-depth B-open.pb) ]; do sleep 60; done
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-channel-file>\n"
|
||||
"Prints anchor depth as contained in OpenChannel message",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 2)
|
||||
opt_usage_exit_fail("Expected one argument");
|
||||
|
||||
o = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
|
||||
printf("%u\n", o->anchor->min_confirms);
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
38
test-cli/leak-anchor-sigs.c
Normal file
38
test-cli/leak-anchor-sigs.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Insecure hack to leak signatures early, to make up for non-normalized txs */
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "pkt.h"
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenAnchorScriptsigs *s;
|
||||
struct pkt *pkt;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-anchor-sig-file>\n"
|
||||
"Create LeakAnchorSigsAndPretendWeDidnt to stdout",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 2)
|
||||
opt_usage_exit_fail("Expected 1 argument");
|
||||
|
||||
s = pkt_from_file(argv[1], PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS)
|
||||
->open_anchor_scriptsigs;
|
||||
|
||||
pkt = leak_anchor_sigs_and_pretend_we_didnt_pkt(ctx, s);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
104
test-cli/open-anchor-scriptsigs.c
Normal file
104
test-cli/open-anchor-scriptsigs.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/* My example:
|
||||
* ./open-anchor-scriptsigs A-open.pb B-open.pb cUjoranStkpgTRumAJZNiNEkknJv5UA7wzW1nZ7aPsm9ZWjkxypZ > A-anchor-scriptsigs.pb
|
||||
* ./open-anchor-scriptsigs B-open.pb A-open.pb cNggXygY8fPHWHEdoDqRa6xALau8gVMLq6q6vzMs2eNegLrJGNAW > B-anchor-scriptsigs.pb
|
||||
*/
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "bitcoin/tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "lightning.pb-c.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "bitcoin/address.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* All the input scripts are already set to 0. We just need to make this one. */
|
||||
static u8 *tx_scriptsig(const tal_t *ctx,
|
||||
struct bitcoin_tx *tx,
|
||||
unsigned int i,
|
||||
const BitcoinInput *input,
|
||||
EC_KEY *privkey,
|
||||
const struct pubkey *pubkey)
|
||||
{
|
||||
struct bitcoin_signature sig;
|
||||
|
||||
sig.stype = SIGHASH_ALL;
|
||||
if (!sign_tx_input(ctx, tx, i,
|
||||
input->subscript.data, input->subscript.len,
|
||||
privkey, pubkey, &sig.sig))
|
||||
return NULL;
|
||||
|
||||
if (!is_pay_to_pubkey_hash(input->subscript.data, input->subscript.len))
|
||||
errx(1, "FIXME: Don't know how to handle input");
|
||||
return scriptsig_pay_to_pubkeyhash(ctx, pubkey, &sig);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
OpenChannel *o1, *o2;
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct bitcoin_tx *anchor;
|
||||
struct pkt *pkt;
|
||||
size_t i;
|
||||
u8 **sigs;
|
||||
size_t *map;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-channel-file1> <open-channel-file2> <privkey>...\n"
|
||||
"Create signatures for transactions, and output to stdout",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 3)
|
||||
opt_usage_exit_fail("Expected 2 or more arguments");
|
||||
|
||||
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
|
||||
|
||||
/* FIXME: We should check that their locktime is sane here,
|
||||
* since we're bound to it. Also min_confirms, etc. */
|
||||
|
||||
/* Create merged transaction */
|
||||
anchor = anchor_tx_create(ctx, o1, o2, &map, NULL);
|
||||
if (!anchor)
|
||||
errx(1, "Failed transaction merge");
|
||||
|
||||
/* Sign our inputs. */
|
||||
if (o1->anchor->n_inputs != argc - 3)
|
||||
errx(1, "Expected %zu private keys", o1->anchor->n_inputs);
|
||||
|
||||
sigs = tal_arr(ctx, u8 *, o1->anchor->n_inputs);
|
||||
for (i = 0; i < o1->anchor->n_inputs; i++) {
|
||||
struct pubkey pubkey;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
|
||||
privkey = key_from_base58(argv[3+i], strlen(argv[3+i]),
|
||||
&testnet, &pubkey);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[3+i]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[3+i]);
|
||||
|
||||
sigs[i] = tx_scriptsig(sigs, anchor, map[i],
|
||||
o1->anchor->inputs[i],
|
||||
privkey, &pubkey);
|
||||
}
|
||||
|
||||
pkt = open_anchor_sig_pkt(ctx, sigs, o1->anchor->n_inputs);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
183
test-cli/open-channel.c
Normal file
183
test-cli/open-channel.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/* My example:
|
||||
* ./open-channel 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff 50000000000 030da36b810c0930e5fe8b74014665873f6901d9f46018a5fda743a93dec7f0e4e cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC cTuY5gncxDymqe9dfF7R8QFdAsxMZxdViRMjs8Dj7xJJRsQcmPCt 08ffaf638849198f9c8f04aa75d225a5a104d5e7c540770ca55ad08b9a32d10c/1/100000000000/76a9148d2d939aa2aff2d341cde3e61a89bf9c2c21d12388ac > A-open.pb
|
||||
* ./open-channel 112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00 9795000 022e314a8f7a814e0900bf094f704b233dc693349cf55b888b43d902d7be251e95 cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi 8cb044605f33ca907b966701f49e0bd80b4294696b57f8cf45f22398a1e63a23/0/9800000/76a9143b2aab840afb327a12c8a90fb4ed45b6892eb80988ac > B-open.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "bitcoin/address.h"
|
||||
#include "bitcoin/tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "bitcoin/shadouble.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
#include "opt_bits.h"
|
||||
|
||||
/* Bitcoin nodes are allowed to be 2 hours in the future. */
|
||||
#define LOCKTIME_MIN (2 * 60 * 60)
|
||||
|
||||
static BitcoinInput *parse_anchor_input(const tal_t *ctx, const char *spec)
|
||||
{
|
||||
BitcoinInput *in = tal(ctx, BitcoinInput);
|
||||
struct sha256_double txid;
|
||||
const char *slash;
|
||||
char *end;
|
||||
long l;
|
||||
|
||||
bitcoin_input__init(in);
|
||||
|
||||
slash = strchr(spec, '/');
|
||||
if (!slash)
|
||||
errx(1, "Expected / in <txid>/<num>/<satoshis>/<hexscript>");
|
||||
|
||||
if (!bitcoin_txid_from_hex(spec, slash - spec, &txid))
|
||||
errx(1, "Expected 256-bit hex txid before /");
|
||||
in->txid = sha256_to_proto(in, &txid.sha);
|
||||
|
||||
in->output = l = strtol(slash + 1, &end, 10);
|
||||
if (end == slash + 1 || *end != '/' || (int64_t)in->output != (int64_t)l)
|
||||
errx(1, "Expected <outputnum> after /");
|
||||
|
||||
slash = end;
|
||||
in->amount = l = strtol(slash + 1, &end, 10);
|
||||
if (end == slash + 1 || *end != '/' || (int64_t)in->amount != (int64_t)l)
|
||||
errx(1, "Expected <satoshis> after second /");
|
||||
|
||||
slash = end;
|
||||
in->subscript.len = strlen(slash + 1) / 2;
|
||||
in->subscript.data = tal_arr(in, u8, in->subscript.len);
|
||||
if (!hex_decode(slash + 1, strlen(slash + 1),
|
||||
in->subscript.data, in->subscript.len))
|
||||
errx(1, "Expected hex string after third /");
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
/* FIXME: This is too weak, even for us! */
|
||||
static u64 weak_random64(void)
|
||||
{
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
/* Simple helper to open a channel. */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sha256 seed, revocation_hash;
|
||||
struct pkt *pkt;
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
Anchor anchor = ANCHOR__INIT;
|
||||
u64 commit_tx_fee, total_in;
|
||||
unsigned int locktime_seconds;
|
||||
bool testnet;
|
||||
size_t i;
|
||||
struct pubkey commitkey, outkey, changekey;
|
||||
EC_KEY *commitprivkey, *outprivkey;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
/* Default values. */
|
||||
anchor.min_confirms = 3;
|
||||
/* Remember, other side contributes to fee, too. */
|
||||
anchor.fee = 5000;
|
||||
/* We only need this for involuntary close, so make it larger. */
|
||||
commit_tx_fee = 100000;
|
||||
/* This means we have ~1 day before they can steal our money. */
|
||||
locktime_seconds = LOCKTIME_MIN + 24 * 60 * 60;
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<seed> <amount> <changepubkey> <commitprivkey> <outprivkey> <txid>/<outnum>/<satoshis>/<script-in-hex>...\n"
|
||||
"A test program to output openchannel on stdout.",
|
||||
"Print this message.");
|
||||
opt_register_arg("--min-anchor-confirms",
|
||||
opt_set_uintval, opt_show_uintval, &anchor.min_confirms,
|
||||
"Number of anchor confirmations before channel is active");
|
||||
opt_register_arg("--anchor-fee=<bits>",
|
||||
opt_set_bits, opt_show_bits, &anchor.fee,
|
||||
"100's of satoshi to pay for anchor");
|
||||
opt_register_arg("--commitment-fee=<bits>",
|
||||
opt_set_bits, opt_show_bits, &commit_tx_fee,
|
||||
"100's of satoshi to pay for commitment");
|
||||
opt_register_arg("--locktime=<seconds>",
|
||||
opt_set_uintval, opt_show_uintval, &locktime_seconds,
|
||||
"Seconds to lock out our transaction redemption");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 7)
|
||||
opt_usage_exit_fail("Expected 6 or more arguments");
|
||||
|
||||
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
|
||||
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
|
||||
|
||||
anchor.total = atol(argv[2]);
|
||||
if (!anchor.total)
|
||||
errx(1, "Invalid total: must be > 0");
|
||||
|
||||
if (!pubkey_from_hexstr(argv[3], &changekey))
|
||||
errx(1, "Invalid bitcoin pubkey '%s'", argv[3]);
|
||||
|
||||
/* We don't really need the privkey here, but it's the most
|
||||
* convenient way to get the pubkey from bitcoind. */
|
||||
commitprivkey = key_from_base58(argv[4], strlen(argv[4]), &testnet,
|
||||
&commitkey);
|
||||
if (!commitprivkey)
|
||||
errx(1, "Invalid private key '%s'", argv[4]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[4]);
|
||||
|
||||
outprivkey = key_from_base58(argv[5], strlen(argv[5]), &testnet,
|
||||
&outkey);
|
||||
if (!outprivkey)
|
||||
errx(1, "Invalid private key '%s'", argv[5]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[5]);
|
||||
|
||||
anchor.n_inputs = (argc - 6);
|
||||
anchor.inputs = tal_arr(ctx, BitcoinInput *, anchor.n_inputs);
|
||||
anchor.pubkey = pubkey_to_proto(ctx, &commitkey);
|
||||
|
||||
total_in = 0;
|
||||
for (i = 0; i < anchor.n_inputs; i++) {
|
||||
anchor.inputs[i] = parse_anchor_input(anchor.inputs, argv[i+6]);
|
||||
total_in += anchor.inputs[i]->amount;
|
||||
}
|
||||
|
||||
if (total_in < anchor.total + anchor.fee)
|
||||
errx(1, "Only %llu satoshi in, and %llu out (+%llu fee)",
|
||||
(unsigned long long)total_in,
|
||||
(unsigned long long)anchor.total,
|
||||
(unsigned long long)anchor.fee);
|
||||
|
||||
/* If there's change, say where to send it. */
|
||||
if (total_in != anchor.total + anchor.fee) {
|
||||
anchor.change = tal(ctx, Change);
|
||||
change__init(anchor.change);
|
||||
anchor.change->pubkey = pubkey_to_proto(anchor.change,
|
||||
&changekey);
|
||||
anchor.change->amount = total_in - (anchor.total + anchor.fee);
|
||||
}
|
||||
|
||||
/* Get first revocation hash. */
|
||||
shachain_from_seed(&seed, 0, &revocation_hash);
|
||||
sha256(&revocation_hash,
|
||||
revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
|
||||
|
||||
pkt = openchannel_pkt(ctx, weak_random64(), &revocation_hash, &outkey,
|
||||
commit_tx_fee, locktime_seconds, &anchor);
|
||||
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
98
test-cli/open-commit-sig.c
Normal file
98
test-cli/open-commit-sig.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/* My example:
|
||||
* ./open-commit-sig A-open.pb B-open.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC A-leak-anchor-sigs.pb B-leak-anchor-sigs.pb > A-commit-sig.pb
|
||||
* ./open-commit-sig B-open.pb A-open.pb cQXhbUnNRsFcdzTQwjbCrud5yVskHTEas7tZPUWoJYNk5htGQrpi B-leak-anchor-sigs.pb A-leak-anchor-sigs.pb > B-commit-sig.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
OpenChannel *o1, *o2;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct sha256_double txid;
|
||||
struct pkt *pkt;
|
||||
struct signature sig;
|
||||
size_t *inmap, *outmap;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *subscript;
|
||||
struct sha256 rhash;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<open-channel-file1> <open-channel-file2> <commit-privkey> <leak-anchor-sigs1> <leak-anchor-sigs2>\n"
|
||||
"Create the signature needed for the commit transaction",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 6)
|
||||
opt_usage_exit_fail("Expected 5 arguments");
|
||||
|
||||
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
|
||||
|
||||
privkey = key_from_base58(argv[3], strlen(argv[3]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[3]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[3]);
|
||||
|
||||
/* Create merged anchor transaction */
|
||||
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap);
|
||||
if (!anchor)
|
||||
errx(1, "Failed transaction merge");
|
||||
|
||||
/* Get the transaction ID of the anchor. */
|
||||
anchor_txid(anchor, argv[4], argv[5], inmap, &txid);
|
||||
|
||||
/* Now create THEIR commitment tx to spend 2/2 output of anchor. */
|
||||
proto_to_sha256(o2->revocation_hash, &rhash);
|
||||
commit = create_commit_tx(ctx, o2, o1, &rhash, 0, &txid, outmap[0]);
|
||||
|
||||
/* If contributions don't exceed fees, this fails. */
|
||||
if (!commit)
|
||||
errx(1, "Contributions %llu & %llu vs fees %llu & %llu",
|
||||
(long long)o1->anchor->total,
|
||||
(long long)o2->anchor->total,
|
||||
(long long)o1->commitment_fee,
|
||||
(long long)o2->commitment_fee);
|
||||
|
||||
/* Their pubkey must be valid */
|
||||
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid public open-channel-file2");
|
||||
|
||||
/* Sign it for them. */
|
||||
subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript),
|
||||
privkey, &pubkey1, &sig);
|
||||
|
||||
pkt = open_commit_sig_pkt(ctx, &sig);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
116
test-cli/update-channel-accept.c
Normal file
116
test-cli/update-channel-accept.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/* My example:
|
||||
* ./update-channel-accept <B-SEED> B-open.pb A-open.pb anchor.tx <B-TMPKEY> A-update-1.pb > B-update-accept-1.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct sha256 seed, revocation_hash, their_rhash;
|
||||
OpenChannel *o1, *o2;
|
||||
Update *update;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct sha256_double anchor_txid;
|
||||
struct pkt *pkt;
|
||||
struct bitcoin_signature sig;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *redeemscript;
|
||||
int64_t delta;
|
||||
size_t i, p2sh_out;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <commit-privkey> <update-protobuf> [previous-updates]\n"
|
||||
"Accept a new update message",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 6)
|
||||
opt_usage_exit_fail("Expected 5+ arguments");
|
||||
|
||||
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
|
||||
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
|
||||
|
||||
anchor = bitcoin_tx_from_file(ctx, argv[2]);
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open;
|
||||
|
||||
privkey = key_from_base58(argv[5], strlen(argv[5]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[5]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[5]);
|
||||
|
||||
update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update;
|
||||
|
||||
/* Figure out cumulative delta since anchor. */
|
||||
delta = update->delta;
|
||||
for (i = 7; i < argc; i++) {
|
||||
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
|
||||
delta += u->delta;
|
||||
}
|
||||
|
||||
/* Get next revocation hash. */
|
||||
shachain_from_seed(&seed, argc - 6, &revocation_hash);
|
||||
sha256(&revocation_hash,
|
||||
revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &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->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* This is what the anchor pays to; figure out whick output. */
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
p2sh_out = find_p2sh_out(anchor, redeemscript);
|
||||
|
||||
/* Now create THEIR new commitment tx to spend 2/2 output of anchor. */
|
||||
proto_to_sha256(update->revocation_hash, &their_rhash);
|
||||
commit = create_commit_tx(ctx, o2, o1, &their_rhash, delta,
|
||||
&anchor_txid, p2sh_out);
|
||||
|
||||
/* If contributions don't exceed fees, this fails. */
|
||||
if (!commit)
|
||||
errx(1, "Delta too large");
|
||||
|
||||
/* Sign it for them. */
|
||||
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript),
|
||||
privkey, &pubkey1, &sig.sig);
|
||||
|
||||
pkt = update_accept_pkt(ctx, &sig.sig, &revocation_hash);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
131
test-cli/update-channel-complete.c
Normal file
131
test-cli/update-channel-complete.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/* My example:
|
||||
* ./update-channel-complete <A-SEED> B-open.pb > A-update-complete-1.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct sha256 seed, revocation_hash, our_rhash, their_rhash, preimage;
|
||||
OpenChannel *o1, *o2;
|
||||
UpdateSignature *us;
|
||||
Update *update;
|
||||
struct pkt *pkt;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
size_t i, num_updates, p2sh_out;
|
||||
struct sha256_double anchor_txid;
|
||||
struct bitcoin_signature sig;
|
||||
int64_t delta;
|
||||
u8 *redeemscript;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <update-protobuf> <update-signature-protobuf> [previous-updates]\n"
|
||||
"Create a new update-complete message",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 7)
|
||||
opt_usage_exit_fail("Expected 6+ arguments");
|
||||
|
||||
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
|
||||
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
|
||||
|
||||
anchor = bitcoin_tx_from_file(ctx, argv[2]);
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open;
|
||||
update = pkt_from_file(argv[5], PKT__PKT_UPDATE)->update;
|
||||
us = pkt_from_file(argv[6], PKT__PKT_UPDATE_SIGNATURE)->update_signature;
|
||||
|
||||
/* We need last revocation hash (either in update or update-accept),
|
||||
* and the delta */
|
||||
proto_to_sha256(o2->revocation_hash, &revocation_hash);
|
||||
num_updates = 0;
|
||||
delta = update->delta;
|
||||
for (i = 7; i < argc; i++) {
|
||||
Pkt *p = any_pkt_from_file(argv[i]);
|
||||
switch (p->pkt_case) {
|
||||
case PKT__PKT_UPDATE:
|
||||
proto_to_sha256(p->update->revocation_hash,
|
||||
&revocation_hash);
|
||||
delta += p->update->delta;
|
||||
num_updates++;
|
||||
break;
|
||||
case PKT__PKT_UPDATE_ACCEPT:
|
||||
if (i != argc - 1)
|
||||
errx(1, "Only need last update_accept");
|
||||
proto_to_sha256(p->update_accept->revocation_hash,
|
||||
&revocation_hash);
|
||||
break;
|
||||
default:
|
||||
errx(1, "Expected update/update-accept in %s", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* They gave us right preimage to match rhash of previous commit tx? */
|
||||
proto_to_sha256(us->revocation_preimage, &preimage);
|
||||
sha256(&their_rhash, preimage.u.u8, sizeof(preimage.u.u8));
|
||||
if (!structeq(&their_rhash, &revocation_hash))
|
||||
errx(1, "Their preimage was incorrect");
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1))
|
||||
errx(1, "Invalid o1 commit pubkey");
|
||||
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* This is what the anchor pays to; figure out whick output. */
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
p2sh_out = find_p2sh_out(anchor, redeemscript);
|
||||
|
||||
/* Check their signature signs our new commit tx correctly. */
|
||||
shachain_from_seed(&seed, num_updates + 1, &preimage);
|
||||
sha256(&our_rhash, &preimage, sizeof(preimage));
|
||||
commit = create_commit_tx(ctx, o1, o2, &our_rhash, delta,
|
||||
&anchor_txid, p2sh_out);
|
||||
if (!commit)
|
||||
errx(1, "Delta too large");
|
||||
|
||||
sig.stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(us->sig, &sig.sig))
|
||||
errx(1, "Invalid update-signature signature");
|
||||
|
||||
if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript),
|
||||
&pubkey2, &sig))
|
||||
errx(1, "Invalid signature.");
|
||||
|
||||
/* Hand over our preimage for previous tx. */
|
||||
shachain_from_seed(&seed, num_updates, &preimage);
|
||||
pkt = update_complete_pkt(ctx, &preimage);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
134
test-cli/update-channel-signature.c
Normal file
134
test-cli/update-channel-signature.c
Normal file
@@ -0,0 +1,134 @@
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include "protobuf_convert.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct sha256 seed, revocation_hash, preimage;
|
||||
OpenChannel *o1, *o2;
|
||||
UpdateAccept *ua;
|
||||
Update *update;
|
||||
struct bitcoin_tx *anchor, *commit;
|
||||
struct sha256_double anchor_txid;
|
||||
struct pkt *pkt;
|
||||
struct bitcoin_signature sig;
|
||||
EC_KEY *privkey;
|
||||
bool testnet;
|
||||
struct pubkey pubkey1, pubkey2;
|
||||
u8 *redeemscript;
|
||||
int64_t delta;
|
||||
size_t i, p2sh_out;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<seed> <anchor-tx> <open-channel-file1> <open-channel-file2> <commit-privkey> <update-protobuf> <update-accept-protobuf> [previous-updates]...\n"
|
||||
"Create a new update-channel-signature message",
|
||||
"Print this message.");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc < 8)
|
||||
opt_usage_exit_fail("Expected 7+ arguments");
|
||||
|
||||
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
|
||||
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
|
||||
|
||||
anchor = bitcoin_tx_from_file(ctx, argv[2]);
|
||||
bitcoin_txid(anchor, &anchor_txid);
|
||||
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
|
||||
o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open;
|
||||
|
||||
privkey = key_from_base58(argv[5], strlen(argv[5]), &testnet, &pubkey1);
|
||||
if (!privkey)
|
||||
errx(1, "Invalid private key '%s'", argv[5]);
|
||||
if (!testnet)
|
||||
errx(1, "Private key '%s' not on testnet!", argv[5]);
|
||||
|
||||
update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update;
|
||||
ua = pkt_from_file(argv[7], PKT__PKT_UPDATE_ACCEPT)->update_accept;
|
||||
|
||||
sig.stype = SIGHASH_ALL;
|
||||
if (!proto_to_signature(ua->sig, &sig.sig))
|
||||
errx(1, "Invalid update signature");
|
||||
|
||||
/* Figure out cumulative delta since anchor. */
|
||||
delta = 0;
|
||||
for (i = 8; i < argc; i++) {
|
||||
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
|
||||
delta += u->delta;
|
||||
}
|
||||
|
||||
/* Give up revocation preimage for old tx. */
|
||||
shachain_from_seed(&seed, argc - 7 - 1, &preimage);
|
||||
|
||||
/* Get pubkeys */
|
||||
if (!proto_to_pubkey(o1->anchor->pubkey, &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->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid o2 final pubkey");
|
||||
|
||||
/* This is what the anchor pays to; figure out whick output. */
|
||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
||||
p2sh_out = find_p2sh_out(anchor, redeemscript);
|
||||
|
||||
/* Check our new commit is signed correctly by them. */
|
||||
proto_to_sha256(update->revocation_hash, &revocation_hash);
|
||||
commit = create_commit_tx(ctx, o1, o2, &revocation_hash, delta,
|
||||
&anchor_txid, p2sh_out);
|
||||
if (!commit)
|
||||
errx(1, "Delta too large");
|
||||
|
||||
/* Check their signature signs this input correctly. */
|
||||
if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript),
|
||||
&pubkey2, &sig))
|
||||
errx(1, "Invalid signature.");
|
||||
|
||||
/* Now create THEIR new commitment tx to spend 2/2 output of anchor. */
|
||||
proto_to_sha256(ua->revocation_hash, &revocation_hash);
|
||||
commit = create_commit_tx(ctx, o2, o1, &revocation_hash, -delta,
|
||||
&anchor_txid,
|
||||
find_p2sh_out(anchor, redeemscript));
|
||||
|
||||
/* If contributions don't exceed fees, this fails. */
|
||||
if (!commit)
|
||||
errx(1, "Delta too large");
|
||||
|
||||
/* Their pubkey must be valid */
|
||||
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
|
||||
errx(1, "Invalid public open-channel-file2");
|
||||
|
||||
/* Sign it for them. */
|
||||
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript),
|
||||
privkey, &pubkey1, &sig.sig);
|
||||
|
||||
pkt = update_signature_pkt(ctx, &sig.sig, &preimage);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
73
test-cli/update-channel.c
Normal file
73
test-cli/update-channel.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* My example:
|
||||
* ./update-channel <A-SEED> <my-delta-in-satoshis> A-open.pb B-open.pb anchor.tx <A-TMPKEY> > A-update-1.pb
|
||||
*/
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include "lightning.pb-c.h"
|
||||
#include "anchor.h"
|
||||
#include "bitcoin/base58.h"
|
||||
#include "pkt.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "permute_tx.h"
|
||||
#include "bitcoin/signature.h"
|
||||
#include "commit_tx.h"
|
||||
#include "bitcoin/pubkey.h"
|
||||
#include "find_p2sh_out.h"
|
||||
#include <openssl/ec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal_arr(NULL, char, 0);
|
||||
struct sha256 seed, revocation_hash;
|
||||
struct pkt *pkt;
|
||||
unsigned long long to_them = 0, from_them = 0;
|
||||
int64_t this_delta;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<seed> [previous-updates]\n"
|
||||
"Create a new update message",
|
||||
"Print this message.");
|
||||
opt_register_arg("--to-them=<satoshi>",
|
||||
opt_set_ulonglongval_si, NULL, &to_them,
|
||||
"Amount to pay them (must use this or --from-them)");
|
||||
opt_register_arg("--from-them=<satoshi>",
|
||||
opt_set_ulonglongval_si, NULL, &from_them,
|
||||
"Amount to pay us (must use this or --to-them)");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (!from_them && !to_them)
|
||||
opt_usage_exit_fail("Must use --to-them or --from-them");
|
||||
|
||||
if (argc < 2)
|
||||
opt_usage_exit_fail("Expected 1+ arguments");
|
||||
|
||||
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
|
||||
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
|
||||
|
||||
this_delta = from_them - to_them;
|
||||
if (!this_delta)
|
||||
errx(1, "Delta must not be zero");
|
||||
|
||||
/* Get next revocation hash. */
|
||||
shachain_from_seed(&seed, argc - 2 + 1, &revocation_hash);
|
||||
sha256(&revocation_hash,
|
||||
revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
|
||||
|
||||
pkt = update_pkt(ctx, &revocation_hash, this_delta);
|
||||
if (!write_all(STDOUT_FILENO, pkt,
|
||||
sizeof(pkt->len) + le32_to_cpu(pkt->len)))
|
||||
err(1, "Writing out packet");
|
||||
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user