Browse Source

Split into two anchors.

This is a major change; instead of creating a mutual anchor (funding)
transaction, each side creates its own.  We use escape transactions in
case anything goes wrong; these will be revoked later.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 10 years ago
parent
commit
c03c878afc
  1. 2
      .gitignore
  2. 2
      Makefile
  3. 329
      anchor.c
  4. 60
      anchor.h
  5. 32
      close_tx.c
  6. 8
      close_tx.h
  7. 37
      commit_tx.c
  8. 9
      commit_tx.h
  9. 699
      lightning.pb-c.c
  10. 332
      lightning.pb-c.h
  11. 97
      lightning.proto
  12. 72
      pkt.c
  13. 48
      pkt.h
  14. 112
      test-cli/HOWTO-USE.md
  15. 61
      test-cli/check-anchor-scriptsigs.c
  16. 104
      test-cli/check-commit-sig.c
  17. 92
      test-cli/close-channel.c
  18. 188
      test-cli/create-anchor-tx.c
  19. 97
      test-cli/create-close-tx.c
  20. 1
      test-cli/create-commit-spend-tx.c
  21. 111
      test-cli/create-commit-tx.c
  22. 1
      test-cli/create-steal-tx.c
  23. 3
      test-cli/get-anchor-depth.c
  24. 79
      test-cli/open-anchor-id.c
  25. 98
      test-cli/open-anchor-scriptsigs.c
  26. 114
      test-cli/open-channel.c
  27. 73
      test-cli/open-commit-sig.c
  28. 15
      test-cli/scripts/getinput.sh
  29. 67
      test-cli/scripts/test.sh
  30. 70
      test-cli/update-channel-accept.c
  31. 64
      test-cli/update-channel-complete.c
  32. 97
      test-cli/update-channel-signature.c
  33. 1
      test-cli/update-channel.c

2
.gitignore

@ -25,3 +25,5 @@ txid-of
ccan/tools/configurator/configurator
libsecp256k1.a
libsecp256k1.la
create-anchor-tx
open-anchor-id

2
Makefile

@ -8,7 +8,7 @@ FEATURES := -DHAS_CSV=1 -DALPHA_TXSTYLE=1 -DUSE_SCHNORR=1
# Bitcoin uses DER for signatures
#FEATURES := -DSCRIPTS_USE_DER
PROGRAMS := test-cli/open-channel test-cli/open-anchor-scriptsigs test-cli/open-commit-sig test-cli/check-commit-sig test-cli/check-anchor-scriptsigs test-cli/get-anchor-depth test-cli/create-steal-tx test-cli/create-commit-spend-tx test-cli/close-channel test-cli/create-close-tx test-cli/update-channel test-cli/update-channel-accept test-cli/update-channel-signature test-cli/update-channel-complete test-cli/create-commit-tx test-cli/txid-of
PROGRAMS := test-cli/open-channel test-cli/open-commit-sig test-cli/check-commit-sig test-cli/get-anchor-depth test-cli/create-steal-tx test-cli/create-commit-spend-tx test-cli/close-channel test-cli/create-close-tx test-cli/update-channel test-cli/update-channel-accept test-cli/update-channel-signature test-cli/update-channel-complete test-cli/create-commit-tx test-cli/txid-of test-cli/create-anchor-tx test-cli/open-anchor-id
BITCOIN_OBJS := bitcoin/address.o bitcoin/base58.o bitcoin/pubkey.o bitcoin/script.o bitcoin/shadouble.o bitcoin/signature.o bitcoin/tx.o

329
anchor.c

@ -1,165 +1,200 @@
#include <ccan/err/err.h>
#include "anchor.h"
#include "bitcoin/pubkey.h"
#include "bitcoin/script.h"
#include "bitcoin/tx.h"
#include "overflows.h"
#include "permute_tx.h"
#include "pkt.h"
#include "protobuf_convert.h"
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
const OpenChannel *o1,
const OpenChannel *o2,
size_t **inmapp, size_t **outmapp)
{
uint64_t i, n_out;
struct bitcoin_tx *tx;
u8 *redeemscript;
size_t *inmap, *outmap;
struct pubkey key1, key2;
uint64_t total_in = 0, total_change = 0;
if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs))
return NULL;
n_out = 1 + !!o1->anchor->change + !!o2->anchor->change;
tx = bitcoin_tx(ctx, o1->anchor->n_inputs+o2->anchor->n_inputs, n_out);
/* Override version to use lesser of two versions. */
if (o1->tx_version < o2->tx_version)
tx->version = o1->tx_version;
else
tx->version = o2->tx_version;
/* Populate inputs. */
for (i = 0; i < o1->anchor->n_inputs; i++) {
BitcoinInput *pb = o1->anchor->inputs[i];
struct bitcoin_tx_input *in = &tx->input[i];
proto_to_sha256(pb->txid, &in->txid.sha);
in->index = pb->output;
in->input_amount = pb->amount;
if (add_overflows_u64(total_in, in->input_amount))
return tal_free(tx);
total_in += in->input_amount;
/* Leave inputs as stubs for now, for signing. */
}
for (i = 0; i < o2->anchor->n_inputs; i++) {
BitcoinInput *pb = o2->anchor->inputs[i];
struct bitcoin_tx_input *in
= &tx->input[o1->anchor->n_inputs + i];
proto_to_sha256(pb->txid, &in->txid.sha);
in->index = pb->output;
in->input_amount = pb->amount;
if (add_overflows_u64(total_in, in->input_amount))
return tal_free(tx);
total_in += in->input_amount;
/* Leave inputs as stubs for now, for signing. */
}
#undef DEBUG
#ifdef DEBUG
#include <stdio.h>
#include "bitcoin/pubkey.h"
/* Populate outputs. */
if (add_overflows_u64(o1->anchor->total, o2->anchor->total))
return tal_free(tx);
/* Pubkeys both valid, right? */
if (!proto_to_pubkey(o1->anchor->pubkey, &key1)
|| !proto_to_pubkey(o2->anchor->pubkey, &key2))
return tal_free(tx);
/* Make the 2 of 2 payment for the commitment txs. */
redeemscript = bitcoin_redeem_2of2(tx, &key1, &key2);
tx->output[0].amount = o1->anchor->total + o2->anchor->total;
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script);
/* Add change transactions (if any) */
n_out = 1;
if (o1->anchor->change) {
struct bitcoin_tx_output *out = &tx->output[n_out++];
struct pubkey key;
if (!proto_to_pubkey(o1->anchor->change->pubkey, &key))
return tal_free(tx);
out->amount = o1->anchor->change->amount;
out->script = scriptpubkey_p2sh(tx,
bitcoin_redeem_single(tx, &key));
out->script_length = tal_count(out->script);
total_change += out->amount;
static void dump_anchor_spend(const char *what,
size_t input,
const struct pubkey *commitkey1,
const struct pubkey *commitkey2,
const struct pubkey *finalkey,
const struct sha256 *escapehash,
const struct pubkey *signingkey,
const struct signature *sig)
{
size_t i;
fprintf(stderr, "%s input %zu:", what, input);
fprintf(stderr, " commitkey1=");
for (i = 0; i < pubkey_len(commitkey1); i++)
fprintf(stderr, "%02x", commitkey1->key[i]);
fprintf(stderr, " commitkey2=");
for (i = 0; i < pubkey_len(commitkey2); i++)
fprintf(stderr, "%02x", commitkey2->key[i]);
fprintf(stderr, " finalkey=");
for (i = 0; i < pubkey_len(finalkey); i++)
fprintf(stderr, "%02x", finalkey->key[i]);
fprintf(stderr, " escapehash=");
for (i = 0; i < sizeof(escapehash->u.u8); i++)
fprintf(stderr, "%02x", escapehash->u.u8[i]);
fprintf(stderr, " signingkey=");
for (i = 0; i < pubkey_len(signingkey); i++)
fprintf(stderr, "%02x", signingkey->key[i]);
fprintf(stderr, " -> sig {r=");
for (i = 0; i < sizeof(sig->r); i++)
fprintf(stderr, "%02x", sig->r[i]);
fprintf(stderr, ", s=");
for (i = 0; i < sizeof(sig->s); i++)
fprintf(stderr, "%02x", sig->s[i]);
fprintf(stderr, "}\n");
}
if (o2->anchor->change) {
struct bitcoin_tx_output *out = &tx->output[n_out++];
struct pubkey key;
if (!proto_to_pubkey(o2->anchor->change->pubkey, &key))
return tal_free(tx);
out->amount = o2->anchor->change->amount;
out->script = scriptpubkey_p2sh(tx,
bitcoin_redeem_single(tx, &key));
out->script_length = tal_count(out->script);
if (add_overflows_u64(total_change, out->amount))
return tal_free(tx);
total_change += out->amount;
#else
static void dump_anchor_spend(const char *what,
size_t input,
const struct pubkey *commitkey1,
const struct pubkey *commitkey2,
const struct pubkey *finalkey,
const struct sha256 *escapehash,
const struct pubkey *signingkey,
const struct signature *sig)
{
}
assert(n_out == tx->output_count);
/* Figure out fee we're paying; check for over and underflow */
if (add_overflows_u64(total_change, tx->output[0].amount))
return tal_free(tx);
if (total_in < total_change + tx->output[0].amount)
return tal_free(tx);
tx->fee = total_in - (total_change + tx->output[0].amount);
/* Check that the fees add up correctly. */
if (add_overflows_u64(o1->anchor->fee, o2->anchor->fee))
return tal_free(tx);
if (tx->fee != o1->anchor->fee + o2->anchor->fee)
return tal_free(tx);
if (inmapp)
inmap = *inmapp = tal_arr(ctx, size_t, tx->input_count);
else
inmap = NULL;
if (outmapp)
outmap = *outmapp = tal_arr(ctx, size_t, tx->output_count);
else
outmap = NULL;
permute_inputs(tx->input, tx->input_count, inmap);
permute_outputs(tx->output, tx->output_count, outmap);
return tx;
#endif
bool sign_anchor_spend(struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const struct pubkey *signing_pubkey,
const struct privkey *signing_privkey,
struct signature sig[2])
{
const tal_t *ctx = tal(NULL, char);
u8 *redeemscript;
bool ret;
/* Sign input for our anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey,
their_finalkey, my_escapehash);
ret = sign_tx_input(ctx, tx, inmap[0],
redeemscript, tal_count(redeemscript),
signing_privkey, signing_pubkey, &sig[inmap[0]]);
dump_anchor_spend("signed from_mine", inmap[0],
my_commitkey, their_commitkey, their_finalkey,
my_escapehash, signing_pubkey, &sig[inmap[0]]);
/* Sign input for their anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey,
my_finalkey, their_escapehash);
ret &= sign_tx_input(ctx, tx, inmap[1],
redeemscript, tal_count(redeemscript),
signing_privkey, signing_pubkey, &sig[inmap[1]]);
dump_anchor_spend("signed from_yours", inmap[1],
their_commitkey, my_commitkey, my_finalkey,
their_escapehash, signing_pubkey, &sig[inmap[1]]);
tal_free(ctx);
return ret;
}
/* This may create an invalid anchor. That's actually OK, as the bitcoin
* network won't accept it and we'll ds our way out. */
bool anchor_add_scriptsigs(struct bitcoin_tx *anchor,
OpenAnchorScriptsigs *ssigs1,
OpenAnchorScriptsigs *ssigs2,
const size_t *inmap)
/* Check that their sigs sign this tx as expected. */
bool check_anchor_spend(struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const struct pubkey *signing_pubkey,
const AnchorSpend *their_sigs)
{
size_t i;
const tal_t *ctx;
u8 *redeemscript;
bool ret;
struct bitcoin_signature sigs[2];
if (ssigs1->n_script + ssigs2->n_script != anchor->input_count)
return NULL;
sigs[0].stype = sigs[1].stype = SIGHASH_ALL;
for (i = 0; i < ssigs1->n_script; i++) {
size_t n = inmap[i];
anchor->input[n].script = ssigs1->script[i].data;
anchor->input[n].script_length = ssigs1->script[i].len;
}
if (!proto_to_signature(their_sigs->sig0, &sigs[0].sig)
|| !proto_to_signature(their_sigs->sig1, &sigs[1].sig))
return false;
for (i = 0; i < ssigs2->n_script; i++) {
size_t n = inmap[ssigs1->n_script + i];
anchor->input[n].script = ssigs2->script[i].data;
anchor->input[n].script_length = ssigs2->script[i].len;
}
ctx = tal(NULL, char);
return true;
/* Input for our anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey,
their_finalkey, my_escapehash);
ret = check_tx_sig(tx, inmap[0], redeemscript, tal_count(redeemscript),
signing_pubkey, &sigs[inmap[0]]);
dump_anchor_spend("checking from_mine", inmap[0],
my_commitkey, their_commitkey, their_finalkey,
my_escapehash, signing_pubkey, &sigs[inmap[0]].sig);
/* Input for their anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey,
my_finalkey, their_escapehash);
ret &= check_tx_sig(tx, inmap[1], redeemscript, tal_count(redeemscript),
signing_pubkey, &sigs[inmap[1]]);
dump_anchor_spend("checking from_yours", inmap[1],
their_commitkey, my_commitkey, my_finalkey,
their_escapehash, signing_pubkey, &sigs[inmap[1]].sig);
tal_free(ctx);
return ret;
}
void anchor_txid(struct bitcoin_tx *anchor, struct sha256_double *txid)
/* Set up input scriptsigs for this transaction. */
bool populate_anchor_inscripts(const tal_t *ctx,
struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const AnchorSpend *my_sigs,
const AnchorSpend *their_sigs)
{
bitcoin_txid(anchor, txid);
u8 *redeemscript;
struct bitcoin_signature theirs[2], mine[2];
theirs[0].stype = theirs[1].stype = mine[0].stype = mine[1].stype
= SIGHASH_ALL;
if (!proto_to_signature(their_sigs->sig0, &theirs[0].sig)
|| !proto_to_signature(their_sigs->sig1, &theirs[1].sig)
|| !proto_to_signature(my_sigs->sig0, &mine[0].sig)
|| !proto_to_signature(my_sigs->sig1, &mine[1].sig))
return false;
/* Input for our anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey,
their_finalkey, my_escapehash);
tx->input[inmap[0]].script
= scriptsig_p2sh_anchor_commit(ctx,
&theirs[inmap[0]],
&mine[inmap[0]],
redeemscript,
tal_count(redeemscript));
tal_free(redeemscript);
/* Input for their anchor. */
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey,
my_finalkey, their_escapehash);
/* They created their anchor to expect sigs in other order. */
tx->input[inmap[1]].script
= scriptsig_p2sh_anchor_commit(ctx,
&mine[inmap[1]],
&theirs[inmap[1]],
redeemscript,
tal_count(redeemscript));
tal_free(redeemscript);
/* Set up lengths. */
tx->input[0].script_length = tal_count(tx->input[0].script);
tx->input[1].script_length = tal_count(tx->input[1].script);
return true;
}

60
anchor.h

@ -1,31 +1,45 @@
#ifndef LIGHTNING_ANCHOR_H
#define LIGHTNING_ANCHOR_H
#include <ccan/tal/tal.h>
#include "bitcoin/signature.h"
#include "bitcoin/tx.h"
#include "lightning.pb-c.h"
struct sha256_double;
/* Sign this transaction which spends the anchors. */
bool sign_anchor_spend(struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const struct pubkey *signing_pubkey,
const struct privkey *signing_privkey,
struct signature sig[2]);
/* Create an anchor transaction based on both sides' requests.
* The scriptSigs are left empty.
*
* Allocate an input and output map (if non-NULL); the first
* o1->anchor->n_inputs of inmap are the location of o1's inputs, the
* next o2->anchor->n_inputs are o2's. outmap[0] is the location of
* output for the commitment tx, then o1's change (if
* o1->anchor->change), then o2's change if o2->anchor->change.
*/
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
const OpenChannel *o1,
const OpenChannel *o2,
size_t **inmap, size_t **outmap);
/* Check that their sigs sign this tx as expected. */
bool check_anchor_spend(struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const struct pubkey *signing_pubkey,
const AnchorSpend *their_sigs);
/* Add these scriptsigs to the anchor transaction. */
bool anchor_add_scriptsigs(struct bitcoin_tx *anchor,
OpenAnchorScriptsigs *ssigs1,
OpenAnchorScriptsigs *ssigs2,
const size_t *inmap);
/* We wouldn't need the leak files if we had normalized txids! */
void anchor_txid(struct bitcoin_tx *anchor,
struct sha256_double *txid);
/* Set up input scriptsigs for this transaction. */
bool populate_anchor_inscripts(const tal_t *ctx,
struct bitcoin_tx *tx,
const size_t inmap[2],
const struct pubkey *my_commitkey,
const struct pubkey *my_finalkey,
const struct sha256 *my_escapehash,
const struct pubkey *their_commitkey,
const struct pubkey *their_finalkey,
const struct sha256 *their_escapehash,
const AnchorSpend *my_sigs,
const AnchorSpend *their_sigs);
#endif /* LIGHTNING_ANCHOR_H */

32
close_tx.c

@ -11,22 +11,27 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
OpenChannel *ours,
OpenChannel *theirs,
int64_t delta,
const struct sha256_double *anchor_txid,
uint64_t input_amount,
unsigned int anchor_output)
const struct sha256_double *anchor_txid1,
unsigned int index1, uint64_t input_amount1,
const struct sha256_double *anchor_txid2,
unsigned int index2, uint64_t input_amount2,
size_t inmap[2])
{
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);
/* Now create close tx: two inputs, two outputs. */
tx = bitcoin_tx(ctx, 2, 2);
/* Our input spends the anchor tx output. */
tx->input[0].txid = *anchor_txid;
tx->input[0].index = anchor_output;
tx->input[0].input_amount = input_amount;
/* Our inputs spend the anchor tx outputs. */
tx->input[0].txid = *anchor_txid1;
tx->input[0].index = index1;
tx->input[0].input_amount = input_amount1;
tx->input[1].txid = *anchor_txid2;
tx->input[1].index = index2;
tx->input[1].input_amount = input_amount2;
/* Outputs goes to final pubkey */
if (!proto_to_pubkey(ours->final, &ourkey))
@ -35,26 +40,27 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
return tal_free(tx);
/* delta must make sense. */
if (delta < 0 && ours->anchor->total - ours->commitment_fee < -delta)
if (delta < 0 && ours->total_input - ours->commitment_fee < -delta)
return tal_free(tx);
if (delta > 0 && theirs->anchor->total - theirs->commitment_fee < delta)
if (delta > 0 && theirs->total_input - theirs->commitment_fee < delta)
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 + delta;
tx->output[0].amount = ours->total_input - ours->commitment_fee + delta;
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 - delta;
tx->output[1].amount = theirs->total_input - theirs->commitment_fee - delta;
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);
tx->fee = ours->commitment_fee + theirs->commitment_fee;
permute_inputs(tx->input, 2, inmap);
permute_outputs(tx->output, 2, NULL);
return tx;
}

