diff --git a/Makefile b/Makefile index 007959223..3369854c0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # 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 close-channel create-close-tx update-channel update-channel-accept +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 create-close-tx update-channel update-channel-accept update-channel-complete 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 find_p2sh_out.o diff --git a/pkt.c b/pkt.c index ac6f35314..c0a2b2fcb 100644 --- a/pkt.c +++ b/pkt.c @@ -80,7 +80,7 @@ struct pkt *openchannel_pkt(const tal_t *ctx, return to_pkt(ctx, PKT__PKT_OPEN, &o); } -Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect) +Pkt *any_pkt_from_file(const char *filename) { struct pkt *pkt; Pkt *ret; @@ -99,6 +99,12 @@ Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect) ret = pkt__unpack(NULL, len, pkt->data); if (!ret) errx(1, "Unpack failed for %s", filename); + return ret; +} + +Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect) +{ + Pkt *ret = any_pkt_from_file(filename); if (ret->pkt_case != expect) errx(1, "Unexpected type %i in %s", ret->pkt_case, filename); @@ -175,3 +181,11 @@ struct pkt *update_accept_pkt(const tal_t *ctx, ua.revocation_preimage = sha256_to_proto(ctx, revocation_preimage); return to_pkt(ctx, PKT__PKT_UPDATE_ACCEPT, &ua); } + +struct pkt *update_complete_pkt(const tal_t *ctx, + const struct sha256 *revocation_preimage) +{ + UpdateComplete uc = UPDATE_COMPLETE__INIT; + uc.revocation_preimage = sha256_to_proto(ctx, revocation_preimage); + return to_pkt(ctx, PKT__PKT_UPDATE_COMPLETE, &uc); +} diff --git a/pkt.h b/pkt.h index 5885c3f76..3e6e5d1fa 100644 --- a/pkt.h +++ b/pkt.h @@ -18,6 +18,7 @@ struct pkt { /* Utility helper: dies if there's a problem. */ Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect); +Pkt *any_pkt_from_file(const char *filename); struct sha256; struct bitcoin_compressed_pubkey; @@ -104,6 +105,14 @@ struct pkt *update_accept_pkt(const tal_t *ctx, const struct sha256 *revocation_hash, const struct sha256 *revocation_preimage); +/** + * update_complete_pkt - create an update_accept message + * @ctx: tal context to allocate off. + * @revocation_preimage: preimage to revoke existing (now-obsolete) tx. + */ +struct pkt *update_complete_pkt(const tal_t *ctx, + const struct sha256 *revocation_preimage); + /* 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); diff --git a/update-channel-complete.c b/update-channel-complete.c new file mode 100644 index 000000000..2a994ae51 --- /dev/null +++ b/update-channel-complete.c @@ -0,0 +1,127 @@ +/* My example: + * ./update-channel-complete B-open.pb > A-update-complete-1.pb + */ +#include +#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 "commit_tx.h" +#include "pubkey.h" +#include "find_p2sh_out.h" +#include +#include + +int main(int argc, char *argv[]) +{ + const tal_t *ctx = tal_arr(NULL, char, 0); + struct sha256 seed, revocation_hash, their_rhash, preimage; + OpenChannel *o1, *o2; + UpdateAccept *ua; + 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, + " [previous-updates]\n" + "Create a new update-complete 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; + ua = pkt_from_file(argv[5], PKT__PKT_UPDATE_ACCEPT)->update_accept; + proto_to_sha256(ua->revocation_preimage, &preimage); + + /* 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 = 0; + for (i = 6; 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? */ + 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. */ + proto_to_sha256(ua->revocation_hash, &their_rhash); + commit = create_commit_tx(ctx, o1, o2, &their_rhash, delta, + &anchor_txid, p2sh_out); + if (!commit) + errx(1, "Delta too large"); + + sig.stype = SIGHASH_ALL; + if (!proto_to_signature(ua->sig, &sig.sig)) + errx(1, "Invalid update 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; +} +