From 38f7a23064a2a1468bc75416d7589bee4012feda Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 8 Jun 2015 14:44:47 +0930 Subject: [PATCH] close-channel: create message to mutually close channel. Signed-off-by: Rusty Russell --- Makefile | 4 +- close-channel.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++ close_tx.c | 49 +++++++++++++++++++++++ close_tx.h | 15 +++++++ lightning.pb-c.h | 2 +- lightning.proto | 2 +- pkt.c | 7 ++++ pkt.h | 7 ++++ 8 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 close-channel.c create mode 100644 close_tx.c create mode 100644 close_tx.h diff --git a/Makefile b/Makefile index 628cb40d1..bb9502a19 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ # Needs to have oneof support: Ubuntu vivid's is too old :( PROTOCC:=protoc-c -PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig check-anchor-scriptsigs get-anchor-depth create-steal-tx create-commit-spend-tx +PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig check-anchor-scriptsigs get-anchor-depth create-steal-tx create-commit-spend-tx close-channel -HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o bitcoin_script.o permute_tx.o signature.o bitcoin_tx.o bitcoin_address.o anchor.o commit_tx.o pubkey.o opt_bits.o +HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o bitcoin_script.o permute_tx.o signature.o bitcoin_tx.o bitcoin_address.o anchor.o commit_tx.o pubkey.o opt_bits.o close_tx.o CCAN_OBJS := ccan-crypto-sha256.o ccan-crypto-shachain.o ccan-err.o ccan-tal.o ccan-tal-str.o ccan-take.o ccan-list.o ccan-str.o ccan-opt-helpers.o ccan-opt.o ccan-opt-parse.o ccan-opt-usage.o ccan-read_write_all.o ccan-str-hex.o ccan-tal-grab_file.o ccan-noerr.o diff --git a/close-channel.c b/close-channel.c new file mode 100644 index 000000000..de488f7a8 --- /dev/null +++ b/close-channel.c @@ -0,0 +1,101 @@ +/* My example: + * ./close-channel A-anchor.tx A-open.pb B-open.pb cUBCjrdJu8tfvM7FT8So6aqs6G6bZS1Cax6Rc9rFzYL6nYG4XNEC > A-close.pb + */ +#include +#include +#include +#include +#include +#include +#include +#include "lightning.pb-c.h" +#include "anchor.h" +#include "base58.h" +#include "pkt.h" +#include "bitcoin_script.h" +#include "permute_tx.h" +#include "signature.h" +#include "pubkey.h" +#include "close_tx.h" +#include +#include + +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; + struct pubkey pubkey1, pubkey2; + u8 *redeemscript, *p2sh; + size_t i; + + err_set_progname(argv[0]); + + /* FIXME: Take update.pbs to adjust channel */ + opt_register_noarg("--help|-h", opt_usage_and_exit, + " \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 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); + + /* This is the scriptPubKey commit tx will have */ + p2sh = scriptpubkey_p2sh(ctx, redeemscript); + + for (i = 0; i < anchor->output_count; i++) { + if (anchor->output[i].script_length != tal_count(p2sh)) + continue; + if (memcmp(anchor->output[i].script, p2sh, tal_count(p2sh)) == 0) + break; + } + if (i == anchor->output_count) + errx(1, "No matching output in %s", argv[1]); + + /* Now create the close tx to spend 2/2 output of anchor. */ + close_tx = create_close_tx(ctx, o1, o2, &anchor_txid, i); + + /* Sign it for them. */ + sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript), + privkey, &sig); + + 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; +} + diff --git a/close_tx.c b/close_tx.c new file mode 100644 index 000000000..f1988709a --- /dev/null +++ b/close_tx.c @@ -0,0 +1,49 @@ +#include "close_tx.h" +#include "shadouble.h" +#include "bitcoin_tx.h" +#include "bitcoin_script.h" +#include "permute_tx.h" +#include "pubkey.h" +#include "pkt.h" + +struct bitcoin_tx *create_close_tx(const tal_t *ctx, + OpenChannel *ours, + OpenChannel *theirs, + const struct sha256_double *anchor_txid, + unsigned int anchor_output) +{ + struct bitcoin_tx *tx; + const u8 *redeemscript; + struct pubkey ourkey, theirkey; + struct sha256 redeem; + + /* Now create close tx: one input, two outputs. */ + tx = bitcoin_tx(ctx, 1, 2); + + /* Our input spends the anchor tx output. */ + tx->input[0].txid = *anchor_txid; + tx->input[0].index = anchor_output; + + /* Outputs goes to final pubkey */ + if (!proto_to_pubkey(ours->final, &ourkey)) + return tal_free(tx); + if (!proto_to_pubkey(theirs->final, &theirkey)) + return tal_free(tx); + + proto_to_sha256(ours->revocation_hash, &redeem); + + /* One output is to us. */ + tx->output[0].amount = ours->anchor->total - ours->commitment_fee; + redeemscript = bitcoin_redeem_single(tx, &ourkey); + tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); + tx->output[0].script_length = tal_count(tx->output[0].script); + + /* Other output is to them. */ + tx->output[1].amount = theirs->anchor->total - theirs->commitment_fee; + redeemscript = bitcoin_redeem_single(tx, &theirkey); + tx->output[1].script = scriptpubkey_p2sh(tx, redeemscript); + tx->output[1].script_length = tal_count(tx->output[1].script); + + permute_outputs(ours->seed, theirs->seed, 1, tx->output, 2, NULL); + return tx; +} diff --git a/close_tx.h b/close_tx.h new file mode 100644 index 000000000..f104ed0ea --- /dev/null +++ b/close_tx.h @@ -0,0 +1,15 @@ +#ifndef LIGHTNING_CLOSE_TX_H +#define LIGHTNING_CLOSE_TX_H +#include +#include "lightning.pb-c.h" + +struct sha256_double; + +/* Create close tx to spend the anchor tx output; doesn't fill in + * input scriptsig. */ +struct bitcoin_tx *create_close_tx(const tal_t *ctx, + OpenChannel *ours, + OpenChannel *theirs, + const struct sha256_double *anchor_txid, + unsigned int anchor_output); +#endif diff --git a/lightning.pb-c.h b/lightning.pb-c.h index 6f2ff5d63..ff978e5fe 100644 --- a/lightning.pb-c.h +++ b/lightning.pb-c.h @@ -431,7 +431,7 @@ struct _CloseChannel ProtobufCMessage base; /* * This is our signature a new transaction which spends the anchor - * output to my open->script_to_me and your open->script_to_me, + * output to my open->final and your open->final, * as per the last commit tx. */ Signature *sig; diff --git a/lightning.proto b/lightning.proto index d4d9ad6c3..a9cd7e36a 100644 --- a/lightning.proto +++ b/lightning.proto @@ -176,7 +176,7 @@ message new_anchor_complete { // Begin cooperative close of channel. message close_channel { // This is our signature a new transaction which spends the anchor - // output to my open->script_to_me and your open->script_to_me, + // output to my open->final and your open->final, // as per the last commit tx. required signature sig = 1; } diff --git a/pkt.c b/pkt.c index 1955f4fa9..3d5af43f9 100644 --- a/pkt.c +++ b/pkt.c @@ -137,3 +137,10 @@ struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sig) o.sig = signature_to_proto(ctx, sig); return to_pkt(ctx, PKT__PKT_OPEN_COMMIT_SIG, &o); } + +struct pkt *close_channel_pkt(const tal_t *ctx, const struct signature *sig) +{ + CloseChannel c = CLOSE_CHANNEL__INIT; + c.sig = signature_to_proto(ctx, sig); + return to_pkt(ctx, PKT__PKT_CLOSE, &c); +} diff --git a/pkt.h b/pkt.h index 7bf91b31d..726fa82ea 100644 --- a/pkt.h +++ b/pkt.h @@ -66,6 +66,13 @@ struct pkt *leak_anchor_sigs_and_pretend_we_didnt_pkt(const tal_t *ctx, */ struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sig); +/** + * close_channel_pkt - create an close_channel message + * @ctx: tal context to allocate off. + * @sig: the signature for the close transaction input. + */ +struct pkt *close_channel_pkt(const tal_t *ctx, const struct signature *sig); + /* Useful helper for allocating & populating a protobuf Sha256Hash */ Sha256Hash *sha256_to_proto(const tal_t *ctx, const struct sha256 *hash); void proto_to_sha256(const Sha256Hash *pb, struct sha256 *hash);