8
close_tx.h

@ -11,7 +11,9 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
OpenChannel *ours,
OpenChannel *theirs,
int64_t delta,
const struct sha256_double *anchor_txid,
uint64_t input_amount,
unsigned int anchor_output);
const struct sha256_double *anchor_txid1,
unsigned int index1, uint64_t input_amount1,
const struct sha256_double *anchor_txid2,
unsigned int index2, uint64_t input_amount2,
size_t inmap[2]);
#endif

37
commit_tx.c

@ -13,23 +13,31 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
OpenChannel *theirs,
const struct sha256 *rhash,
int64_t delta,
const struct sha256_double *anchor_txid,
unsigned int anchor_output)
const struct sha256_double *anchor_txid1,
unsigned int index1, uint64_t input_amount1,
const struct sha256_double *anchor_txid2,
unsigned int index2, uint64_t input_amount2,
size_t inmap[2])
{
struct bitcoin_tx *tx;
const u8 *redeemscript;
struct pubkey ourkey, theirkey, to_me;
u32 locktime;
/* Now create commitment tx: one input, two outputs. */
tx = bitcoin_tx(ctx, 1, 2);
/* Now create commitment tx: two inputs, two outputs. */
tx = bitcoin_tx(ctx, 2, 2);
/* Our input spends the anchor tx output. */
tx->input[0].txid = *anchor_txid;
tx->input[0].index = anchor_output;
if (add_overflows_u64(ours->anchor->total, theirs->anchor->total))
/* Our inputs spend the anchor txs outputs. */
tx->input[0].txid = *anchor_txid1;
tx->input[0].index = index1;
tx->input[0].input_amount = input_amount1;
tx->input[1].txid = *anchor_txid2;
tx->input[1].index = index2;
tx->input[1].input_amount = input_amount2;
if (add_overflows_u64(tx->input[0].input_amount,
tx->input[1].input_amount))
return tal_free(tx);
tx->input[0].input_amount = ours->anchor->total + theirs->anchor->total;
/* Output goes to our final pubkeys */
if (!proto_to_pubkey(ours->final, &ourkey))
@ -48,9 +56,9 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script);
if (ours->anchor->total < ours->commitment_fee)
if (ours->total_input < ours->commitment_fee)
return tal_free(tx);
tx->output[0].amount = ours->anchor->total - ours->commitment_fee;
tx->output[0].amount = ours->total_input - ours->commitment_fee;
/* Asking for more than we have? */
if (delta < 0 && -delta > tx->output[0].amount)
return tal_free(tx);
@ -64,18 +72,19 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
&to_me));
tx->output[1].script_length = tal_count(tx->output[1].script);
if (theirs->anchor->total < theirs->commitment_fee)
if (theirs->total_input < theirs->commitment_fee)
return tal_free(tx);
tx->output[1].amount = theirs->anchor->total - theirs->commitment_fee;
tx->output[1].amount = theirs->total_input - theirs->commitment_fee;
/* Asking for more than they have? */
if (delta > 0 && delta > tx->output[1].amount)
return tal_free(tx);
tx->output[0].amount -= delta;
/* Calculate fee; difference of inputs and outputs. */
tx->fee = tx->input[0].input_amount
tx->fee = tx->input[0].input_amount + tx->input[1].input_amount
- (tx->output[0].amount + tx->output[1].amount);
permute_inputs(tx->input, 2, inmap);
permute_outputs(tx->output, 2, NULL);
return tx;
}

9
commit_tx.h

@ -6,13 +6,16 @@
struct sha256_double;
struct sha256;
/* Create commitment tx to spend the anchor tx output; doesn't fill in
/* Create commitment tx to spend the anchor tx outputs; doesn't fill in
* input scriptsig. */
struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
OpenChannel *ours,
OpenChannel *theirs,
const struct sha256 *revocation_hash,
int64_t delta,
const struct sha256_double *anchor_txid,
unsigned int anchor_output);
const struct sha256_double *anchor_txid1,
unsigned int index1, uint64_t input_amount1,
const struct sha256_double *anchor_txid2,
unsigned int index2, uint64_t input_amount2,
size_t inmap[2]);
#endif

699
lightning.pb-c.c

File diff suppressed because it is too large

332
lightning.pb-c.h

@ -17,13 +17,12 @@ PROTOBUF_C__BEGIN_DECLS
typedef struct _Sha256Hash Sha256Hash;
typedef struct _Signature Signature;
typedef struct _BitcoinInput BitcoinInput;
typedef struct _AnchorSpend AnchorSpend;
typedef struct _BitcoinPubkey BitcoinPubkey;
typedef struct _Change Change;
typedef struct _Anchor Anchor;
typedef struct _OpenChannel OpenChannel;
typedef struct _OpenAnchor OpenAnchor;
typedef struct _OpenEscapeSigs OpenEscapeSigs;
typedef struct _OpenCommitSig OpenCommitSig;
typedef struct _OpenAnchorScriptsigs OpenAnchorScriptsigs;
typedef struct _OpenComplete OpenComplete;
typedef struct _Update Update;
typedef struct _UpdateAccept UpdateAccept;
@ -74,31 +73,24 @@ struct _Signature
/*
* Identifies consumption of a bitcoin output.
* To update the channel (commit tx or close tx) we need a signature for each
* input.
*/
struct _BitcoinInput
struct _AnchorSpend
{
ProtobufCMessage base;
/*
* This is the transaction ID.
* From first anchor input.
*/
Sha256Hash *txid;
Signature *sig0;
/*
* This is the output number.
* From second anchor input.
*/
uint32_t output;
/*
* And the subscript we're signing.
*/
ProtobufCBinaryData subscript;
/*
* The amount this input is worth.
*/
uint64_t amount;
Signature *sig1;
};
#define BITCOIN_INPUT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&bitcoin_input__descriptor) \
, NULL, 0, {0,NULL}, 0 }
#define ANCHOR_SPEND__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&anchor_spend__descriptor) \
, NULL, NULL }
/*
@ -117,57 +109,6 @@ struct _BitcoinPubkey
, {0,NULL} }
/*
* Change, if we want any.
*/
struct _Change
{
ProtobufCMessage base;
uint64_t amount;
BitcoinPubkey *pubkey;
};
#define CHANGE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&change__descriptor) \
, 0, NULL }
/*
* All about an anchor transaction.
*/
struct _Anchor
{
ProtobufCMessage base;
/*
* 0 or more unspent inputs we want to use for anchor.
*/
size_t n_inputs;
BitcoinInput **inputs;
/*
* Pubkey for anchor to pay to for commitment tx (p2sh)
*/
BitcoinPubkey *pubkey;
/*
* Any change from anchor (in case we don't want to use them all)
*/
Change *change;
/*
* How much transaction fee we'll pay in the anchor tx.
*/
uint64_t fee;
/*
* How much we'll be putting into channel (== sum(inputs) - change - fee)
*/
uint64_t total;
/*
* How many confirmations on anchor before we'll use channel.
*/
uint32_t min_confirms;
};
#define ANCHOR__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&anchor__descriptor) \
, 0,NULL, NULL, NULL, 0, 0, 0 }
typedef enum {
OPEN_CHANNEL__LOCKTIME__NOT_SET = 0,
OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS = 2,
@ -185,7 +126,7 @@ struct _OpenChannel
*/
Sha256Hash *revocation_hash;
/*
* How to pay money to us from commit_tx.
* How to pay money to us from commit_tx (also for escape txs)
*/
BitcoinPubkey *final;
/*
@ -193,13 +134,21 @@ struct _OpenChannel
*/
uint64_t commitment_fee;
/*
* The anchor transaction details.
* Key for commitment tx 2of2.
*/
BitcoinPubkey *commitkey;
/*
* How much we'll be putting into channel
*/
Anchor *anchor;
uint64_t total_input;
/*
* Maximum transaction version we support.
* Secret hash for escape transactions.
*/
Sha256Hash *escape_hash;
/*
* How many confirmations on anchor before we'll use channel.
*/
uint32_t tx_version;
uint32_t min_confirms;
OpenChannel__LocktimeCase locktime_case;
union {
uint32_t locktime_seconds;
@ -208,34 +157,57 @@ struct _OpenChannel
};
#define OPEN_CHANNEL__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_channel__descriptor) \
, NULL, NULL, 0, NULL, 0, OPEN_CHANNEL__LOCKTIME__NOT_SET, {} }
, NULL, NULL, 0, NULL, 0, NULL, 0, OPEN_CHANNEL__LOCKTIME__NOT_SET, {} }
/*
* Supply signature for commitment tx
* Give them the txid of our anchor transaction.
*/
struct _OpenCommitSig
struct _OpenAnchor
{
ProtobufCMessage base;
Signature *sig;
Sha256Hash *anchor_txid;
/*
* Which output of anchor goes to this.
*/
uint32_t index;
};
#define OPEN_COMMIT_SIG__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_commit_sig__descriptor) \
, NULL }
#define OPEN_ANCHOR__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_anchor__descriptor) \
, NULL, 0 }
/*
* Give them signatures for their escape transactions.
*/
struct _OpenEscapeSigs
{
ProtobufCMessage base;
/*
* Signature for their escape tx.
*/
Signature *escape;
/*
* Signature for their fast-escape tx.
*/
Signature *fast_escape;
};
#define OPEN_ESCAPE_SIGS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_escape_sigs__descriptor) \
, NULL, NULL }
/*
* Supply ScriptSig for each anchor tx inputs.
* Supply signatures for commitment tx
*/
struct _OpenAnchorScriptsigs
struct _OpenCommitSig
{
ProtobufCMessage base;
size_t n_script;
ProtobufCBinaryData *script;
AnchorSpend *sigs;
};
#define OPEN_ANCHOR_SCRIPTSIGS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_anchor_scriptsigs__descriptor) \
, 0,NULL }
#define OPEN_COMMIT_SIG__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_commit_sig__descriptor) \
, NULL }
/*
@ -287,13 +259,9 @@ struct _UpdateAccept
{
ProtobufCMessage base;
/*
* Signature for your new commitment tx.
* Signatures for your new commitment tx.
*/
Signature *sig;
/*
* Signature for old anchor (if any)
*/
Signature *old_anchor_sig;
AnchorSpend *sigs;
/*
* Hash for which I will supply preimage to revoke this new commit tx.
*/
@ -301,7 +269,7 @@ struct _UpdateAccept
};
#define UPDATE_ACCEPT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&update_accept__descriptor) \
, NULL, NULL, NULL }
, NULL, NULL }
/*
@ -311,9 +279,9 @@ struct _UpdateSignature
{
ProtobufCMessage base;
/*
* Signature for your new commitment tx.
* Signatures for your new commitment tx.
*/
Signature *sig;
AnchorSpend *sigs;
/*
* Hash preimage which revokes old commitment tx.
*/
@ -347,11 +315,10 @@ struct _CloseChannel
{
ProtobufCMessage base;
/*
* This is our signature a new transaction which spends the anchor
* output to my open->final and your open->final,
* as per the last commit tx.
* These are our signatures on a new transaction which spends the anchor
* outputs to my open->final and your open->final, as per the last commit tx.
*/
Signature *sig;
AnchorSpend *sigs;
};
#define CLOSE_CHANNEL__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&close_channel__descriptor) \
@ -365,9 +332,9 @@ struct _CloseChannelComplete
{
ProtobufCMessage base;
/*
* This is my signature for that same tx.
* These are my signatures for that same tx.
*/
Signature *sig;
AnchorSpend *sigs;
};
#define CLOSE_CHANNEL_COMPLETE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&close_channel_complete__descriptor) \
@ -390,8 +357,9 @@ struct _Error
typedef enum {
PKT__PKT__NOT_SET = 0,
PKT__PKT_OPEN = 201,
PKT__PKT_OPEN_ANCHOR = 203,
PKT__PKT_OPEN_ESCAPE_SIGS = 205,
PKT__PKT_OPEN_COMMIT_SIG = 202,
PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS = 203,
PKT__PKT_OPEN_COMPLETE = 204,
PKT__PKT_UPDATE = 1,
PKT__PKT_UPDATE_ACCEPT = 2,
@ -414,8 +382,9 @@ struct _Pkt
* Opening
*/
OpenChannel *open;
OpenAnchor *open_anchor;
OpenEscapeSigs *open_escape_sigs;
OpenCommitSig *open_commit_sig;
OpenAnchorScriptsigs *open_anchor_scriptsigs;
OpenComplete *open_complete;
/*
* Updating (most common)
@ -478,24 +447,24 @@ Signature *
void signature__free_unpacked
(Signature *message,
ProtobufCAllocator *allocator);
/* BitcoinInput methods */
void bitcoin_input__init
(BitcoinInput *message);
size_t bitcoin_input__get_packed_size
(const BitcoinInput *message);
size_t bitcoin_input__pack
(const BitcoinInput *message,
/* AnchorSpend methods */
void anchor_spend__init
(AnchorSpend *message);
size_t anchor_spend__get_packed_size
(const AnchorSpend *message);
size_t anchor_spend__pack
(const AnchorSpend *message,
uint8_t *out);
size_t bitcoin_input__pack_to_buffer
(const BitcoinInput *message,
size_t anchor_spend__pack_to_buffer
(const AnchorSpend *message,
ProtobufCBuffer *buffer);
BitcoinInput *
bitcoin_input__unpack
AnchorSpend *
anchor_spend__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void bitcoin_input__free_unpacked
(BitcoinInput *message,
void anchor_spend__free_unpacked
(AnchorSpend *message,
ProtobufCAllocator *allocator);
/* BitcoinPubkey methods */
void bitcoin_pubkey__init
@ -516,44 +485,6 @@ BitcoinPubkey *
void bitcoin_pubkey__free_unpacked
(BitcoinPubkey *message,
ProtobufCAllocator *allocator);
/* Change methods */
void change__init
(Change *message);
size_t change__get_packed_size
(const Change *message);
size_t change__pack
(const Change *message,
uint8_t *out);
size_t change__pack_to_buffer
(const Change *message,
ProtobufCBuffer *buffer);
Change *
change__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void change__free_unpacked
(Change *message,
ProtobufCAllocator *allocator);
/* Anchor methods */
void anchor__init
(Anchor *message);
size_t anchor__get_packed_size
(const Anchor *message);
size_t anchor__pack
(const Anchor *message,
uint8_t *out);
size_t anchor__pack_to_buffer
(const Anchor *message,
ProtobufCBuffer *buffer);
Anchor *
anchor__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void anchor__free_unpacked
(Anchor *message,
ProtobufCAllocator *allocator);
/* OpenChannel methods */
void open_channel__init
(OpenChannel *message);
@ -573,6 +504,44 @@ OpenChannel *
void open_channel__free_unpacked
(OpenChannel *message,
ProtobufCAllocator *allocator);
/* OpenAnchor methods */
void open_anchor__init
(OpenAnchor *message);
size_t open_anchor__get_packed_size
(const OpenAnchor *message);
size_t open_anchor__pack
(const OpenAnchor *message,
uint8_t *out);
size_t open_anchor__pack_to_buffer
(const OpenAnchor *message,
ProtobufCBuffer *buffer);
OpenAnchor *
open_anchor__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void open_anchor__free_unpacked
(OpenAnchor *message,
ProtobufCAllocator *allocator);
/* OpenEscapeSigs methods */
void open_escape_sigs__init
(OpenEscapeSigs *message);
size_t open_escape_sigs__get_packed_size
(const OpenEscapeSigs *message);
size_t open_escape_sigs__pack
(const OpenEscapeSigs *message,
uint8_t *out);
size_t open_escape_sigs__pack_to_buffer
(const OpenEscapeSigs *message,
ProtobufCBuffer *buffer);
OpenEscapeSigs *
open_escape_sigs__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void open_escape_sigs__free_unpacked
(OpenEscapeSigs *message,
ProtobufCAllocator *allocator);
/* OpenCommitSig methods */
void open_commit_sig__init
(OpenCommitSig *message);
@ -592,25 +561,6 @@ OpenCommitSig *
void open_commit_sig__free_unpacked
(OpenCommitSig *message,
ProtobufCAllocator *allocator);
/* OpenAnchorScriptsigs methods */
void open_anchor_scriptsigs__init
(OpenAnchorScriptsigs *message);
size_t open_anchor_scriptsigs__get_packed_size
(const OpenAnchorScriptsigs *message);
size_t open_anchor_scriptsigs__pack
(const OpenAnchorScriptsigs *message,
uint8_t *out);
size_t open_anchor_scriptsigs__pack_to_buffer
(const OpenAnchorScriptsigs *message,
ProtobufCBuffer *buffer);
OpenAnchorScriptsigs *
open_anchor_scriptsigs__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void open_anchor_scriptsigs__free_unpacked
(OpenAnchorScriptsigs *message,
ProtobufCAllocator *allocator);
/* OpenComplete methods */
void open_complete__init
(OpenComplete *message);
@ -790,27 +740,24 @@ typedef void (*Sha256Hash_Closure)
typedef void (*Signature_Closure)
(const Signature *message,
void *closure_data);
typedef void (*BitcoinInput_Closure)
(const BitcoinInput *message,
typedef void (*AnchorSpend_Closure)
(const AnchorSpend *message,
void *closure_data);
typedef void (*BitcoinPubkey_Closure)
(const BitcoinPubkey *message,
void *closure_data);
typedef void (*Change_Closure)
(const Change *message,
void *closure_data);
typedef void (*Anchor_Closure)
(const Anchor *message,
void *closure_data);
typedef void (*OpenChannel_Closure)
(const OpenChannel *message,
void *closure_data);
typedef void (*OpenAnchor_Closure)
(const OpenAnchor *message,
void *closure_data);
typedef void (*OpenEscapeSigs_Closure)
(const OpenEscapeSigs *message,
void *closure_data);
typedef void (*OpenCommitSig_Closure)
(const OpenCommitSig *message,
void *closure_data);
typedef void (*OpenAnchorScriptsigs_Closure)
(const OpenAnchorScriptsigs *message,
void *closure_data);
typedef void (*OpenComplete_Closure)
(const OpenComplete *message,
void *closure_data);
@ -846,13 +793,12 @@ typedef void (*Pkt_Closure)
extern const ProtobufCMessageDescriptor sha256_hash__descriptor;
extern const ProtobufCMessageDescriptor signature__descriptor;
extern const ProtobufCMessageDescriptor bitcoin_input__descriptor;
extern const ProtobufCMessageDescriptor anchor_spend__descriptor;
extern const ProtobufCMessageDescriptor bitcoin_pubkey__descriptor;
extern const ProtobufCMessageDescriptor change__descriptor;
extern const ProtobufCMessageDescriptor anchor__descriptor;
extern const ProtobufCMessageDescriptor open_channel__descriptor;
extern const ProtobufCMessageDescriptor open_anchor__descriptor;
extern const ProtobufCMessageDescriptor open_escape_sigs__descriptor;
extern const ProtobufCMessageDescriptor open_commit_sig__descriptor;
extern const ProtobufCMessageDescriptor open_anchor_scriptsigs__descriptor;
extern const ProtobufCMessageDescriptor open_complete__descriptor;
extern const ProtobufCMessageDescriptor update__descriptor;
extern const ProtobufCMessageDescriptor update_accept__descriptor;

97
lightning.proto

@ -24,16 +24,13 @@ message signature {
required fixed64 s4 = 8;
}
// Identifies consumption of a bitcoin output.
message bitcoin_input {
// This is the transaction ID.
required sha256_hash txid = 1;
// This is the output number.
required uint32 output = 2;
// And the subscript we're signing.
required bytes subscript = 3;
// The amount this input is worth.
required uint64 amount = 4;
// To update the channel (commit tx or close tx) we need a signature for each
// input.
message anchor_spend {
// From first anchor input.
required signature sig0 = 1;
// From second anchor input.
required signature sig1 = 2;
}
// Pubkey for commitment transaction input.
@ -42,28 +39,6 @@ message bitcoin_pubkey {
required bytes key = 1;
};
// Change, if we want any.
message change {
required uint64 amount = 1;
required bitcoin_pubkey pubkey = 2;
}
// All about an anchor transaction.
message anchor {
// 0 or more unspent inputs we want to use for anchor.
repeated bitcoin_input inputs = 1;
// Pubkey for anchor to pay to for commitment tx (p2sh)
required bitcoin_pubkey pubkey = 5;
// Any change from anchor (in case we don't want to use them all)
optional change change = 2;
// How much transaction fee we'll pay in the anchor tx.
required uint64 fee = 8;
// How much we'll be putting into channel (== sum(inputs) - change - fee)
required uint64 total = 4;
// How many confirmations on anchor before we'll use channel.
required uint32 min_confirms = 10;
}
//
// Packet Types
//
@ -77,24 +52,38 @@ message open_channel {
}
// Hash seed for revoking commitment transactions.
required sha256_hash revocation_hash = 4;
// How to pay money to us from commit_tx.
// How to pay money to us from commit_tx (also for escape txs)
required bitcoin_pubkey final = 5;
// How much transaction fee we'll pay for commitment txs.
required uint64 commitment_fee = 6;
// The anchor transaction details.
required anchor anchor = 7;
// Maximum transaction version we support.
required uint32 tx_version = 8;
// Key for commitment tx 2of2.
required bitcoin_pubkey commitkey = 7;
// How much we'll be putting into channel
required uint64 total_input = 8;
// Secret hash for escape transactions.
required sha256_hash escape_hash = 9;
// How many confirmations on anchor before we'll use channel.
required uint32 min_confirms = 10;
}
// Supply signature for commitment tx
message open_commit_sig {
required signature sig = 1;
// Give them the txid of our anchor transaction.
message open_anchor {
required sha256_hash anchor_txid = 1;
// Which output of anchor goes to this.
required uint32 index = 2;
}
// Supply ScriptSig for each anchor tx inputs.
message open_anchor_scriptsigs {
repeated bytes script = 1;
// Give them signatures for their escape transactions.
message open_escape_sigs {
// Signature for their escape tx.
required signature escape = 1;
// Signature for their fast-escape tx.
required signature fast_escape = 2;
}
// Supply signatures for commitment tx
message open_commit_sig {
required anchor_spend sigs = 1;
}
// Indicates we've seen transaction reach min-depth.
@ -115,16 +104,16 @@ message update {
// OK, I accept that update; here's your signature.
message update_accept {
// Signature for your new commitment tx.
required signature sig = 1;
// Signatures for your new commitment tx.
required anchor_spend sigs = 1;
// Hash for which I will supply preimage to revoke this new commit tx.
required sha256_hash revocation_hash = 3;
}
// Thanks for accepting, here's my last bit.
message update_signature {
// Signature for your new commitment tx.
required signature sig = 1;
// Signatures for your new commitment tx.
required anchor_spend sigs = 1;
// Hash preimage which revokes old commitment tx.
required sha256_hash revocation_preimage = 2;
}
@ -137,16 +126,15 @@ message update_complete {
// Begin cooperative close of channel.
message close_channel {
// This is our signature a new transaction which spends the anchor
// output to my open->final and your open->final,
// as per the last commit tx.
required signature sig = 1;
// These are our signatures on a new transaction which spends the anchor
// outputs to my open->final and your open->final, as per the last commit tx.
required anchor_spend sigs = 1;
}
// OK, here's my sig so you can broadcast it too. We're done.
message close_channel_complete {
// This is my signature for that same tx.
required signature sig = 1;
// These are my signatures for that same tx.
required anchor_spend sigs = 1;
}
// This means we're going to hang up; it's to help diagnose only!
@ -159,8 +147,9 @@ message pkt {
oneof pkt {
// Opening
open_channel open = 201;
open_anchor open_anchor = 203;
open_escape_sigs open_escape_sigs = 205;
open_commit_sig open_commit_sig = 202;
open_anchor_scriptsigs open_anchor_scriptsigs = 203;
open_complete open_complete = 204;
// Updating (most common)
update update = 1;

72
pkt.c

@ -33,24 +33,25 @@ static struct pkt *to_pkt(const tal_t *ctx, Pkt__PktCase type, void *msg)
struct pkt *openchannel_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash,
const struct pubkey *to_me,
const struct pubkey *commit,
const struct pubkey *final,
u64 commitment_fee,
u32 rel_locktime_seconds,
Anchor *anchor)
u64 anchor_amount,
const struct sha256 *escape_hash,
u32 min_confirms)
{
OpenChannel o = OPEN_CHANNEL__INIT;
/* Required fields must be set: pack functions don't check! */
assert(anchor->inputs);
assert(anchor->pubkey);
o.revocation_hash = sha256_to_proto(ctx, revocation_hash);
o.final = pubkey_to_proto(ctx, to_me);
o.commitkey = pubkey_to_proto(ctx, commit);
o.final = pubkey_to_proto(ctx, final);
o.commitment_fee = commitment_fee;
o.anchor = anchor;
o.locktime_case = OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS;
o.locktime_seconds = rel_locktime_seconds;
o.tx_version = BITCOIN_TX_VERSION;
o.total_input = anchor_amount;
o.escape_hash = sha256_to_proto(ctx, escape_hash);
o.min_confirms = min_confirms;
{
size_t len = open_channel__get_packed_size(&o);
@ -93,41 +94,44 @@ Pkt *pkt_from_file(const char *filename, Pkt__PktCase expect)
return ret;
}
struct pkt *open_anchor_sig_pkt(const tal_t *ctx, u8 **sigs, size_t num_sigs)
struct pkt *open_anchor_pkt(const tal_t *ctx, const struct sha256_double *txid,
u32 index)
{
OpenAnchorScriptsigs o = OPEN_ANCHOR_SCRIPTSIGS__INIT;
size_t i;
o.n_script = num_sigs;
o.script = tal_arr(ctx, ProtobufCBinaryData, num_sigs);
for (i = 0; i < num_sigs; i++) {
o.script[i].data = sigs[i];
o.script[i].len = tal_count(sigs[i]);
}
OpenAnchor oa = OPEN_ANCHOR__INIT;
return to_pkt(ctx, PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS, &o);
oa.anchor_txid = sha256_to_proto(ctx, &txid->sha);
oa.index = index;
return to_pkt(ctx, PKT__PKT_OPEN_ANCHOR, &oa);
}
struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sig)
struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sigs)
{
OpenCommitSig o = OPEN_COMMIT_SIG__INIT;
o.sig = signature_to_proto(ctx, sig);
o.sigs = tal(ctx, AnchorSpend);
anchor_spend__init(o.sigs);
o.sigs->sig0 = signature_to_proto(ctx, &sigs[0]);
o.sigs->sig1 = signature_to_proto(ctx, &sigs[1]);
return to_pkt(ctx, PKT__PKT_OPEN_COMMIT_SIG, &o);
}
struct pkt *close_channel_pkt(const tal_t *ctx, const struct signature *sig)
struct pkt *close_channel_pkt(const tal_t *ctx, const struct signature *sigs)
{
CloseChannel c = CLOSE_CHANNEL__INIT;
c.sig = signature_to_proto(ctx, sig);
c.sigs = tal(ctx, AnchorSpend);
anchor_spend__init(c.sigs);
c.sigs->sig0 = signature_to_proto(ctx, &sigs[0]);
c.sigs->sig1 = signature_to_proto(ctx, &sigs[1]);
return to_pkt(ctx, PKT__PKT_CLOSE, &c);
}
struct pkt *close_channel_complete_pkt(const tal_t *ctx,
const struct signature *sig)
const struct signature *sigs)
{
CloseChannelComplete c = CLOSE_CHANNEL_COMPLETE__INIT;
c.sig = signature_to_proto(ctx, sig);
c.sigs = tal(ctx, AnchorSpend);
anchor_spend__init(c.sigs);
c.sigs->sig0 = signature_to_proto(ctx, &sigs[0]);
c.sigs->sig1 = signature_to_proto(ctx, &sigs[1]);
return to_pkt(ctx, PKT__PKT_CLOSE_COMPLETE, &c);
}
@ -142,21 +146,27 @@ struct pkt *update_pkt(const tal_t *ctx,
}
struct pkt *update_accept_pkt(const tal_t *ctx,
struct signature *sig,
const struct signature *sigs,
const struct sha256 *revocation_hash)
{
UpdateAccept ua = UPDATE_ACCEPT__INIT;
ua.sig = signature_to_proto(ctx, sig);
ua.sigs = tal(ctx, AnchorSpend);
anchor_spend__init(ua.sigs);
ua.sigs->sig0 = signature_to_proto(ctx, &sigs[0]);
ua.sigs->sig1 = signature_to_proto(ctx, &sigs[1]);
ua.revocation_hash = sha256_to_proto(ctx, revocation_hash);
return to_pkt(ctx, PKT__PKT_UPDATE_ACCEPT, &ua);
}
struct pkt *update_signature_pkt(const tal_t *ctx,
const struct signature *sig,
const struct signature *sigs,
const struct sha256 *revocation_preimage)
{
UpdateSignature us = UPDATE_SIGNATURE__INIT;
us.sig = signature_to_proto(ctx, sig);
us.sigs = tal(ctx, AnchorSpend);
anchor_spend__init(us.sigs);
us.sigs->sig0 = signature_to_proto(ctx, &sigs[0]);
us.sigs->sig1 = signature_to_proto(ctx, &sigs[1]);
us.revocation_preimage = sha256_to_proto(ctx, revocation_preimage);
return to_pkt(ctx, PKT__PKT_UPDATE_SIGNATURE, &us);
}

48
pkt.h

@ -24,6 +24,7 @@ Pkt *any_pkt_from_file(const char *filename);
size_t pkt_totlen(const struct pkt *pkt);
struct sha256;
struct sha256_double;
struct bitcoin_compressed_pubkey;
struct signature;
struct pubkey;
@ -32,47 +33,58 @@ struct pubkey;
* openchannel_pkt - create an openchannel message
* @ctx: tal context to allocate off.
* @revocation_hash: first hash value generated from seed.
* @to_me: the pubkey for the commit transactions' P2SH output.
* @commit: the pubkey for commit transactions.
* @final: the pubkey for the commit transactions' output and escape input.
* @commitment_fee: the fee to use for commitment tx.
* @rel_locktime_seconds: relative seconds for commitment locktime.
* @anchor: the anchor transaction details.
* @anchor_txid: the anchor transaction ID.
* @anchor_amount: the anchor amount.
* @escape_hash: the hash whose preimage will revoke our escape txs.
* @min_confirms: how many confirms we want on anchor.
*/
struct pkt *openchannel_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash,
const struct pubkey *to_me,
const struct pubkey *commit,
const struct pubkey *final,
u64 commitment_fee,
u32 rel_locktime_seconds,
Anchor *anchor);
u64 anchor_amount,
const struct sha256 *escape_hash,
u32 min_confirms);
/**
* open_anchor_sig_pkt - create an open_anchor_sig message
* open_anchor_pkt - create an open_anchor_sig message
* @ctx: tal context to allocate off.
* @sigs: the der-encoded signatures (tal_count() gives len).
* @num_sigs: the number of sigs.
* @txid: the anchor's txid
* @index: the anchor's output to spend.
*/
struct pkt *open_anchor_sig_pkt(const tal_t *ctx, u8 **sigs, size_t num_sigs);
struct pkt *open_anchor_pkt(const tal_t *ctx,
const struct sha256_double *txid, u32 index);
/**
* open_commit_sig_pkt - create an open_commit_sig message
* @ctx: tal context to allocate off.
* @sig: the signature for the commit transaction input.
* @sigs: two signatures for the commit transaction inputs
*/
struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sig);
struct pkt *open_commit_sig_pkt(const tal_t *ctx,
const struct signature *sigs);
/**
* close_channel_pkt - create an close_channel message
* @ctx: tal context to allocate off.
* @sig: the signature for the close transaction input.
* @sigs: two signatures for the close transaction inputs
*/
struct pkt *close_channel_pkt(const tal_t *ctx, const struct signature *sig);
struct pkt *close_channel_pkt(const tal_t *ctx,
const struct signature *sigs);
/**
* close_channel_complete_pkt - create an close_channel_complete message
* @ctx: tal context to allocate off.
* @sig: the signature for the close transaction input.
* @sigs: two signatures for the close transaction inputs
*/
struct pkt *close_channel_complete_pkt(const tal_t *ctx,
const struct signature *sig);
const struct signature *sigs);
/**
* update_pkt - create an update message
@ -87,21 +99,21 @@ struct pkt *update_pkt(const tal_t *ctx,
/**
* update_accept_pkt - create an update_accept message
* @ctx: tal context to allocate off.
* @sig: the signature for the close transaction input.
* @sigs: two signatures for the commit transaction inputs
* @revocation_hash: hash to revoke the next tx.
*/
struct pkt *update_accept_pkt(const tal_t *ctx,
struct signature *sig,
const struct signature *sigs,
const struct sha256 *revocation_hash);
/**
* update_signature_pkt - create an update_signature message
* @ctx: tal context to allocate off.
* @sig: the signature for the close transaction input.
* @sigs: two signatures for the commit transaction inputs
* @revocation_preimage: preimage to revoke existing (now-obsolete) tx.
*/
struct pkt *update_signature_pkt(const tal_t *ctx,
const struct signature *sig,
const struct signature *sigs,
const struct sha256 *revocation_preimage);
/**
* update_complete_pkt - create an update_accept message

112
test-cli/HOWTO-USE.md

@ -41,98 +41,116 @@ For each side A and B you need:
7. FINALKEY: The private key for FINALADDR
eg. `alpha-cli -regtest -testnet=0 dumpprivkey <FINALADDR>`
8. TXIN{1-n}: One or more unspent transaction outputs on testnet.
These are in form "<txid>/<outnum>/<amount>/<scriptsig>".
These are in form "<txid>/<outnum>/<amount>/<scriptsig>/<privkey>".
eg. scripts/getinput.sh (`scripts/getinput.sh 2`, etc).
9. TXINKEY{1-n}: The private keys to spend the TXINs.
eg. `scripts/getinput.sh --privkey` can get these.
9. ESCAPE-SECRET: A secret 256-bit number, in hex.
Try 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
STEP 1
------
First each side needs to tell the other what it wants the channel
to look like, including how many satoshis to put in the channel.
Note that the default anchor fee is 5000 satoshi each, (use
`--anchor-fee=` to override), so your amount must be less than or equal
to the total inputs plus this fee.
A: Create a channel open request packet:
test-cli/open-channel <A-SEED> <amount> <A-CHANGEPUBKEY> <A-TMPKEY> <A-FINALKEY> <txid>/<outnum>/<amount>/<scriptsig>... > A-open.pb
test-cli/open-channel <A-SEED> <amount> <A-TMPKEY> <A-FINALKEY> <A-ESCAPE-SECRET> > A-open.pb
B: The same:
test-cli/open-channel <B-SEED> <amount> <B-CHANGEPUBKEY> <B-TMPKEY> <B-FINALKEY> <txid>/<outnum>/<amount>/<scriptsig>... > B-open.pb
test-cli/open-channel <B-SEED> <amount> <B-TMPKEY> <B-FINALKEY> <B-ESCAPE-SECRET> > B-open.pb
STEP 2
------
Create the signatures for the anchor transaction: we don't send them
until we have completed the commitment transaction though, so we're sure
we can get our funds back. We need one TXINKEY for each TXIN:
Each side creates their anchor transaction which pays to a 2 of 2
(spendable with their own key and the other's TMPKEY or FINALKEY). We
don't send them until we have completed the escape transactions
though, so we're sure we can get our funds back.
The change-pubkey arg is only used if you supply inputs which are greater
than the amount promised in the open packet.
A:
test-cli/create-anchor-tx A-open.pb B-open.pb <A-CHANGEPUBKEY> <txid>/<outnum>/<amount>/<scriptsig>/<privkey>... > A-anchor.tx
test-cli/open-anchor-scriptsigs A-open.pb B-open.pb <A-TXINKEY>... > A-anchor-scriptsigs.pb
B:
test-cli/open-anchor-scriptsigs B-open.pb A-open.pb <B-TXINKEY>... > B-anchor-scriptsigs.pb
test-cli/create-anchor-tx A-open.pb B-open.pb <B-CHANGEPUBKEY> <txid>/<outnum>/<amount>/<scriptsig>/<privkey>... > B-anchor.tx
STEP 3
------
Now both sides create the commitment transaction signatures which spend
the transaction output:
Send transaction ID and output number of the anchor to the other side:
A:
test-cli/open-anchor-id A-anchor.tx > A-anchor-id.pb
test-cli/open-commit-sig A-open.pb B-open.pb <A-TMPKEY> > A-commit-sig.pb
B:
test-cli/open-commit-sig B-open.pb A-open.ob <B-TMPKEY> > B-commit-sig.pb
test-cli/open-anchor-id B-anchor.tx > B-anchor-id.pb
STEP 4
------
Check the commitment signatures from the other side, and produce commit txs.
Create signatures for the other side's escape transaction(s) which
allow return of funds if something goes wrong:
A:
test-cli/open-escape-sigs A-open.pb B-open.pb B-anchor-id.pb <A-TMPKEY> <A-FINALKEY> > A-escape-sigs.pb
test-cli/check-commit-sig A-open.pb B-open.pb B-commit-sig.pb <A-TMPKEY> > A-commit-0.tx
B:
test-cli/check-commit-sig B-open.pb A-open.pb A-commit-sig.pb <B-TMPKEY> > B-commit-0.tx
test-cli/open-escape-sigs B-open.pb A-open.pb A-anchor-id.pb <B-TMPKEY> <B-FINALKEY> > B-escape-sigs.pb
STEP 5
------
Check the anchor signatures from the other side, and use them to generate the
anchor transaction (as a hex string, suitable for bitcoind).
Check the escape signatures from the other side, and use them to create our
escape txs.
A:
test-cli/create-escape A-open.pb B-open.pb A-anchor-id.pb B-escape-sigs.pb <A-FINALKEY> > A-escape.tx
test-cli/create-escape --fast A-open.pb B-open.pb A-anchor-id.pb B-escape-sigs.pb <A-FINALKEY> > A-fast-escape.tx
test-cli/check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb > A-anchor.tx
B:
test-cli/create-escape B-open.pb A-open.pb B-anchor-id.pb A-escape-sigs.pb <B-FINALKEY> > B-escape.tx
test-cli/create-escape --fast B-open.pb A-open.pb B-anchor-id.pb A-escape-sigs.pb <B-FINALKEY> > B-fast-escape.tx
test-cli/check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb > B-anchor.tx
STEP 6
------
Now both sides create the commitment transaction signatures which spend
the anchors outputs:
They should be identical:
A:
test-cli/open-commit-sig A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb <A-TMPKEY> > A-commit-sig.pb
B:
cmp A-anchor.tx B-anchor.tx || echo FAIL
test-cli/open-commit-sig B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb <B-TMPKEY> > B-commit-sig.pb
STEP 6
STEP 7
------
Check the commitment signatures from the other side, and produce commit txs.
A:
test-cli/check-commit-sig A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb B-commit-sig.pb <A-TMPKEY> > A-commit-0.tx
B:
test-cli/check-commit-sig B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-commit-sig.pb <B-TMPKEY> > B-commit-0.tx
STEP 8
------
Broadcast the anchor transaction:
Broadcast the anchor transactions (note they contain their inputs amounts
separated by colons for internal use: the daemon only wants the raw transaction):
Either one:
A:
alpha-cli -regtest -testnet=0 sendrawtransaction `cut -d: -f1 A-anchor.tx` > A-anchor.txid
alpha-cli -regtest -testnet=0 sendrawtransaction `cat A-anchor.tx` > anchor.txid
B:
alpha-cli -regtest -testnet=0 sendrawtransaction `cut -d: -f1 B-anchor.tx` > B-anchor.txid
Generate blocks until we have enough confirms (I don't do this, so I
can reset the entire state by restarting bitcoind with `-zapwallettxes=1`):
A:
while [ 0$(alpha-cli -regtest -testnet=0 getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(test-cli/get-anchor-depth A-open.pb) ]; do scripts/generate-block.sh; done
while [ 0$(alpha-cli -regtest -testnet=0 getrawtransaction $(cat B-anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(test-cli/get-anchor-depth A-open.pb) ]; do scripts/generate-block.sh; done
B:
while [ 0$(alpha-cli -regtest -testnet=0 getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(test-cli/get-anchor-depth B-open.pb) ]; do scripts/generate-block.sh; done
while [ 0$(alpha-cli -regtest -testnet=0 getrawtransaction $(cat A-anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $(test-cli/get-anchor-depth B-open.pb) ]; do scripts/generate-block.sh; done
Using a Generalized Channel
===========================
@ -149,19 +167,19 @@ revocation hash for the new tx:
B:
test-cli/update-channel-accept <B-SEED> B-anchor.tx B-open.pb A-open.pb <B-TMPKEY> A-update-1.pb > B-update-accept-1.pb
test-cli/update-channel-accept <B-SEED> B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb <B-TMPKEY> A-update-1.pb > B-update-accept-1.pb
A completes its side by signing the new tx, and revoking the old:
A:
test-cli/update-channel-signature <A_SEED> A-anchor.tx A-open.pb B-open.pb <A-TMPKEY> A-update-1.pb B-update-accept-1.pb > A-update-sig-1.pb
test-cli/update-channel-signature <A_SEED> A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb <A-TMPKEY> A-update-1.pb B-update-accept-1.pb > A-update-sig-1.pb
B now revokes its old tx:
B:
test-cli/update-channel-complete <B_SEED> B-anchor.tx B-open.pb A-open.pb A-update-1.pb A-update-sig-1.pb > B-update-complete-1.pb
test-cli/update-channel-complete <B_SEED> B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-update-1.pb A-update-sig-1.pb > B-update-complete-1.pb
B checks that the commit tx is indeed revoked.
@ -178,7 +196,7 @@ since the initial tx (here we just have one, A-update-1.pb):
A:
test-cli/create-commit-tx A-anchor.tx A-open.pb B-open.pb A-update-1.pb B-update-accept-1.pb <A-TMPKEY> > A-commit-1.tx
test-cli/create-commit-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb A-update-1.pb B-update-accept-1.pb <A-TMPKEY> > A-commit-1.tx
Special Effects: Trying To Cheat
================================
@ -187,7 +205,7 @@ A now tries to spend an old (revoked) commitment tx:
A:
test-cli/create-commit-tx A-anchor.tx A-open.pb B-open.pb <A-TMPKEY> B-commit-sig.pb > commit-0.tx
test-cli/create-commit-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb <A-TMPKEY> B-commit-sig.pb > commit-0.tx
A:
@ -235,20 +253,20 @@ reflect the final commitment total:
A:
./close-channel A-anchor.tx A-open.pb B-open.pb <A-TMPKEY> A-update-1.pb > A-close.pb
./close-channel A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb <A-TMPKEY> A-update-1.pb > A-close.pb
B:
./close-channel --complete A-anchor.tx B-open.pb A-open.pb <B-TMPKEY> A-update-1.pb > B-close-accept.pb
./close-channel --complete B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb <B-TMPKEY> A-update-1.pb > B-close-accept.pb
Both ends have both signatures now, so either can create the close tx:
A:
./create-close-tx A-anchor.tx A-open.pb B-open.pb A-close.pb B-close-accept.pb > A-close.tx
./create-close-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb A-close.pb B-close-accept.pb > A-close.tx
B:
./create-close-tx A-anchor.tx B-open.pb A-open.pb A-close.pb B-close-accept.pb > B-close.tx
./create-close-tx B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-close.pb B-close-accept.pb > B-close.tx
They should be identical:

61
test-cli/check-anchor-scriptsigs.c

@ -1,61 +0,0 @@
#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/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 <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;
size_t *inmap, *outmap;
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);
if (!bitcoin_tx_write(STDOUT_FILENO, anchor))
err(1, "Writing out anchor transaction");
tal_free(ctx);
return 0;
}

104
test-cli/check-commit-sig.c

@ -21,82 +21,90 @@ int main(int argc, char *argv[])
{
const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
OpenCommitSig *cs2;
struct bitcoin_tx *anchor, *commit;
struct sha256_double txid;
u8 *subscript;
size_t *inmap, *outmap;
struct pubkey pubkey1, pubkey2;
struct bitcoin_signature sig1, sig2;
AnchorSpend mysigs = ANCHOR_SPEND__INIT;
struct bitcoin_tx *commit;
struct sha256_double anchor_txid1, anchor_txid2;
struct pubkey pubkey1, pubkey2, final1, final2;
struct signature sigs[2];
struct privkey privkey;
bool testnet;
struct sha256 rhash;
struct sha256 rhash, escape_hash1, escape_hash2;
size_t inmap[2];
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>\n"
"<open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-file2> <commit-sig-2> <commit-key1>\n"
"Output the commitment transaction if both signatures are valid",
"Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 5)
opt_usage_exit_fail("Expected 4 arguments");
if (argc != 7)
opt_usage_exit_fail("Expected 6 arguments");
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
cs2 = pkt_from_file(argv[3], PKT__PKT_OPEN_COMMIT_SIG)->open_commit_sig;
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]);
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
cs2 = pkt_from_file(argv[5], PKT__PKT_OPEN_COMMIT_SIG)->open_commit_sig;
if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[6]);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]);
errx(1, "Private key '%s' not on testnet!", argv[6]);
/* 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, &txid);
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid open-2 key");
if (!proto_to_pubkey(o2->final, &final2))
errx(1, "Invalid o2 final pubkey");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
/* Now create our commitment tx. */
proto_to_sha256(o1->revocation_hash, &rhash);
commit = create_commit_tx(ctx, o1, o2, &rhash, 0, &txid, outmap[0]);
commit = create_commit_tx(ctx, o1, o2, &rhash, 0,
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
/* 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->total_input,
(long long)o2->total_input,
(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);
/* Check they signed out anchor inputs correctly. */
if (!check_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey2, cs2->sigs))
errx(1, "Bad signature");
if (!sign_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &privkey, sigs))
errx(1, "Could not sign tx");
/* populate_anchor_inscripts wants args in protobuf */
mysigs.sig0 = signature_to_proto(ctx, &sigs[0]);
mysigs.sig1 = signature_to_proto(ctx, &sigs[1]);
/* Shouldn't fail, since we checked them in check_anchor_spend */
if (!populate_anchor_inscripts(commit, commit, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&mysigs,
cs2->sigs))
errx(1, "Malformed signatures");
/* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, commit))

92
test-cli/close-channel.c

@ -23,16 +23,17 @@ 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;
OpenAnchor *oa1, *oa2;
struct sha256_double anchor_txid1, anchor_txid2;
struct bitcoin_tx *close_tx;
struct sha256 escape_hash1, escape_hash2;
struct pkt *pkt;
struct signature sig;
struct signature sigs[2];
struct privkey privkey;
bool testnet, complete = false;
struct pubkey pubkey1, pubkey2;
u8 *redeemscript;
struct pubkey pubkey1, pubkey2, final1, final2;
int64_t delta;
size_t i, anchor_out;
size_t i, inmap[2];
err_set_progname(argv[0]);
@ -40,61 +41,82 @@ int main(int argc, char *argv[])
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"
"<open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-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");
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;
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]);
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[4]);
bitcoin_txid(anchor, &anchor_txid);
errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Get delta by accumulting all the updates. */
delta = 0;
for (i = 5; i < argc; i++) {
for (i = 6; 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))
if (!proto_to_pubkey(o1->commitkey, &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))
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 commit pubkey");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
if (!proto_to_pubkey(o2->final, &final2))
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 */
anchor_out = find_p2sh_out(anchor, redeemscript);
/* Now create the close tx to spend 2/2 outputs of anchors. */
close_tx = create_close_tx(ctx, o1, o2, complete ? -delta : delta,
&anchor_txid,
anchor->output[anchor_out].amount,
anchor_out);
/* Sign it for them. */
sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript),
&privkey, &pubkey1, &sig);
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
warnx("input[0].txid = %02x%02x%02x%02x...",
close_tx->input[0].txid.sha.u.u8[0],
close_tx->input[0].txid.sha.u.u8[1],
close_tx->input[0].txid.sha.u.u8[2],
close_tx->input[0].txid.sha.u.u8[3]);
warnx("input[1].txid = %02x%02x%02x%02x...",
close_tx->input[1].txid.sha.u.u8[0],
close_tx->input[1].txid.sha.u.u8[1],
close_tx->input[1].txid.sha.u.u8[2],
close_tx->input[1].txid.sha.u.u8[3]);
warnx("input %zu should be %02x%02x%02x%02x...",
inmap[0],
anchor_txid1.sha.u.u8[0],
anchor_txid1.sha.u.u8[1],
anchor_txid1.sha.u.u8[2],
anchor_txid1.sha.u.u8[3]);
/* Sign close. */
if (!sign_anchor_spend(close_tx, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &privkey, sigs))
errx(1, "Failed creating signatures");
if (complete)
pkt = close_channel_complete_pkt(ctx, &sig);
pkt = close_channel_complete_pkt(ctx, sigs);
else
pkt = close_channel_pkt(ctx, &sig);
pkt = close_channel_pkt(ctx, sigs);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");

188
test-cli/create-anchor-tx.c

@ -0,0 +1,188 @@
#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/privkey.h"
#include "bitcoin/shadouble.h"
#include "protobuf_convert.h"
#include <unistd.h>
#include <time.h>
#include "opt_bits.h"
struct input {
struct bitcoin_tx_input in;
struct privkey privkey;
struct pubkey pubkey;
struct bitcoin_signature sig;
};
static void parse_anchor_input(const char *spec, struct input *in)
{
const char *slash;
char *end;
long l;
bool testnet;
slash = strchr(spec, '/');
if (!slash)
errx(1, "Expected / in <txid>/<num>/<satoshis>/<hexscript>/<privkey>");
if (!bitcoin_txid_from_hex(spec, slash - spec, &in->in.txid))
errx(1, "Expected 256-bit hex txid before /");
in->in.index = l = strtol(slash + 1, &end, 10);
if (end == slash + 1 || *end != '/' || (int64_t)in->in.index != (int64_t)l)
errx(1, "Expected <outputnum> after /");
slash = end;
in->in.input_amount = l = strtol(slash + 1, &end, 10);
if (end == slash + 1 || *end != '/' || (int64_t)in->in.input_amount != (int64_t)l)
errx(1, "Expected <satoshis> after second /");
slash = end;
end = (char *)slash + 1 + strcspn(slash + 1, "/");
in->in.script_length = hex_data_size(end - (slash + 1));
in->in.script = tal_arr(in, u8, in->in.script_length);
if (!hex_decode(slash + 1, end - (slash + 1),
in->in.script, in->in.script_length))
errx(1, "Expected hex string after third /");
if (*end != '/')
errx(1, "Expected / after hexscript");
if (!key_from_base58(end+1, strlen(end + 1), &testnet,
&in->privkey, &in->pubkey))
errx(1, "Invalid private key '%s'", end+1);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", end+1);
}
/* Create an anchor transaction which pays to the commit/escape 2of2 script. */
int main(int argc, char *argv[])
{
const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2;
size_t i;
u64 anchor_fee, total_in, change;
struct input *in;
u8 *redeemscript;
struct pubkey ourkey, their_commit_key, their_escape_key;
struct sha256 escape_hash;
struct bitcoin_tx *anchor;
err_set_progname(argv[0]);
/* Default values. */
anchor_fee = 10000;
opt_register_noarg("--help|-h", opt_usage_and_exit,
"<our-open.pb> <their-open.pb> <change-pubkey> <txid>/<outnum>/<satoshis>/<script-in-hex>/<privkey>...\n"
"A test program to create an anchor transaction 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_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 5)
opt_usage_exit_fail("Expected 4 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(o2->final, &their_escape_key)
|| !proto_to_pubkey(o1->commitkey, &ourkey)
|| !proto_to_pubkey(o2->commitkey, &their_commit_key))
errx(1, "Invalid key");
proto_to_sha256(o1->escape_hash, &escape_hash);
in = tal_arr(ctx, struct input, argc - 4);
total_in = 0;
for (i = 0; i < tal_count(in); i++) {
parse_anchor_input(argv[4+i], &in[i]);
total_in += in[i].in.input_amount;
}
if (total_in < o1->total_input + anchor_fee)
errx(1, "Only %llu satoshi in, and %llu out (+%llu fee)",
(unsigned long long)total_in,
(unsigned long long)o1->total_input,
(unsigned long long)anchor_fee);
change = total_in - (o1->total_input + 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;
redeemscript = bitcoin_redeem_anchor(ctx,
&ourkey, &their_commit_key,
&their_escape_key,
&escape_hash);
/* Set up outputs. */
anchor->output[0].amount = o1->total_input;
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[3], &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;
}

97
test-cli/create-close-tx.c

@ -21,75 +21,80 @@ 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;
OpenAnchor *oa1, *oa2;
struct bitcoin_tx *close_tx;
struct sha256_double anchor_txid1, anchor_txid2;
struct sha256 escape_hash1, escape_hash2;
struct pubkey pubkey1, pubkey2, final1, final2;
CloseChannel *close;
CloseChannelComplete *closecomplete;
size_t i, anchor_out;
size_t i, inmap[2];
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"
"<open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-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");
if (argc < 7)
opt_usage_exit_fail("Expected 6+ 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);
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
close = pkt_from_file(argv[5], PKT__PKT_CLOSE)->close;
closecomplete = pkt_from_file(argv[6], PKT__PKT_CLOSE_COMPLETE)->close_complete;
/* 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");
if (!proto_to_pubkey(o1->commitkey, &pubkey1))
errx(1, "Invalid open-1 key");
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid open-2 key");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
if (!proto_to_pubkey(o2->final, &final2))
errx(1, "Invalid o2 final pubkey");
/* Get delta by accumulting all the updates. */
delta = 0;
for (i = 6; i < argc; i++) {
for (i = 7; 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. */
anchor_out = find_p2sh_out(anchor, redeemscript);
close_tx = create_close_tx(ctx, o1, o2, delta, &anchor_txid,
anchor->output[anchor_out].amount,
anchor_out);
/* 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);
close_tx = create_close_tx(ctx, o1, o2, delta,
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
if (!check_anchor_spend(close_tx, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, close->sigs))
errx(1, "Close signature check failed");
if (!check_anchor_spend(close_tx, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey2, closecomplete->sigs))
errx(1, "Closecomplete signature check failed");
if (!populate_anchor_inscripts(close_tx, close_tx, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
close->sigs,
closecomplete->sigs))
errx(1, "Malformed signatures");
/* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, close_tx))

1
test-cli/create-commit-spend-tx.c

@ -6,7 +6,6 @@
#include <ccan/err/err.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"

111
test-cli/create-commit-tx.c

@ -23,100 +23,119 @@ int main(int argc, char *argv[])
{
const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
Pkt *pkt;
struct bitcoin_tx *anchor, *commit;
struct sha256_double anchor_txid;
AnchorSpend mysigs = ANCHOR_SPEND__INIT;
struct bitcoin_tx *commit;
struct sha256_double anchor_txid1, anchor_txid2;
struct sha256 escape_hash1, escape_hash2;
struct privkey privkey;
bool testnet;
struct bitcoin_signature sig1, sig2;
size_t i;
struct pubkey pubkey1, pubkey2;
u8 *redeemscript;
struct signature sigs[2];
AnchorSpend *their_sigs;
size_t i, inmap[2];
struct pubkey pubkey1, pubkey2, final1, final2;
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> <commit-privkey> [final-update-accept|open-commit-sig] [<updates>]\n"
"<open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-file2> <commit-privkey> [final-update-accept|open-commit-sig] [<updates>]\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");
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;
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]);
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[4]);
errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2))
errx(1, "Invalid o1 anchor pubkey");
if (!proto_to_pubkey(o1->commitkey, &pubkey2))
errx(1, "Invalid o1 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");
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 pubkey");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
if (!proto_to_pubkey(o2->final, &final2))
errx(1, "Invalid o2 final pubkey");
/* Their signature comes from open-commit or from update-accept. */
sig2.stype = SIGHASH_ALL;
pkt = any_pkt_from_file(argv[5]);
pkt = any_pkt_from_file(argv[6]);
switch (pkt->pkt_case) {
case PKT__PKT_UPDATE_ACCEPT:
if (!proto_to_signature(pkt->update_accept->sig, &sig2.sig))
errx(1, "Invalid update-accept sig");
their_sigs = pkt->update_accept->sigs;
break;
case PKT__PKT_OPEN_COMMIT_SIG:
if (!proto_to_signature(pkt->open_commit_sig->sig, &sig2.sig))
errx(1, "Invalid open-commit-sig sig");
their_sigs = pkt->open_commit_sig->sigs;
break;
default:
errx(1, "Unexpected packet type %u in %s",
pkt->pkt_case, argv[5]);
pkt->pkt_case, argv[6]);
}
/* Initial revocation hash comes from open. */
proto_to_sha256(o1->revocation_hash, &rhash);
delta = 0;
/* Figure out cumulative delta since anchor, update revocation hash */
for (i = 6; i < argc; i++) {
/* Figure out cumulative delta since anchors, update revocation hash */
for (i = 7; i < argc; i++) {
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta;
proto_to_sha256(u->revocation_hash, &rhash);
}
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
/* Now create commitment tx to spend 2/2 output of anchor. */
commit = create_commit_tx(ctx, o1, o2, &rhash, delta, &anchor_txid,
find_p2sh_out(anchor, redeemscript));
/* Now create commitment tx to spend 2/2 outputs of anchors. */
commit = create_commit_tx(ctx, o1, o2, &rhash, delta,
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
/* 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);
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);
if (!check_anchor_spend(commit, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey2, their_sigs))
errx(1, "Bad signatures");
/* We generate our signatures. */
if (!sign_anchor_spend(commit, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &privkey, sigs))
errx(1, "Could not create signatures");
/* populate_anchor_inscripts wants args in protobuf */
mysigs.sig0 = signature_to_proto(ctx, &sigs[0]);
mysigs.sig1 = signature_to_proto(ctx, &sigs[1]);
/* Shouldn't fail, since we checked them in check_anchor_spend */
if (!populate_anchor_inscripts(commit, commit, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&mysigs, their_sigs))
errx(1, "Malformed signatures");
/* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, commit))

1
test-cli/create-steal-tx.c

@ -5,7 +5,6 @@
#include <ccan/str/hex/hex.h>
#include <ccan/err/err.h>
#include "lightning.pb-c.h"
#include "anchor.h"
#include "bitcoin/base58.h"
#include "pkt.h"
#include "bitcoin/script.h"

3
test-cli/get-anchor-depth.c

@ -5,7 +5,6 @@
#include <ccan/str/hex/hex.h>
#include <ccan/err/err.h>
#include "lightning.pb-c.h"
#include "anchor.h"
#include "bitcoin/base58.h"
#include "pkt.h"
#include "bitcoin/script.h"
@ -33,7 +32,7 @@ int main(int argc, char *argv[])
opt_usage_exit_fail("Expected one argument");
o = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
printf("%u\n", o->anchor->min_confirms);
printf("%u\n", o->min_confirms);
tal_free(ctx);
return 0;

79
test-cli/open-anchor-id.c

@ -0,0 +1,79 @@
#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/privkey.h"
#include "bitcoin/shadouble.h"
#include "protobuf_convert.h"
#include <unistd.h>
#include <time.h>
#include "opt_bits.h"
int main(int argc, char *argv[])
{
struct pkt *pkt;
const tal_t *ctx = tal_arr(NULL, char, 0);
struct bitcoin_tx *anchor;
struct sha256_double txid;
unsigned int i;
err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit,
"<anchor-tx-file> <change-key>\n"
"A test program to output open-anchor on stdout.",
"Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 3)
opt_usage_exit_fail("Expected 1 argument");
anchor = bitcoin_tx_from_file(ctx, argv[1]);
bitcoin_txid(anchor, &txid);
/* Figure out which output is for the commit tx. */
if (anchor->output_count != 1) {
u8 *script;
struct pubkey change_key;
if (!pubkey_from_hexstr(argv[2], &change_key))
errx(1, "Invalid change key %s", argv[2]);
if (anchor->output_count != 2)
errx(1, "Expected 1 or 2 outputs on anchor");
script = scriptpubkey_p2sh(anchor,
bitcoin_redeem_single(anchor,
&change_key));
for (i = 0; i < anchor->output_count; i++) {
if (anchor->output[i].script_length != tal_count(script))
continue;
if (memcmp(anchor->output[i].script, script,
tal_count(script)) == 0)
break;
}
if (i == anchor->output_count)
errx(1, "No output to change found");
/* We found change output, so we want the other one. */
i = !i;
} else
i = 0;
pkt = open_anchor_pkt(ctx, &txid, i);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");
tal_free(ctx);
return 0;
}

98
test-cli/open-anchor-scriptsigs.c

@ -1,98 +0,0 @@
#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 "bitcoin/privkey.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,
struct privkey *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;
struct privkey privkey;
bool testnet;
if (!key_from_base58(argv[3+i], strlen(argv[3+i]),
&testnet, &privkey, &pubkey))
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, pkt_totlen(pkt)))
err(1, "Writing out packet");
tal_free(ctx);
return 0;
}

114
test-cli/open-channel.c

@ -22,78 +22,34 @@
/* 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;
}
/* Simple helper to open a channel. */
int main(int argc, char *argv[])
{
struct sha256 seed, revocation_hash;
struct sha256 seed, revocation_hash, escape_secret, escape_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;
unsigned int locktime_seconds, min_confirms;
bool testnet;
size_t i;
struct pubkey commitkey, outkey, changekey;
struct pubkey commitkey, outkey;
struct privkey commitprivkey, outprivkey;
err_set_progname(argv[0]);
/* Default values. */
anchor.min_confirms = 3;
/* Remember, other side contributes to fee, too. */
anchor.fee = 5000;
min_confirms = 3;
/* 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"
"<seed> <amount> <commitprivkey> <outprivkey> <escape-secret>\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,
opt_set_uintval, opt_show_uintval, &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");
@ -103,65 +59,45 @@ int main(int argc, char *argv[])
opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 7)
opt_usage_exit_fail("Expected 6 or more arguments");
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.total = atol(argv[2]);
if (!anchor.total)
total_in = atol(argv[2]);
if (!total_in)
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. */
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet,
if (!key_from_base58(argv[3], strlen(argv[3]), &testnet,
&commitprivkey, &commitkey))
errx(1, "Invalid private key '%s'", argv[4]);
errx(1, "Invalid private key '%s'", argv[3]);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]);
errx(1, "Private key '%s' not on testnet!", argv[3]);
if (!key_from_base58(argv[5], strlen(argv[5]), &testnet,
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet,
&outprivkey, &outkey))
errx(1, "Invalid private key '%s'", argv[5]);
errx(1, "Invalid private key '%s'", argv[4]);
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;
}
errx(1, "Private key '%s' not on testnet!", argv[4]);
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);
}
if (!hex_decode(argv[5], strlen(argv[5]), &escape_secret,
sizeof(escape_secret)))
errx(1, "Invalid escape hash '%s' - need 256 hex bits", argv[5]);
/* 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, &revocation_hash, &outkey,
commit_tx_fee, locktime_seconds, &anchor);
/* Get hash from escape secret. */
sha256(&escape_hash, escape_secret.u.u8, sizeof(escape_secret.u.u8));
pkt = openchannel_pkt(ctx, &revocation_hash, &commitkey, &outkey,
commit_tx_fee, locktime_seconds, total_in,
&escape_hash, min_confirms);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");

73
test-cli/open-commit-sig.c

@ -22,67 +22,74 @@ 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;
OpenAnchor *oa1, *oa2;
struct bitcoin_tx *commit;
struct sha256 escape_hash1, escape_hash2;
struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt;
struct signature sig;
size_t *inmap, *outmap;
struct signature sigs[2];
struct privkey privkey;
bool testnet;
struct pubkey pubkey1, pubkey2;
u8 *subscript;
struct pubkey pubkey1, pubkey2, final1, final2;
struct sha256 rhash;
size_t inmap[2];
err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit,
"<open-channel-file1> <open-channel-file2> <commit-privkey>\n"
"<open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-file2> <commit-privkey>\n"
"Create the signature needed for the commit transaction",
"Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 4)
opt_usage_exit_fail("Expected 3 arguments");
if (argc != 6)
opt_usage_exit_fail("Expected 5 arguments");
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
if (!key_from_base58(argv[3], strlen(argv[3]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[3]);
proto_to_sha256(o2->escape_hash, &escape_hash2);
if (!proto_to_pubkey(o2->final, &final2))
errx(1, "Invalid o2 final pubkey");
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 commit pubkey");
oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
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[3]);
/* Create merged anchor transaction */
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap);
if (!anchor)
errx(1, "Failed transaction merge");
errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Get the transaction ID of the anchor. */
anchor_txid(anchor, &txid);
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
/* Now create THEIR commitment tx to spend 2/2 output of anchor. */
/* Now create THEIR commitment tx to spend outputs of anchors. */
proto_to_sha256(o2->revocation_hash, &rhash);
commit = create_commit_tx(ctx, o2, o1, &rhash, 0, &txid, outmap[0]);
commit = create_commit_tx(ctx, o2, o1, &rhash, 0,
&anchor_txid2, oa2->index, o2->total_input,
&anchor_txid1, oa1->index, o1->total_input,
inmap);
/* 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->total_input,
(long long)o2->total_input,
(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);
/* Since we're signing theirs, "my" and "their" args are backwards. */
if (!sign_anchor_spend(commit, inmap,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &final1, &escape_hash1,
&pubkey1, &privkey, sigs))
errx(1, "Could not sign tx");
pkt = open_commit_sig_pkt(ctx, &sig);
pkt = open_commit_sig_pkt(ctx, sigs);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");

15
test-cli/scripts/getinput.sh

@ -8,10 +8,6 @@ set -e
. `dirname $0`/vars.sh
if [ n"$1" = n--privkey ]; then
KEY=1
shift
fi
NUM=1
if [ $# = 1 ]; then
NUM=$1
@ -19,18 +15,15 @@ if [ $# = 1 ]; then
fi
if [ $# -gt 0 ]; then
echo "Usage: getinput.sh [--privkey] [INPUT-INDEX]"
echo "Usage: getinput.sh [INPUT-INDEX]"
exit 1
fi
if [ -n "$KEY" ]; then
ADDR=`$CLI listunspent | sed -n 's/^ *"address" *: *"\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1`
$CLI dumpprivkey $ADDR
else
TXID=`$CLI listunspent | sed -n 's/^ *"txid" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1`
OUTNUM=`$CLI listunspent | sed -n 's/^ *"vout" *: *\([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1`
AMOUNT=`$CLI listunspent | sed -n 's/^ *"amount" *: *\([0-9.]*\),$/\1/p' | tail -n +$NUM | head -n1 | tr -d . | sed 's/^0*//'`
SCRIPT=`$CLI listunspent | sed -n 's/^ *"scriptPubKey" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1`
ADDR=`$CLI listunspent | sed -n 's/^ *"address" *: *"\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1`
PRIVKEY=`$CLI dumpprivkey $ADDR`
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT
fi
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT/$PRIVKEY

67
test-cli/scripts/test.sh

@ -66,13 +66,14 @@ B_FINALADDR=`scripts/get-new-address.sh`
#B_FINALADDR=mvQgfEX4iMSEYqD31524jASQviPwPwpvuv
A_TXIN=`scripts/getinput.sh $A_INPUTNUM`
A_TXINKEY=`scripts/getinput.sh --privkey $A_INPUTNUM`
B_TXIN=`scripts/getinput.sh $B_INPUTNUM`
B_TXINKEY=`scripts/getinput.sh --privkey $B_INPUTNUM`
A_SEED=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
B_SEED=112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00
A_ESCSECRET=00112233445566778899aabbccddeeff00112233445566778899aabbccddeef0
B_ESCSECRET=112233445566778899aabbccddeeff00112233445566778899aabbccddeeff0f
A_CHANGEPUBKEY=`getpubkey $A_CHANGEADDR`
A_TMPKEY=`getprivkey $A_TMPADDR`
A_FINALKEY=`getprivkey $A_FINALADDR`
@ -82,56 +83,56 @@ B_TMPKEY=`getprivkey $B_TMPADDR`
B_FINALKEY=`getprivkey $B_FINALADDR`
# Both sides say what they want from channel
$PREFIX ./open-channel $A_SEED $A_AMOUNT $A_CHANGEPUBKEY $A_TMPKEY $A_FINALKEY $A_TXIN > A-open.pb
# FIXME: Use pubkeys for tmpkey and finalkey here!
$PREFIX ./open-channel $A_SEED $A_AMOUNT $A_TMPKEY $A_FINALKEY $A_ESCSECRET > A-open.pb
# B asks for a (dangerously) short locktime, for testing unilateral close.
$PREFIX ./open-channel --locktime=60 $B_SEED $B_AMOUNT $B_CHANGEPUBKEY $B_TMPKEY $B_FINALKEY $B_TXIN > B-open.pb
$PREFIX ./open-channel --locktime=60 $B_SEED $B_AMOUNT $B_TMPKEY $B_FINALKEY $B_ESCSECRET > B-open.pb
# Now sign anchor.
$PREFIX ./open-anchor-scriptsigs A-open.pb B-open.pb $A_TXINKEY > A-anchor-scriptsigs.pb
$PREFIX ./open-anchor-scriptsigs B-open.pb A-open.pb $B_TXINKEY > B-anchor-scriptsigs.pb
# Now create anchors.
$PREFIX ./create-anchor-tx A-open.pb B-open.pb $A_CHANGEPUBKEY $A_TXIN > A-anchor.tx
$PREFIX ./create-anchor-tx B-open.pb A-open.pb $B_CHANGEPUBKEY $B_TXIN > B-anchor.tx
# Now create commit signature
$PREFIX ./open-commit-sig A-open.pb B-open.pb $A_TMPKEY > A-commit-sig.pb
# Now tell the other side about it.
$PREFIX ./open-anchor-id A-anchor.tx $A_CHANGEPUBKEY > A-anchor-id.pb
$PREFIX ./open-anchor-id B-anchor.tx $B_CHANGEPUBKEY > B-anchor-id.pb
$PREFIX ./open-commit-sig B-open.pb A-open.pb $B_TMPKEY > B-commit-sig.pb
# Now create commit signature
$PREFIX ./open-commit-sig A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY > A-commit-sig.pb
$PREFIX ./open-commit-sig B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb $B_TMPKEY > B-commit-sig.pb
# Now check it.
$PREFIX ./check-commit-sig A-open.pb B-open.pb B-commit-sig.pb $A_TMPKEY > A-commit.tx
$PREFIX ./check-commit-sig B-open.pb A-open.pb A-commit-sig.pb $B_TMPKEY > B-commit.tx
# Now check anchor sigs and make sure they're the same.
$PREFIX ./check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb > A-anchor.tx
$PREFIX ./check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb > B-anchor.tx
cmp A-anchor.tx B-anchor.tx
$PREFIX ./check-commit-sig A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb B-commit-sig.pb $A_TMPKEY > A-commit.tx
$PREFIX ./check-commit-sig B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-commit-sig.pb $B_TMPKEY > B-commit.tx
# Broadcast
$CLI sendrawtransaction `cut -d: -f1 A-anchor.tx` > anchor.txid
# Broadcast anchors
$CLI sendrawtransaction `cut -d: -f1 A-anchor.tx` > A-anchor.txid
$CLI sendrawtransaction `cut -d: -f1 B-anchor.tx` > B-anchor.txid
# # Wait for confirms
# while [ 0$($CLI getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $($PREFIX ./get-anchor-depth A-open.pb) ]; do scripts/generate-block.sh; done
# while [ 0$($CLI getrawtransaction $(cat B-anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $($PREFIX ./get-anchor-depth A-open.pb) ]; do scripts/generate-block.sh; done
# while [ 0$($CLI getrawtransaction $(cat anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $($PREFIX ./get-anchor-depth B-open.pb) ]; do scripts/generate-block.sh; done
# while [ 0$($CLI getrawtransaction $(cat A-anchor.txid) 1 | sed -n 's/.*"confirmations" : \([0-9]*\),/\1/p') -lt $($PREFIX ./get-anchor-depth B-open.pb) ]; do scripts/generate-block.sh; done
# Just for testing, generate the first transaction.
$PREFIX ./create-commit-tx A-anchor.tx A-open.pb B-open.pb $A_TMPKEY B-commit-sig.pb > A-commit-0.tx
$PREFIX ./create-commit-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY B-commit-sig.pb > A-commit-0.tx
# Now, update the channel, so I pay you 500 satoshi.
$PREFIX ./update-channel --to-them=500 $A_SEED > A-update-1.pb
$PREFIX ./update-channel-accept $B_SEED B-anchor.tx B-open.pb A-open.pb $B_TMPKEY A-update-1.pb > B-update-accept-1.pb
$PREFIX ./update-channel-signature $A_SEED A-anchor.tx A-open.pb B-open.pb $A_TMPKEY A-update-1.pb B-update-accept-1.pb > A-update-sig-1.pb
$PREFIX ./update-channel-complete $B_SEED B-anchor.tx B-open.pb A-open.pb A-update-1.pb A-update-sig-1.pb > B-update-complete-1.pb
$PREFIX ./update-channel-accept $B_SEED B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb $B_TMPKEY A-update-1.pb > B-update-accept-1.pb
$PREFIX ./update-channel-signature $A_SEED A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY A-update-1.pb B-update-accept-1.pb > A-update-sig-1.pb
$PREFIX ./update-channel-complete $B_SEED B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-update-1.pb A-update-sig-1.pb > B-update-complete-1.pb
# Just for testing, generate second transaction
$PREFIX ./create-commit-tx A-anchor.tx A-open.pb B-open.pb $A_TMPKEY B-update-accept-1.pb A-update-1.pb > A-commit-1.tx
$PREFIX ./create-commit-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY B-update-accept-1.pb A-update-1.pb > A-commit-1.tx
# Now you pay me 1000.
$PREFIX ./update-channel --from-them=1000 $A_SEED A-update-1.pb > A-update-2.pb
$PREFIX ./update-channel-accept $B_SEED B-anchor.tx B-open.pb A-open.pb $B_TMPKEY A-update-2.pb A-update-1.pb > B-update-accept-2.pb 2>/dev/null
$PREFIX ./update-channel-signature $A_SEED A-anchor.tx A-open.pb B-open.pb $A_TMPKEY A-update-2.pb B-update-accept-2.pb A-update-1.pb > A-update-sig-2.pb
$PREFIX ./update-channel-complete $B_SEED B-anchor.tx B-open.pb A-open.pb A-update-2.pb A-update-sig-2.pb A-update-1.pb > B-update-complete-2.pb
$PREFIX ./update-channel-accept $B_SEED B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb $B_TMPKEY A-update-2.pb A-update-1.pb > B-update-accept-2.pb 2>/dev/null
$PREFIX ./update-channel-signature $A_SEED A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY A-update-2.pb B-update-accept-2.pb A-update-1.pb > A-update-sig-2.pb
$PREFIX ./update-channel-complete $B_SEED B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb A-update-2.pb A-update-sig-2.pb A-update-1.pb > B-update-complete-2.pb
# Just for testing, generate third transaction
$PREFIX ./create-commit-tx A-anchor.tx A-open.pb B-open.pb $A_TMPKEY B-update-accept-2.pb A-update-1.pb A-update-2.pb > A-commit-2.tx
$PREFIX ./create-commit-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY B-update-accept-2.pb A-update-1.pb A-update-2.pb > A-commit-2.tx
if [ x"$1" = x--steal ]; then
# A stupidly broadcasts a revoked transaction.
@ -152,8 +153,8 @@ if [ x"$1" = x--unilateral ]; then
fi
# Now close channel by mutual consent.
$PREFIX ./close-channel A-anchor.tx A-open.pb B-open.pb $A_TMPKEY A-update-1.pb A-update-2.pb > A-close.pb
$PREFIX ./close-channel --complete B-anchor.tx B-open.pb A-open.pb $B_TMPKEY A-update-1.pb A-update-2.pb > B-close-complete.pb
$PREFIX ./create-close-tx A-anchor.tx A-open.pb B-open.pb A-close.pb B-close-complete.pb A-update-1.pb A-update-2.pb > A-close.tx
$PREFIX ./close-channel A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb $A_TMPKEY A-update-1.pb A-update-2.pb > A-close.pb
$PREFIX ./close-channel --complete B-open.pb A-open.pb B-anchor-id.pb A-anchor-id.pb $B_TMPKEY A-update-1.pb A-update-2.pb > B-close-complete.pb
$PREFIX ./create-close-tx A-open.pb B-open.pb A-anchor-id.pb B-anchor-id.pb A-close.pb B-close-complete.pb A-update-1.pb A-update-2.pb > A-close.tx
$CLI sendrawtransaction `cut -d: -f1 A-close.tx` > close.txid

70
test-cli/update-channel-accept.c

@ -22,24 +22,24 @@
int main(int argc, char *argv[])
{
const tal_t *ctx = tal_arr(NULL, char, 0);
struct sha256 seed, revocation_hash, their_rhash;
struct sha256 seed, revocation_hash, their_rhash, escape_hash1, escape_hash2;
OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
Update *update;
struct bitcoin_tx *anchor, *commit;
struct sha256_double anchor_txid;
struct bitcoin_tx *commit;
struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt;
struct bitcoin_signature sig;
struct signature sigs[2];
struct privkey privkey;
bool testnet;
struct pubkey pubkey1, pubkey2;
u8 *redeemscript;
struct pubkey pubkey1, pubkey2, final1, final2;
int64_t delta;
size_t i, p2sh_out;
size_t i, inmap[2];
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"
"<seed> <open-channel-file1> <open-channel-file2> <anchor-id-file1> <anchor-id-file2> <commit-privkey> <update-protobuf> [previous-updates]\n"
"Accept a new update message",
"Print this message.");
@ -51,57 +51,65 @@ int main(int argc, char *argv[])
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;
if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[5]);
o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[5], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[6]);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[5]);
errx(1, "Private key '%s' not on testnet!", argv[6]);
update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update;
update = pkt_from_file(argv[7], PKT__PKT_UPDATE)->update;
/* Figure out cumulative delta since anchor. */
delta = update->delta;
for (i = 7; i < argc; i++) {
for (i = 8; 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);
shachain_from_seed(&seed, argc - 7, &revocation_hash);
sha256(&revocation_hash,
revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
/* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2))
if (!proto_to_pubkey(o1->commitkey, &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))
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 commit pubkey");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
if (!proto_to_pubkey(o2->final, &final2))
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. */
/* Now create THEIR new commitment tx to spend 2/2 outputs of anchors. */
proto_to_sha256(update->revocation_hash, &their_rhash);
commit = create_commit_tx(ctx, o2, o1, &their_rhash, delta,
&anchor_txid, p2sh_out);
&anchor_txid2, oa2->index, o2->total_input,
&anchor_txid1, oa1->index, o1->total_input,
inmap);
/* 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);
/* Sign it for them (since its theirs, reverse args). */
if (!sign_anchor_spend(commit, inmap, &pubkey2, &final2, &escape_hash2,
&pubkey1, &final1, &escape_hash1,
&pubkey1, &privkey, sigs))
errx(1, "Failed creating signatures");
pkt = update_accept_pkt(ctx, &sig.sig, &revocation_hash);
pkt = update_accept_pkt(ctx, sigs, &revocation_hash);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");

64
test-cli/update-channel-complete.c

@ -24,45 +24,49 @@ 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;
OpenAnchor *oa1, *oa2;
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;
struct bitcoin_tx *commit;
struct pubkey pubkey1, pubkey2, final1, final2;
size_t i, num_updates, inmap[2];
struct sha256_double anchor_txid1, anchor_txid2;
struct sha256 escape_hash1, escape_hash2;
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"
"<seed> <open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-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 (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;
update = pkt_from_file(argv[5], PKT__PKT_UPDATE)->update;
us = pkt_from_file(argv[6], PKT__PKT_UPDATE_SIGNATURE)->update_signature;
o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[5], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
update = pkt_from_file(argv[6], PKT__PKT_UPDATE)->update;
us = pkt_from_file(argv[7], 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++) {
for (i = 8; i < argc; i++) {
Pkt *p = any_pkt_from_file(argv[i]);
switch (p->pkt_case) {
case PKT__PKT_UPDATE:
@ -89,30 +93,30 @@ int main(int argc, char *argv[])
errx(1, "Their preimage was incorrect");
/* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1))
if (!proto_to_pubkey(o1->commitkey, &pubkey1))
errx(1, "Invalid o1 commit pubkey");
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2))
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o2 final pubkey");
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 commit pubkey");
if (!proto_to_pubkey(o2->final, &final2))
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);
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
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.");
if (!check_anchor_spend(commit, inmap,
&pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey2, us->sigs))
errx(1, "Bad signatures");
/* Hand over our preimage for previous tx. */
shachain_from_seed(&seed, num_updates, &preimage);

97
test-cli/update-channel-signature.c

@ -22,107 +22,110 @@
int main(int argc, char *argv[])
{
const tal_t *ctx = tal_arr(NULL, char, 0);
struct sha256 seed, revocation_hash, preimage;
struct sha256 seed, revocation_hash, preimage,
escape_hash1, escape_hash2;
OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
UpdateAccept *ua;
Update *update;
struct bitcoin_tx *anchor, *commit;
struct sha256_double anchor_txid;
struct bitcoin_tx *commit;
struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt;
struct bitcoin_signature sig;
struct signature sigs[2];
struct privkey privkey;
bool testnet;
struct pubkey pubkey1, pubkey2;
u8 *redeemscript;
struct pubkey pubkey1, pubkey2, final1, final2;
int64_t delta;
size_t i, p2sh_out;
size_t i, inmap[2];
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"
"<seed> <open-channel-file1> <open-channel-file2> <open-anchor-file1> <open-anchor-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 (argc < 9)
opt_usage_exit_fail("Expected 8+ 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;
if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[5]);
o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
proto_to_sha256(o1->escape_hash, &escape_hash1);
o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
proto_to_sha256(o2->escape_hash, &escape_hash2);
oa1 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[5], PKT__PKT_OPEN_ANCHOR)->open_anchor;
proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[6]);
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;
errx(1, "Private key '%s' not on testnet!", argv[6]);
sig.stype = SIGHASH_ALL;
if (!proto_to_signature(ua->sig, &sig.sig))
errx(1, "Invalid update signature");
update = pkt_from_file(argv[7], PKT__PKT_UPDATE)->update;
ua = pkt_from_file(argv[8], PKT__PKT_UPDATE_ACCEPT)->update_accept;
/* Figure out cumulative delta since anchor. */
delta = 0;
for (i = 8; i < argc; i++) {
for (i = 9; 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);
shachain_from_seed(&seed, argc - 8 - 1, &preimage);
/* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2))
if (!proto_to_pubkey(o1->commitkey, &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))
if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid o2 commit pubkey");
if (!proto_to_pubkey(o1->final, &final1))
errx(1, "Invalid o1 final pubkey");
if (!proto_to_pubkey(o2->final, &final2))
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);
&anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
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.");
/* Check their signatures sign this input correctly. */
if (!check_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey2, ua->sigs))
errx(1, "Invalid signatures");
/* 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));
&anchor_txid2, oa2->index, o2->total_input,
&anchor_txid1, oa1->index, o1->total_input,
inmap);
/* 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);
/* Sign it for them (since its theirs, reverse args). */
if (!sign_anchor_spend(commit, inmap, &pubkey2, &final2, &escape_hash2,
&pubkey1, &final1, &escape_hash1,
&pubkey1, &privkey, sigs))
errx(1, "Failed creating signatures");
pkt = update_signature_pkt(ctx, &sig.sig, &preimage);
pkt = update_signature_pkt(ctx, sigs, &preimage);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet");

1
test-cli/update-channel.c

@ -6,7 +6,6 @@
#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"

Loading…
Cancel
Save