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>
This commit is contained in:
Rusty Russell
2015-07-24 16:00:10 +09:30
parent 11099d738f
commit c03c878afc
33 changed files with 1644 additions and 1623 deletions

2
.gitignore vendored
View File

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

View File

@@ -8,7 +8,7 @@ FEATURES := -DHAS_CSV=1 -DALPHA_TXSTYLE=1 -DUSE_SCHNORR=1
# Bitcoin uses DER for signatures # Bitcoin uses DER for signatures
#FEATURES := -DSCRIPTS_USE_DER #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 BITCOIN_OBJS := bitcoin/address.o bitcoin/base58.o bitcoin/pubkey.o bitcoin/script.o bitcoin/shadouble.o bitcoin/signature.o bitcoin/tx.o

335
anchor.c
View File

@@ -1,165 +1,200 @@
#include <ccan/err/err.h>
#include "anchor.h" #include "anchor.h"
#include "bitcoin/pubkey.h"
#include "bitcoin/script.h" #include "bitcoin/script.h"
#include "bitcoin/tx.h"
#include "overflows.h"
#include "permute_tx.h"
#include "pkt.h"
#include "protobuf_convert.h" #include "protobuf_convert.h"
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx, #undef DEBUG
const OpenChannel *o1, #ifdef DEBUG
const OpenChannel *o2, #include <stdio.h>
size_t **inmapp, size_t **outmapp) #include "bitcoin/pubkey.h"
{
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)) static void dump_anchor_spend(const char *what,
return NULL; size_t input,
const struct pubkey *commitkey1,
n_out = 1 + !!o1->anchor->change + !!o2->anchor->change; const struct pubkey *commitkey2,
tx = bitcoin_tx(ctx, o1->anchor->n_inputs+o2->anchor->n_inputs, n_out); const struct pubkey *finalkey,
const struct sha256 *escapehash,
/* Override version to use lesser of two versions. */ const struct pubkey *signingkey,
if (o1->tx_version < o2->tx_version) const struct signature *sig)
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. */
}
/* 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;
}
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;
}
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;
}
/* 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)
{ {
size_t i; 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");
}
#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)
{
}
#endif
if (ssigs1->n_script + ssigs2->n_script != anchor->input_count) bool sign_anchor_spend(struct bitcoin_tx *tx,
return NULL; 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;
for (i = 0; i < ssigs1->n_script; i++) { /* Sign input for our anchor. */
size_t n = inmap[i]; redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey,
anchor->input[n].script = ssigs1->script[i].data; their_finalkey, my_escapehash);
anchor->input[n].script_length = ssigs1->script[i].len; 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;
} }
for (i = 0; i < ssigs2->n_script; i++) { /* Check that their sigs sign this tx as expected. */
size_t n = inmap[ssigs1->n_script + i]; bool check_anchor_spend(struct bitcoin_tx *tx,
anchor->input[n].script = ssigs2->script[i].data; const size_t inmap[2],
anchor->input[n].script_length = ssigs2->script[i].len; 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)
{
const tal_t *ctx;
u8 *redeemscript;
bool ret;
struct bitcoin_signature sigs[2];
sigs[0].stype = sigs[1].stype = SIGHASH_ALL;
if (!proto_to_signature(their_sigs->sig0, &sigs[0].sig)
|| !proto_to_signature(their_sigs->sig1, &sigs[1].sig))
return false;
ctx = tal(NULL, char);
/* 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;
} }
/* 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)
{
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; return true;
} }
void anchor_txid(struct bitcoin_tx *anchor, struct sha256_double *txid)
{
bitcoin_txid(anchor, txid);
}

View File

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

View File

@@ -11,22 +11,27 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
OpenChannel *ours, OpenChannel *ours,
OpenChannel *theirs, OpenChannel *theirs,
int64_t delta, int64_t delta,
const struct sha256_double *anchor_txid, const struct sha256_double *anchor_txid1,
uint64_t input_amount, unsigned int index1, uint64_t input_amount1,
unsigned int anchor_output) const struct sha256_double *anchor_txid2,
unsigned int index2, uint64_t input_amount2,
size_t inmap[2])
{ {
struct bitcoin_tx *tx; struct bitcoin_tx *tx;
const u8 *redeemscript; const u8 *redeemscript;
struct pubkey ourkey, theirkey; struct pubkey ourkey, theirkey;
struct sha256 redeem; struct sha256 redeem;
/* Now create close tx: one input, two outputs. */ /* Now create close tx: two inputs, two outputs. */
tx = bitcoin_tx(ctx, 1, 2); tx = bitcoin_tx(ctx, 2, 2);
/* Our input spends the anchor tx output. */ /* Our inputs spend the anchor tx outputs. */
tx->input[0].txid = *anchor_txid; tx->input[0].txid = *anchor_txid1;
tx->input[0].index = anchor_output; tx->input[0].index = index1;
tx->input[0].input_amount = input_amount; 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 */ /* Outputs goes to final pubkey */
if (!proto_to_pubkey(ours->final, &ourkey)) 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); return tal_free(tx);
/* delta must make sense. */ /* 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); 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); return tal_free(tx);
proto_to_sha256(ours->revocation_hash, &redeem); proto_to_sha256(ours->revocation_hash, &redeem);
/* One output is to us. */ /* 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); redeemscript = bitcoin_redeem_single(tx, &ourkey);
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript); tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script); tx->output[0].script_length = tal_count(tx->output[0].script);
/* Other output is to them. */ /* 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); redeemscript = bitcoin_redeem_single(tx, &theirkey);
tx->output[1].script = scriptpubkey_p2sh(tx, redeemscript); tx->output[1].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[1].script_length = tal_count(tx->output[1].script); tx->output[1].script_length = tal_count(tx->output[1].script);
tx->fee = ours->commitment_fee + theirs->commitment_fee; tx->fee = ours->commitment_fee + theirs->commitment_fee;
permute_inputs(tx->input, 2, inmap);
permute_outputs(tx->output, 2, NULL); permute_outputs(tx->output, 2, NULL);
return tx; return tx;
} }

View File

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

View File

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

View File

@@ -6,13 +6,16 @@
struct sha256_double; struct sha256_double;
struct sha256; 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. */ * input scriptsig. */
struct bitcoin_tx *create_commit_tx(const tal_t *ctx, struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
OpenChannel *ours, OpenChannel *ours,
OpenChannel *theirs, OpenChannel *theirs,
const struct sha256 *revocation_hash, const struct sha256 *revocation_hash,
int64_t delta, int64_t delta,
const struct sha256_double *anchor_txid, const struct sha256_double *anchor_txid1,
unsigned int anchor_output); 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 #endif

File diff suppressed because it is too large Load Diff

View File

@@ -17,13 +17,12 @@ PROTOBUF_C__BEGIN_DECLS
typedef struct _Sha256Hash Sha256Hash; typedef struct _Sha256Hash Sha256Hash;
typedef struct _Signature Signature; typedef struct _Signature Signature;
typedef struct _BitcoinInput BitcoinInput; typedef struct _AnchorSpend AnchorSpend;
typedef struct _BitcoinPubkey BitcoinPubkey; typedef struct _BitcoinPubkey BitcoinPubkey;
typedef struct _Change Change;
typedef struct _Anchor Anchor;
typedef struct _OpenChannel OpenChannel; typedef struct _OpenChannel OpenChannel;
typedef struct _OpenAnchor OpenAnchor;
typedef struct _OpenEscapeSigs OpenEscapeSigs;
typedef struct _OpenCommitSig OpenCommitSig; typedef struct _OpenCommitSig OpenCommitSig;
typedef struct _OpenAnchorScriptsigs OpenAnchorScriptsigs;
typedef struct _OpenComplete OpenComplete; typedef struct _OpenComplete OpenComplete;
typedef struct _Update Update; typedef struct _Update Update;
typedef struct _UpdateAccept UpdateAccept; 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; 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; Signature *sig1;
/*
* And the subscript we're signing.
*/
ProtobufCBinaryData subscript;
/*
* The amount this input is worth.
*/
uint64_t amount;
}; };
#define BITCOIN_INPUT__INIT \ #define ANCHOR_SPEND__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&bitcoin_input__descriptor) \ { PROTOBUF_C_MESSAGE_INIT (&anchor_spend__descriptor) \
, NULL, 0, {0,NULL}, 0 } , NULL, NULL }
/* /*
@@ -117,57 +109,6 @@ struct _BitcoinPubkey
, {0,NULL} } , {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 { typedef enum {
OPEN_CHANNEL__LOCKTIME__NOT_SET = 0, OPEN_CHANNEL__LOCKTIME__NOT_SET = 0,
OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS = 2, OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS = 2,
@@ -185,7 +126,7 @@ struct _OpenChannel
*/ */
Sha256Hash *revocation_hash; 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; BitcoinPubkey *final;
/* /*
@@ -193,13 +134,21 @@ struct _OpenChannel
*/ */
uint64_t commitment_fee; uint64_t commitment_fee;
/* /*
* The anchor transaction details. * Key for commitment tx 2of2.
*/ */
Anchor *anchor; BitcoinPubkey *commitkey;
/* /*
* Maximum transaction version we support. * How much we'll be putting into channel
*/ */
uint32_t tx_version; uint64_t total_input;
/*
* Secret hash for escape transactions.
*/
Sha256Hash *escape_hash;
/*
* How many confirmations on anchor before we'll use channel.
*/
uint32_t min_confirms;
OpenChannel__LocktimeCase locktime_case; OpenChannel__LocktimeCase locktime_case;
union { union {
uint32_t locktime_seconds; uint32_t locktime_seconds;
@@ -208,36 +157,59 @@ struct _OpenChannel
}; };
#define OPEN_CHANNEL__INIT \ #define OPEN_CHANNEL__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_channel__descriptor) \ { 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 _OpenAnchor
{
ProtobufCMessage base;
Sha256Hash *anchor_txid;
/*
* Which output of anchor goes to this.
*/
uint32_t index;
};
#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 signatures for commitment tx
*/ */
struct _OpenCommitSig struct _OpenCommitSig
{ {
ProtobufCMessage base; ProtobufCMessage base;
Signature *sig; AnchorSpend *sigs;
}; };
#define OPEN_COMMIT_SIG__INIT \ #define OPEN_COMMIT_SIG__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_commit_sig__descriptor) \ { PROTOBUF_C_MESSAGE_INIT (&open_commit_sig__descriptor) \
, NULL } , NULL }
/*
* Supply ScriptSig for each anchor tx inputs.
*/
struct _OpenAnchorScriptsigs
{
ProtobufCMessage base;
size_t n_script;
ProtobufCBinaryData *script;
};
#define OPEN_ANCHOR_SCRIPTSIGS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&open_anchor_scriptsigs__descriptor) \
, 0,NULL }
/* /*
* Indicates we've seen transaction reach min-depth. * Indicates we've seen transaction reach min-depth.
*/ */
@@ -287,13 +259,9 @@ struct _UpdateAccept
{ {
ProtobufCMessage base; ProtobufCMessage base;
/* /*
* Signature for your new commitment tx. * Signatures for your new commitment tx.
*/ */
Signature *sig; AnchorSpend *sigs;
/*
* Signature for old anchor (if any)
*/
Signature *old_anchor_sig;
/* /*
* Hash for which I will supply preimage to revoke this new commit tx. * Hash for which I will supply preimage to revoke this new commit tx.
*/ */
@@ -301,7 +269,7 @@ struct _UpdateAccept
}; };
#define UPDATE_ACCEPT__INIT \ #define UPDATE_ACCEPT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&update_accept__descriptor) \ { PROTOBUF_C_MESSAGE_INIT (&update_accept__descriptor) \
, NULL, NULL, NULL } , NULL, NULL }
/* /*
@@ -311,9 +279,9 @@ struct _UpdateSignature
{ {
ProtobufCMessage base; 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. * Hash preimage which revokes old commitment tx.
*/ */
@@ -347,11 +315,10 @@ struct _CloseChannel
{ {
ProtobufCMessage base; ProtobufCMessage base;
/* /*
* This is our signature a new transaction which spends the anchor * These are our signatures on a new transaction which spends the anchor
* output to my open->final and your open->final, * outputs to my open->final and your open->final, as per the last commit tx.
* as per the last commit tx.
*/ */
Signature *sig; AnchorSpend *sigs;
}; };
#define CLOSE_CHANNEL__INIT \ #define CLOSE_CHANNEL__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&close_channel__descriptor) \ { PROTOBUF_C_MESSAGE_INIT (&close_channel__descriptor) \
@@ -365,9 +332,9 @@ struct _CloseChannelComplete
{ {
ProtobufCMessage base; 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 \ #define CLOSE_CHANNEL_COMPLETE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&close_channel_complete__descriptor) \ { PROTOBUF_C_MESSAGE_INIT (&close_channel_complete__descriptor) \
@@ -390,8 +357,9 @@ struct _Error
typedef enum { typedef enum {
PKT__PKT__NOT_SET = 0, PKT__PKT__NOT_SET = 0,
PKT__PKT_OPEN = 201, PKT__PKT_OPEN = 201,
PKT__PKT_OPEN_ANCHOR = 203,
PKT__PKT_OPEN_ESCAPE_SIGS = 205,
PKT__PKT_OPEN_COMMIT_SIG = 202, PKT__PKT_OPEN_COMMIT_SIG = 202,
PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS = 203,
PKT__PKT_OPEN_COMPLETE = 204, PKT__PKT_OPEN_COMPLETE = 204,
PKT__PKT_UPDATE = 1, PKT__PKT_UPDATE = 1,
PKT__PKT_UPDATE_ACCEPT = 2, PKT__PKT_UPDATE_ACCEPT = 2,
@@ -414,8 +382,9 @@ struct _Pkt
* Opening * Opening
*/ */
OpenChannel *open; OpenChannel *open;
OpenAnchor *open_anchor;
OpenEscapeSigs *open_escape_sigs;
OpenCommitSig *open_commit_sig; OpenCommitSig *open_commit_sig;
OpenAnchorScriptsigs *open_anchor_scriptsigs;
OpenComplete *open_complete; OpenComplete *open_complete;
/* /*
* Updating (most common) * Updating (most common)
@@ -478,24 +447,24 @@ Signature *
void signature__free_unpacked void signature__free_unpacked
(Signature *message, (Signature *message,
ProtobufCAllocator *allocator); ProtobufCAllocator *allocator);
/* BitcoinInput methods */ /* AnchorSpend methods */
void bitcoin_input__init void anchor_spend__init
(BitcoinInput *message); (AnchorSpend *message);
size_t bitcoin_input__get_packed_size size_t anchor_spend__get_packed_size
(const BitcoinInput *message); (const AnchorSpend *message);
size_t bitcoin_input__pack size_t anchor_spend__pack
(const BitcoinInput *message, (const AnchorSpend *message,
uint8_t *out); uint8_t *out);
size_t bitcoin_input__pack_to_buffer size_t anchor_spend__pack_to_buffer
(const BitcoinInput *message, (const AnchorSpend *message,
ProtobufCBuffer *buffer); ProtobufCBuffer *buffer);
BitcoinInput * AnchorSpend *
bitcoin_input__unpack anchor_spend__unpack
(ProtobufCAllocator *allocator, (ProtobufCAllocator *allocator,
size_t len, size_t len,
const uint8_t *data); const uint8_t *data);
void bitcoin_input__free_unpacked void anchor_spend__free_unpacked
(BitcoinInput *message, (AnchorSpend *message,
ProtobufCAllocator *allocator); ProtobufCAllocator *allocator);
/* BitcoinPubkey methods */ /* BitcoinPubkey methods */
void bitcoin_pubkey__init void bitcoin_pubkey__init
@@ -516,44 +485,6 @@ BitcoinPubkey *
void bitcoin_pubkey__free_unpacked void bitcoin_pubkey__free_unpacked
(BitcoinPubkey *message, (BitcoinPubkey *message,
ProtobufCAllocator *allocator); 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 */ /* OpenChannel methods */
void open_channel__init void open_channel__init
(OpenChannel *message); (OpenChannel *message);
@@ -573,6 +504,44 @@ OpenChannel *
void open_channel__free_unpacked void open_channel__free_unpacked
(OpenChannel *message, (OpenChannel *message,
ProtobufCAllocator *allocator); 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 */ /* OpenCommitSig methods */
void open_commit_sig__init void open_commit_sig__init
(OpenCommitSig *message); (OpenCommitSig *message);
@@ -592,25 +561,6 @@ OpenCommitSig *
void open_commit_sig__free_unpacked void open_commit_sig__free_unpacked
(OpenCommitSig *message, (OpenCommitSig *message,
ProtobufCAllocator *allocator); 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 */ /* OpenComplete methods */
void open_complete__init void open_complete__init
(OpenComplete *message); (OpenComplete *message);
@@ -790,27 +740,24 @@ typedef void (*Sha256Hash_Closure)
typedef void (*Signature_Closure) typedef void (*Signature_Closure)
(const Signature *message, (const Signature *message,
void *closure_data); void *closure_data);
typedef void (*BitcoinInput_Closure) typedef void (*AnchorSpend_Closure)
(const BitcoinInput *message, (const AnchorSpend *message,
void *closure_data); void *closure_data);
typedef void (*BitcoinPubkey_Closure) typedef void (*BitcoinPubkey_Closure)
(const BitcoinPubkey *message, (const BitcoinPubkey *message,
void *closure_data); 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) typedef void (*OpenChannel_Closure)
(const OpenChannel *message, (const OpenChannel *message,
void *closure_data); 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) typedef void (*OpenCommitSig_Closure)
(const OpenCommitSig *message, (const OpenCommitSig *message,
void *closure_data); void *closure_data);
typedef void (*OpenAnchorScriptsigs_Closure)
(const OpenAnchorScriptsigs *message,
void *closure_data);
typedef void (*OpenComplete_Closure) typedef void (*OpenComplete_Closure)
(const OpenComplete *message, (const OpenComplete *message,
void *closure_data); void *closure_data);
@@ -846,13 +793,12 @@ typedef void (*Pkt_Closure)
extern const ProtobufCMessageDescriptor sha256_hash__descriptor; extern const ProtobufCMessageDescriptor sha256_hash__descriptor;
extern const ProtobufCMessageDescriptor signature__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 bitcoin_pubkey__descriptor;
extern const ProtobufCMessageDescriptor change__descriptor;
extern const ProtobufCMessageDescriptor anchor__descriptor;
extern const ProtobufCMessageDescriptor open_channel__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_commit_sig__descriptor;
extern const ProtobufCMessageDescriptor open_anchor_scriptsigs__descriptor;
extern const ProtobufCMessageDescriptor open_complete__descriptor; extern const ProtobufCMessageDescriptor open_complete__descriptor;
extern const ProtobufCMessageDescriptor update__descriptor; extern const ProtobufCMessageDescriptor update__descriptor;
extern const ProtobufCMessageDescriptor update_accept__descriptor; extern const ProtobufCMessageDescriptor update_accept__descriptor;

View File

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

72
pkt.c
View File

@@ -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, struct pkt *openchannel_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash, const struct sha256 *revocation_hash,
const struct pubkey *to_me, const struct pubkey *commit,
const struct pubkey *final,
u64 commitment_fee, u64 commitment_fee,
u32 rel_locktime_seconds, u32 rel_locktime_seconds,
Anchor *anchor) u64 anchor_amount,
const struct sha256 *escape_hash,
u32 min_confirms)
{ {
OpenChannel o = OPEN_CHANNEL__INIT; 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.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.commitment_fee = commitment_fee;
o.anchor = anchor;
o.locktime_case = OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS; o.locktime_case = OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS;
o.locktime_seconds = rel_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); 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; 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; OpenAnchor oa = OPEN_ANCHOR__INIT;
size_t i;
o.n_script = num_sigs; oa.anchor_txid = sha256_to_proto(ctx, &txid->sha);
o.script = tal_arr(ctx, ProtobufCBinaryData, num_sigs); oa.index = index;
for (i = 0; i < num_sigs; i++) { return to_pkt(ctx, PKT__PKT_OPEN_ANCHOR, &oa);
o.script[i].data = sigs[i];
o.script[i].len = tal_count(sigs[i]);
} }
return to_pkt(ctx, PKT__PKT_OPEN_ANCHOR_SCRIPTSIGS, &o); struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sigs)
}
struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sig)
{ {
OpenCommitSig o = OPEN_COMMIT_SIG__INIT; OpenCommitSig o = OPEN_COMMIT_SIG__INIT;
o.sigs = tal(ctx, AnchorSpend);
o.sig = signature_to_proto(ctx, sig); 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); 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; 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); return to_pkt(ctx, PKT__PKT_CLOSE, &c);
} }
struct pkt *close_channel_complete_pkt(const tal_t *ctx, struct pkt *close_channel_complete_pkt(const tal_t *ctx,
const struct signature *sig) const struct signature *sigs)
{ {
CloseChannelComplete c = CLOSE_CHANNEL_COMPLETE__INIT; 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); 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 pkt *update_accept_pkt(const tal_t *ctx,
struct signature *sig, const struct signature *sigs,
const struct sha256 *revocation_hash) const struct sha256 *revocation_hash)
{ {
UpdateAccept ua = UPDATE_ACCEPT__INIT; 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); ua.revocation_hash = sha256_to_proto(ctx, revocation_hash);
return to_pkt(ctx, PKT__PKT_UPDATE_ACCEPT, &ua); return to_pkt(ctx, PKT__PKT_UPDATE_ACCEPT, &ua);
} }
struct pkt *update_signature_pkt(const tal_t *ctx, struct pkt *update_signature_pkt(const tal_t *ctx,
const struct signature *sig, const struct signature *sigs,
const struct sha256 *revocation_preimage) const struct sha256 *revocation_preimage)
{ {
UpdateSignature us = UPDATE_SIGNATURE__INIT; 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); us.revocation_preimage = sha256_to_proto(ctx, revocation_preimage);
return to_pkt(ctx, PKT__PKT_UPDATE_SIGNATURE, &us); return to_pkt(ctx, PKT__PKT_UPDATE_SIGNATURE, &us);
} }

48
pkt.h
View File

@@ -24,6 +24,7 @@ Pkt *any_pkt_from_file(const char *filename);
size_t pkt_totlen(const struct pkt *pkt); size_t pkt_totlen(const struct pkt *pkt);
struct sha256; struct sha256;
struct sha256_double;
struct bitcoin_compressed_pubkey; struct bitcoin_compressed_pubkey;
struct signature; struct signature;
struct pubkey; struct pubkey;
@@ -32,47 +33,58 @@ struct pubkey;
* openchannel_pkt - create an openchannel message * openchannel_pkt - create an openchannel message
* @ctx: tal context to allocate off. * @ctx: tal context to allocate off.
* @revocation_hash: first hash value generated from seed. * @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. * @commitment_fee: the fee to use for commitment tx.
* @rel_locktime_seconds: relative seconds for commitment locktime. * @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, struct pkt *openchannel_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash, const struct sha256 *revocation_hash,
const struct pubkey *to_me, const struct pubkey *commit,
const struct pubkey *final,
u64 commitment_fee, u64 commitment_fee,
u32 rel_locktime_seconds, 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. * @ctx: tal context to allocate off.
* @sigs: the der-encoded signatures (tal_count() gives len). * @txid: the anchor's txid
* @num_sigs: the number of sigs. * @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 * open_commit_sig_pkt - create an open_commit_sig message
* @ctx: tal context to allocate off. * @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 * close_channel_pkt - create an close_channel message
* @ctx: tal context to allocate off. * @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 * close_channel_complete_pkt - create an close_channel_complete message
* @ctx: tal context to allocate off. * @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, struct pkt *close_channel_complete_pkt(const tal_t *ctx,
const struct signature *sig); const struct signature *sigs);
/** /**
* update_pkt - create an update message * 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 * update_accept_pkt - create an update_accept message
* @ctx: tal context to allocate off. * @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. * @revocation_hash: hash to revoke the next tx.
*/ */
struct pkt *update_accept_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); const struct sha256 *revocation_hash);
/** /**
* update_signature_pkt - create an update_signature message * update_signature_pkt - create an update_signature message
* @ctx: tal context to allocate off. * @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. * @revocation_preimage: preimage to revoke existing (now-obsolete) tx.
*/ */
struct pkt *update_signature_pkt(const tal_t *ctx, struct pkt *update_signature_pkt(const tal_t *ctx,
const struct signature *sig, const struct signature *sigs,
const struct sha256 *revocation_preimage); const struct sha256 *revocation_preimage);
/** /**
* update_complete_pkt - create an update_accept message * update_complete_pkt - create an update_accept message

View File

@@ -41,98 +41,116 @@ For each side A and B you need:
7. FINALKEY: The private key for FINALADDR 7. FINALKEY: The private key for FINALADDR
eg. `alpha-cli -regtest -testnet=0 dumpprivkey <FINALADDR>` eg. `alpha-cli -regtest -testnet=0 dumpprivkey <FINALADDR>`
8. TXIN{1-n}: One or more unspent transaction outputs on testnet. 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). eg. scripts/getinput.sh (`scripts/getinput.sh 2`, etc).
9. TXINKEY{1-n}: The private keys to spend the TXINs. 9. ESCAPE-SECRET: A secret 256-bit number, in hex.
eg. `scripts/getinput.sh --privkey` can get these. Try 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
STEP 1 STEP 1
------ ------
First each side needs to tell the other what it wants the channel 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. 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: 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: 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 STEP 2
------ ------
Create the signatures for the anchor transaction: we don't send them Each side creates their anchor transaction which pays to a 2 of 2
until we have completed the commitment transaction though, so we're sure (spendable with their own key and the other's TMPKEY or FINALKEY). We
we can get our funds back. We need one TXINKEY for each TXIN: 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: 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: B:
test-cli/create-anchor-tx A-open.pb B-open.pb <B-CHANGEPUBKEY> <txid>/<outnum>/<amount>/<scriptsig>/<privkey>... > B-anchor.tx
test-cli/open-anchor-scriptsigs B-open.pb A-open.pb <B-TXINKEY>... > B-anchor-scriptsigs.pb
STEP 3 STEP 3
------ ------
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
B:
test-cli/open-anchor-id B-anchor.tx > B-anchor-id.pb
STEP 4
------
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
B:
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 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
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
STEP 6
------
Now both sides create the commitment transaction signatures which spend Now both sides create the commitment transaction signatures which spend
the transaction output: the anchors outputs:
A: A:
test-cli/open-commit-sig A-open.pb B-open.pb <A-TMPKEY> > A-commit-sig.pb 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: B:
test-cli/open-commit-sig B-open.pb A-open.ob <B-TMPKEY> > B-commit-sig.pb 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 4 STEP 7
------ ------
Check the commitment signatures from the other side, and produce commit txs. Check the commitment signatures from the other side, and produce commit txs.
A: A:
test-cli/check-commit-sig A-open.pb B-open.pb B-commit-sig.pb <A-TMPKEY> > A-commit-0.tx 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: B:
test-cli/check-commit-sig B-open.pb A-open.pb A-commit-sig.pb <B-TMPKEY> > B-commit-0.tx 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 5 STEP 8
------ ------
Check the anchor signatures from the other side, and use them to generate the Broadcast the anchor transactions (note they contain their inputs amounts
anchor transaction (as a hex string, suitable for bitcoind). separated by colons for internal use: the daemon only wants the raw transaction):
A: A:
alpha-cli -regtest -testnet=0 sendrawtransaction `cut -d: -f1 A-anchor.tx` > A-anchor.txid
test-cli/check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb > A-anchor.tx
B: B:
alpha-cli -regtest -testnet=0 sendrawtransaction `cut -d: -f1 B-anchor.tx` > B-anchor.txid
test-cli/check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb > B-anchor.tx
They should be identical:
cmp A-anchor.tx B-anchor.tx || echo FAIL
STEP 6
------
Broadcast the anchor transaction:
Either one:
alpha-cli -regtest -testnet=0 sendrawtransaction `cat A-anchor.tx` > anchor.txid
Generate blocks until we have enough confirms (I don't do this, so I 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`): can reset the entire state by restarting bitcoind with `-zapwallettxes=1`):
A: A:
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
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
B: B:
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
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
Using a Generalized Channel Using a Generalized Channel
=========================== ===========================
@@ -149,19 +167,19 @@ revocation hash for the new tx:
B: 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 completes its side by signing the new tx, and revoking the old:
A: 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 now revokes its old tx:
B: 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. 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: 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 Special Effects: Trying To Cheat
================================ ================================
@@ -187,7 +205,7 @@ A now tries to spend an old (revoked) commitment tx:
A: 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: A:
@@ -235,20 +253,20 @@ reflect the final commitment total:
A: 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: 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: Both ends have both signatures now, so either can create the close tx:
A: 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: 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: They should be identical:

View File

@@ -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;
}

View File

@@ -21,82 +21,90 @@ int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
OpenCommitSig *cs2; OpenCommitSig *cs2;
struct bitcoin_tx *anchor, *commit; AnchorSpend mysigs = ANCHOR_SPEND__INIT;
struct sha256_double txid; struct bitcoin_tx *commit;
u8 *subscript; struct sha256_double anchor_txid1, anchor_txid2;
size_t *inmap, *outmap; struct pubkey pubkey1, pubkey2, final1, final2;
struct pubkey pubkey1, pubkey2; struct signature sigs[2];
struct bitcoin_signature sig1, sig2;
struct privkey privkey; struct privkey privkey;
bool testnet; bool testnet;
struct sha256 rhash; struct sha256 rhash, escape_hash1, escape_hash2;
size_t inmap[2];
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Output the commitment transaction if both signatures are valid",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 5) if (argc != 7)
opt_usage_exit_fail("Expected 4 arguments"); opt_usage_exit_fail("Expected 6 arguments");
o1 = pkt_from_file(argv[1], 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; o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
cs2 = pkt_from_file(argv[3], PKT__PKT_OPEN_COMMIT_SIG)->open_commit_sig; 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[4], strlen(argv[4]), &testnet, &privkey, &pubkey1)) if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]); errx(1, "Invalid private key '%s'", argv[6]);
if (!testnet) 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? */ /* Pubkey well-formed? */
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid anchor-2 key"); errx(1, "Invalid open-2 key");
if (!proto_to_pubkey(o2->final, &final2))
/* Get the transaction ID of the anchor. */ errx(1, "Invalid o2 final pubkey");
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap); if (!proto_to_pubkey(o1->final, &final1))
if (!anchor) errx(1, "Invalid o1 final pubkey");
errx(1, "Failed transaction merge");
anchor_txid(anchor, &txid);
/* Now create our commitment tx. */ /* Now create our commitment tx. */
proto_to_sha256(o1->revocation_hash, &rhash); 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 contributions don't exceed fees, this fails. */
if (!commit) if (!commit)
errx(1, "Contributions %llu & %llu vs fees %llu & %llu", errx(1, "Contributions %llu & %llu vs fees %llu & %llu",
(long long)o1->anchor->total, (long long)o1->total_input,
(long long)o2->anchor->total, (long long)o2->total_input,
(long long)o1->commitment_fee, (long long)o1->commitment_fee,
(long long)o2->commitment_fee); (long long)o2->commitment_fee);
/* FIXME: Creating out signature just to check the script we create /* Check they signed out anchor inputs correctly. */
* is overkill: if their signature and pubkey signed the commit txin, if (!check_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
* we're happy. */ &pubkey2, &final2, &escape_hash2,
sig1.stype = SIGHASH_ALL; &pubkey2, cs2->sigs))
subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); errx(1, "Bad signature");
sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript),
&privkey, &pubkey1, &sig1.sig);
/* Signatures well-formed? */ if (!sign_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
if (!proto_to_signature(cs2->sig, &sig2.sig)) &pubkey2, &final2, &escape_hash2,
errx(1, "Invalid commit-sig-2"); &pubkey1, &privkey, sigs))
sig2.stype = SIGHASH_ALL; errx(1, "Could not sign tx");
/* Combined signatures must validate correctly. */ /* populate_anchor_inscripts wants args in protobuf */
if (!check_2of2_sig(commit, 0, subscript, tal_count(subscript), mysigs.sig0 = signature_to_proto(ctx, &sigs[0]);
&pubkey1, &pubkey2, &sig1, &sig2)) mysigs.sig1 = signature_to_proto(ctx, &sigs[1]);
errx(1, "Signature failed");
/* Create p2sh input for commit */ /* Shouldn't fail, since we checked them in check_anchor_spend */
commit->input[0].script = scriptsig_p2sh_2of2(commit, &sig1, &sig2, if (!populate_anchor_inscripts(commit, commit, inmap,
&pubkey1, &pubkey2); &pubkey1, &final1, &escape_hash1,
commit->input[0].script_length = tal_count(commit->input[0].script); &pubkey2, &final2, &escape_hash2,
&mysigs,
cs2->sigs))
errx(1, "Malformed signatures");
/* Print it out in hex. */ /* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, commit)) if (!bitcoin_tx_write(STDOUT_FILENO, commit))

View File

@@ -23,16 +23,17 @@ int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
struct bitcoin_tx *anchor, *close_tx; OpenAnchor *oa1, *oa2;
struct sha256_double anchor_txid; struct sha256_double anchor_txid1, anchor_txid2;
struct bitcoin_tx *close_tx;
struct sha256 escape_hash1, escape_hash2;
struct pkt *pkt; struct pkt *pkt;
struct signature sig; struct signature sigs[2];
struct privkey privkey; struct privkey privkey;
bool testnet, complete = false; bool testnet, complete = false;
struct pubkey pubkey1, pubkey2; struct pubkey pubkey1, pubkey2, final1, final2;
u8 *redeemscript;
int64_t delta; int64_t delta;
size_t i, anchor_out; size_t i, inmap[2];
err_set_progname(argv[0]); err_set_progname(argv[0]);
@@ -40,61 +41,82 @@ int main(int argc, char *argv[])
opt_register_noarg("--complete", opt_set_bool, &complete, opt_register_noarg("--complete", opt_set_bool, &complete,
"Create a close_transaction_complete msg instead"); "Create a close_transaction_complete msg instead");
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create the signature needed for the close transaction",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 5) if (argc < 6)
opt_usage_exit_fail("Expected 4+ arguments"); opt_usage_exit_fail("Expected 5+ arguments");
anchor = bitcoin_tx_from_file(ctx, argv[1]); o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
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; 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)) if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]); errx(1, "Invalid private key '%s'", argv[5]);
if (!testnet) if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]); errx(1, "Private key '%s' not on testnet!", argv[5]);
bitcoin_txid(anchor, &anchor_txid);
/* Get delta by accumulting all the updates. */ /* Get delta by accumulting all the updates. */
delta = 0; 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; Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta; delta += u->delta;
} }
/* Get pubkeys */ /* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o1->commitkey, &pubkey2))
errx(1, "Invalid o1 commit pubkey"); errx(1, "Invalid o1 commit pubkey");
if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2)
|| memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0)
errx(1, "o1 pubkey != this privkey"); 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"); errx(1, "Invalid o2 final pubkey");
/* This is what the anchor pays to; figure out whick output. */ /* Now create the close tx to spend 2/2 outputs of anchors. */
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);
close_tx = create_close_tx(ctx, o1, o2, complete ? -delta : delta, close_tx = create_close_tx(ctx, o1, o2, complete ? -delta : delta,
&anchor_txid, &anchor_txid1, oa1->index, o1->total_input,
anchor->output[anchor_out].amount, &anchor_txid2, oa2->index, o2->total_input,
anchor_out); 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 it for them. */ /* Sign close. */
sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript), if (!sign_anchor_spend(close_tx, inmap,
&privkey, &pubkey1, &sig); &pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &privkey, sigs))
errx(1, "Failed creating signatures");
if (complete) if (complete)
pkt = close_channel_complete_pkt(ctx, &sig); pkt = close_channel_complete_pkt(ctx, sigs);
else else
pkt = close_channel_pkt(ctx, &sig); pkt = close_channel_pkt(ctx, sigs);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt))) if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet"); err(1, "Writing out packet");

188
test-cli/create-anchor-tx.c Normal file
View File

@@ -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;
}

View File

@@ -21,75 +21,80 @@ int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
struct bitcoin_tx *anchor, *close_tx; OpenAnchor *oa1, *oa2;
struct sha256_double anchor_txid; struct bitcoin_tx *close_tx;
struct bitcoin_signature sig1, sig2; struct sha256_double anchor_txid1, anchor_txid2;
struct pubkey pubkey1, pubkey2; struct sha256 escape_hash1, escape_hash2;
u8 *redeemscript; struct pubkey pubkey1, pubkey2, final1, final2;
CloseChannel *close; CloseChannel *close;
CloseChannelComplete *closecomplete; CloseChannelComplete *closecomplete;
size_t i, anchor_out; size_t i, inmap[2];
int64_t delta; int64_t delta;
err_set_progname(argv[0]); err_set_progname(argv[0]);
/* FIXME: Take update.pbs to adjust channel */ /* FIXME: Take update.pbs to adjust channel */
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create the close transaction from the signatures",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 6) if (argc < 7)
opt_usage_exit_fail("Expected 5+ arguments"); opt_usage_exit_fail("Expected 6+ arguments");
anchor = bitcoin_tx_from_file(ctx, argv[1]); o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
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; o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
close = pkt_from_file(argv[4], PKT__PKT_CLOSE)->close; proto_to_sha256(o2->escape_hash, &escape_hash2);
closecomplete = pkt_from_file(argv[5], PKT__PKT_CLOSE_COMPLETE)->close_complete; oa1 = pkt_from_file(argv[3], PKT__PKT_OPEN_ANCHOR)->open_anchor;
oa2 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
bitcoin_txid(anchor, &anchor_txid); 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? */ /* Pubkeys well-formed? */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1)) if (!proto_to_pubkey(o1->commitkey, &pubkey1))
errx(1, "Invalid anchor-1 key"); errx(1, "Invalid open-1 key");
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o2->commitkey, &pubkey2))
errx(1, "Invalid anchor-2 key"); 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. */ /* Get delta by accumulting all the updates. */
delta = 0; 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; Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta; delta += u->delta;
} }
/* This is what the anchor pays to; figure out which output. */ close_tx = create_close_tx(ctx, o1, o2, delta,
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); &anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
/* Now create the close tx to spend 2/2 output of anchor. */ if (!check_anchor_spend(close_tx, inmap,
anchor_out = find_p2sh_out(anchor, redeemscript); &pubkey1, &final1, &escape_hash1,
close_tx = create_close_tx(ctx, o1, o2, delta, &anchor_txid, &pubkey2, &final2, &escape_hash2,
anchor->output[anchor_out].amount, &pubkey1, close->sigs))
anchor_out); errx(1, "Close signature check failed");
/* Signatures well-formed? */ if (!check_anchor_spend(close_tx, inmap,
sig1.stype = sig2.stype = SIGHASH_ALL; &pubkey1, &final1, &escape_hash1,
if (!proto_to_signature(close->sig, &sig1.sig)) &pubkey2, &final2, &escape_hash2,
errx(1, "Invalid close-packet"); &pubkey2, closecomplete->sigs))
if (!proto_to_signature(closecomplete->sig, &sig2.sig)) errx(1, "Closecomplete signature check failed");
errx(1, "Invalid closecomplete-packet");
/* Combined signatures must validate correctly. */ if (!populate_anchor_inscripts(close_tx, close_tx, inmap,
if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript), &pubkey1, &final1, &escape_hash1,
&pubkey1, &pubkey2, &sig1, &sig2)) &pubkey2, &final2, &escape_hash2,
errx(1, "Signature failed"); close->sigs,
closecomplete->sigs))
/* Create p2sh input for close_tx */ errx(1, "Malformed signatures");
close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, &sig1, &sig2,
&pubkey1, &pubkey2);
close_tx->input[0].script_length = tal_count(close_tx->input[0].script);
/* Print it out in hex. */ /* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, close_tx)) if (!bitcoin_tx_write(STDOUT_FILENO, close_tx))

View File

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

View File

@@ -23,100 +23,119 @@ int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
Pkt *pkt; Pkt *pkt;
struct bitcoin_tx *anchor, *commit; AnchorSpend mysigs = ANCHOR_SPEND__INIT;
struct sha256_double anchor_txid; struct bitcoin_tx *commit;
struct sha256_double anchor_txid1, anchor_txid2;
struct sha256 escape_hash1, escape_hash2;
struct privkey privkey; struct privkey privkey;
bool testnet; bool testnet;
struct bitcoin_signature sig1, sig2; struct signature sigs[2];
size_t i; AnchorSpend *their_sigs;
struct pubkey pubkey1, pubkey2; size_t i, inmap[2];
u8 *redeemscript; struct pubkey pubkey1, pubkey2, final1, final2;
int64_t delta; int64_t delta;
struct sha256 rhash; struct sha256 rhash;
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create the signature needed for the commit transaction",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 6) if (argc < 7)
opt_usage_exit_fail("Expected 5+ arguments"); opt_usage_exit_fail("Expected 6+ arguments");
anchor = bitcoin_tx_from_file(ctx, argv[1]); o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open;
bitcoin_txid(anchor, &anchor_txid); proto_to_sha256(o1->escape_hash, &escape_hash1);
o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
o2 = pkt_from_file(argv[3], 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)) if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[4]); errx(1, "Invalid private key '%s'", argv[5]);
if (!testnet) if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]); errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Get pubkeys */ /* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o1->commitkey, &pubkey2))
errx(1, "Invalid o1 anchor pubkey"); errx(1, "Invalid o1 pubkey");
if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2)
|| memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0)
errx(1, "o1 pubkey != this privkey"); 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 anchor pubkey"); 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. */ /* Their signature comes from open-commit or from update-accept. */
sig2.stype = SIGHASH_ALL; pkt = any_pkt_from_file(argv[6]);
pkt = any_pkt_from_file(argv[5]);
switch (pkt->pkt_case) { switch (pkt->pkt_case) {
case PKT__PKT_UPDATE_ACCEPT: case PKT__PKT_UPDATE_ACCEPT:
if (!proto_to_signature(pkt->update_accept->sig, &sig2.sig)) their_sigs = pkt->update_accept->sigs;
errx(1, "Invalid update-accept sig");
break; break;
case PKT__PKT_OPEN_COMMIT_SIG: case PKT__PKT_OPEN_COMMIT_SIG:
if (!proto_to_signature(pkt->open_commit_sig->sig, &sig2.sig)) their_sigs = pkt->open_commit_sig->sigs;
errx(1, "Invalid open-commit-sig sig");
break; break;
default: default:
errx(1, "Unexpected packet type %u in %s", errx(1, "Unexpected packet type %u in %s",
pkt->pkt_case, argv[5]); pkt->pkt_case, argv[6]);
} }
/* Initial revocation hash comes from open. */ /* Initial revocation hash comes from open. */
proto_to_sha256(o1->revocation_hash, &rhash); proto_to_sha256(o1->revocation_hash, &rhash);
delta = 0; delta = 0;
/* Figure out cumulative delta since anchor, update revocation hash */ /* Figure out cumulative delta since anchors, update revocation hash */
for (i = 6; i < argc; i++) { for (i = 7; i < argc; i++) {
Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update; Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta; delta += u->delta;
proto_to_sha256(u->revocation_hash, &rhash); 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. */ /* Now create commitment tx to spend 2/2 outputs of anchors. */
commit = create_commit_tx(ctx, o1, o2, &rhash, delta, &anchor_txid, commit = create_commit_tx(ctx, o1, o2, &rhash, delta,
find_p2sh_out(anchor, redeemscript)); &anchor_txid1, oa1->index, o1->total_input,
&anchor_txid2, oa2->index, o2->total_input,
inmap);
/* If contributions don't exceed fees, this fails. */ /* If contributions don't exceed fees, this fails. */
if (!commit) if (!commit)
errx(1, "Bad commit amounts"); errx(1, "Bad commit amounts");
/* We generate our signature. */ if (!check_anchor_spend(commit, inmap,
sig1.stype = SIGHASH_ALL; &pubkey1, &final1, &escape_hash1,
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript), &pubkey2, &final2, &escape_hash2,
&privkey, &pubkey1, &sig1.sig); &pubkey2, their_sigs))
errx(1, "Bad signatures");
if (!check_2of2_sig(commit, 0, redeemscript, tal_count(redeemscript), /* We generate our signatures. */
&pubkey1, &pubkey2, &sig1, &sig2)) if (!sign_anchor_spend(commit, inmap,
errx(1, "Signature failed"); &pubkey1, &final1, &escape_hash1,
&pubkey2, &final2, &escape_hash2,
&pubkey1, &privkey, sigs))
errx(1, "Could not create signatures");
/* Create p2sh input for commit */ /* populate_anchor_inscripts wants args in protobuf */
commit->input[0].script = scriptsig_p2sh_2of2(commit, &sig1, &sig2, mysigs.sig0 = signature_to_proto(ctx, &sigs[0]);
&pubkey1, &pubkey2); mysigs.sig1 = signature_to_proto(ctx, &sigs[1]);
commit->input[0].script_length = tal_count(commit->input[0].script);
/* 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. */ /* Print it out in hex. */
if (!bitcoin_tx_write(STDOUT_FILENO, commit)) if (!bitcoin_tx_write(STDOUT_FILENO, commit))

View File

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

View File

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

79
test-cli/open-anchor-id.c Normal file
View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -22,78 +22,34 @@
/* Bitcoin nodes are allowed to be 2 hours in the future. */ /* Bitcoin nodes are allowed to be 2 hours in the future. */
#define LOCKTIME_MIN (2 * 60 * 60) #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. */ /* Simple helper to open a channel. */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct sha256 seed, revocation_hash; struct sha256 seed, revocation_hash, escape_secret, escape_hash;
struct pkt *pkt; struct pkt *pkt;
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
Anchor anchor = ANCHOR__INIT;
u64 commit_tx_fee, total_in; u64 commit_tx_fee, total_in;
unsigned int locktime_seconds; unsigned int locktime_seconds, min_confirms;
bool testnet; bool testnet;
size_t i; struct pubkey commitkey, outkey;
struct pubkey commitkey, outkey, changekey;
struct privkey commitprivkey, outprivkey; struct privkey commitprivkey, outprivkey;
err_set_progname(argv[0]); err_set_progname(argv[0]);
/* Default values. */ /* Default values. */
anchor.min_confirms = 3; min_confirms = 3;
/* Remember, other side contributes to fee, too. */
anchor.fee = 5000;
/* We only need this for involuntary close, so make it larger. */ /* We only need this for involuntary close, so make it larger. */
commit_tx_fee = 100000; commit_tx_fee = 100000;
/* This means we have ~1 day before they can steal our money. */ /* This means we have ~1 day before they can steal our money. */
locktime_seconds = LOCKTIME_MIN + 24 * 60 * 60; locktime_seconds = LOCKTIME_MIN + 24 * 60 * 60;
opt_register_noarg("--help|-h", opt_usage_and_exit, 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.", "A test program to output openchannel on stdout.",
"Print this message."); "Print this message.");
opt_register_arg("--min-anchor-confirms", 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"); "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_register_arg("--commitment-fee=<bits>",
opt_set_bits, opt_show_bits, &commit_tx_fee, opt_set_bits, opt_show_bits, &commit_tx_fee,
"100's of satoshi to pay for commitment"); "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); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 7) if (argc != 6)
opt_usage_exit_fail("Expected 6 or more arguments"); opt_usage_exit_fail("Expected 5 arguments");
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
anchor.total = atol(argv[2]); total_in = atol(argv[2]);
if (!anchor.total) if (!total_in)
errx(1, "Invalid total: must be > 0"); 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 /* We don't really need the privkey here, but it's the most
* convenient way to get the pubkey from bitcoind. */ * 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)) &commitprivkey, &commitkey))
errx(1, "Invalid private key '%s'", argv[3]);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[3]);
if (!key_from_base58(argv[4], strlen(argv[4]), &testnet,
&outprivkey, &outkey))
errx(1, "Invalid private key '%s'", argv[4]); errx(1, "Invalid private key '%s'", argv[4]);
if (!testnet) if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[4]); errx(1, "Private key '%s' not on testnet!", argv[4]);
if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, if (!hex_decode(argv[5], strlen(argv[5]), &escape_secret,
&outprivkey, &outkey)) sizeof(escape_secret)))
errx(1, "Invalid private key '%s'", argv[5]); errx(1, "Invalid escape hash '%s' - need 256 hex bits", argv[5]);
if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[5]);
anchor.n_inputs = (argc - 6);
anchor.inputs = tal_arr(ctx, BitcoinInput *, anchor.n_inputs);
anchor.pubkey = pubkey_to_proto(ctx, &commitkey);
total_in = 0;
for (i = 0; i < anchor.n_inputs; i++) {
anchor.inputs[i] = parse_anchor_input(anchor.inputs, argv[i+6]);
total_in += anchor.inputs[i]->amount;
}
if (total_in < anchor.total + anchor.fee)
errx(1, "Only %llu satoshi in, and %llu out (+%llu fee)",
(unsigned long long)total_in,
(unsigned long long)anchor.total,
(unsigned long long)anchor.fee);
/* If there's change, say where to send it. */
if (total_in != anchor.total + anchor.fee) {
anchor.change = tal(ctx, Change);
change__init(anchor.change);
anchor.change->pubkey = pubkey_to_proto(anchor.change,
&changekey);
anchor.change->amount = total_in - (anchor.total + anchor.fee);
}
/* Get first revocation hash. */ /* Get first revocation hash. */
shachain_from_seed(&seed, 0, &revocation_hash); shachain_from_seed(&seed, 0, &revocation_hash);
sha256(&revocation_hash, sha256(&revocation_hash,
revocation_hash.u.u8, sizeof(revocation_hash.u.u8)); revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
pkt = openchannel_pkt(ctx, &revocation_hash, &outkey, /* Get hash from escape secret. */
commit_tx_fee, locktime_seconds, &anchor); 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))) if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet"); err(1, "Writing out packet");

View File

@@ -22,67 +22,74 @@ int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
struct bitcoin_tx *anchor, *commit; OpenAnchor *oa1, *oa2;
struct sha256_double txid; struct bitcoin_tx *commit;
struct sha256 escape_hash1, escape_hash2;
struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt; struct pkt *pkt;
struct signature sig; struct signature sigs[2];
size_t *inmap, *outmap;
struct privkey privkey; struct privkey privkey;
bool testnet; bool testnet;
struct pubkey pubkey1, pubkey2; struct pubkey pubkey1, pubkey2, final1, final2;
u8 *subscript;
struct sha256 rhash; struct sha256 rhash;
size_t inmap[2];
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create the signature needed for the commit transaction",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 4) if (argc != 6)
opt_usage_exit_fail("Expected 3 arguments"); opt_usage_exit_fail("Expected 5 arguments");
o1 = pkt_from_file(argv[1], PKT__PKT_OPEN)->open; 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; o2 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
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[3], strlen(argv[3]), &testnet, &privkey, &pubkey1)) if (!key_from_base58(argv[5], strlen(argv[5]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[3]); errx(1, "Invalid private key '%s'", argv[5]);
if (!testnet) if (!testnet)
errx(1, "Private key '%s' not on testnet!", argv[3]); errx(1, "Private key '%s' not on testnet!", argv[5]);
/* Create merged anchor transaction */ proto_to_sha256(oa1->anchor_txid, &anchor_txid1.sha);
anchor = anchor_tx_create(ctx, o1, o2, &inmap, &outmap); proto_to_sha256(oa2->anchor_txid, &anchor_txid2.sha);
if (!anchor)
errx(1, "Failed transaction merge");
/* Get the transaction ID of the anchor. */ /* Now create THEIR commitment tx to spend outputs of anchors. */
anchor_txid(anchor, &txid);
/* Now create THEIR commitment tx to spend 2/2 output of anchor. */
proto_to_sha256(o2->revocation_hash, &rhash); 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 contributions don't exceed fees, this fails. */
if (!commit) if (!commit)
errx(1, "Contributions %llu & %llu vs fees %llu & %llu", errx(1, "Contributions %llu & %llu vs fees %llu & %llu",
(long long)o1->anchor->total, (long long)o1->total_input,
(long long)o2->anchor->total, (long long)o2->total_input,
(long long)o1->commitment_fee, (long long)o1->commitment_fee,
(long long)o2->commitment_fee); (long long)o2->commitment_fee);
/* Their pubkey must be valid */ /* Since we're signing theirs, "my" and "their" args are backwards. */
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) if (!sign_anchor_spend(commit, inmap,
errx(1, "Invalid public open-channel-file2"); &pubkey2, &final2, &escape_hash2,
&pubkey1, &final1, &escape_hash1,
&pubkey1, &privkey, sigs))
errx(1, "Could not sign tx");
/* Sign it for them. */ pkt = open_commit_sig_pkt(ctx, sigs);
subscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
sign_tx_input(ctx, commit, 0, subscript, tal_count(subscript),
&privkey, &pubkey1, &sig);
pkt = open_commit_sig_pkt(ctx, &sig);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt))) if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet"); err(1, "Writing out packet");

View File

@@ -8,10 +8,6 @@ set -e
. `dirname $0`/vars.sh . `dirname $0`/vars.sh
if [ n"$1" = n--privkey ]; then
KEY=1
shift
fi
NUM=1 NUM=1
if [ $# = 1 ]; then if [ $# = 1 ]; then
NUM=$1 NUM=$1
@@ -19,18 +15,15 @@ if [ $# = 1 ]; then
fi fi
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
echo "Usage: getinput.sh [--privkey] [INPUT-INDEX]" echo "Usage: getinput.sh [INPUT-INDEX]"
exit 1 exit 1
fi 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` 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` 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*//'` 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` 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 echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT/$PRIVKEY
fi

View File

@@ -66,13 +66,14 @@ B_FINALADDR=`scripts/get-new-address.sh`
#B_FINALADDR=mvQgfEX4iMSEYqD31524jASQviPwPwpvuv #B_FINALADDR=mvQgfEX4iMSEYqD31524jASQviPwPwpvuv
A_TXIN=`scripts/getinput.sh $A_INPUTNUM` A_TXIN=`scripts/getinput.sh $A_INPUTNUM`
A_TXINKEY=`scripts/getinput.sh --privkey $A_INPUTNUM`
B_TXIN=`scripts/getinput.sh $B_INPUTNUM` B_TXIN=`scripts/getinput.sh $B_INPUTNUM`
B_TXINKEY=`scripts/getinput.sh --privkey $B_INPUTNUM`
A_SEED=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff A_SEED=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
B_SEED=112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00 B_SEED=112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00
A_ESCSECRET=00112233445566778899aabbccddeeff00112233445566778899aabbccddeef0
B_ESCSECRET=112233445566778899aabbccddeeff00112233445566778899aabbccddeeff0f
A_CHANGEPUBKEY=`getpubkey $A_CHANGEADDR` A_CHANGEPUBKEY=`getpubkey $A_CHANGEADDR`
A_TMPKEY=`getprivkey $A_TMPADDR` A_TMPKEY=`getprivkey $A_TMPADDR`
A_FINALKEY=`getprivkey $A_FINALADDR` A_FINALKEY=`getprivkey $A_FINALADDR`
@@ -82,56 +83,56 @@ B_TMPKEY=`getprivkey $B_TMPADDR`
B_FINALKEY=`getprivkey $B_FINALADDR` B_FINALKEY=`getprivkey $B_FINALADDR`
# Both sides say what they want from channel # 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. # 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. # Now create anchors.
$PREFIX ./open-anchor-scriptsigs A-open.pb B-open.pb $A_TXINKEY > A-anchor-scriptsigs.pb $PREFIX ./create-anchor-tx A-open.pb B-open.pb $A_CHANGEPUBKEY $A_TXIN > A-anchor.tx
$PREFIX ./open-anchor-scriptsigs B-open.pb A-open.pb $B_TXINKEY > B-anchor-scriptsigs.pb $PREFIX ./create-anchor-tx B-open.pb A-open.pb $B_CHANGEPUBKEY $B_TXIN > B-anchor.tx
# 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
# Now create commit signature # Now create commit signature
$PREFIX ./open-commit-sig A-open.pb B-open.pb $A_TMPKEY > A-commit-sig.pb $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
$PREFIX ./open-commit-sig B-open.pb A-open.pb $B_TMPKEY > B-commit-sig.pb
# Now check it. # 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 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 A-commit-sig.pb $B_TMPKEY > B-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
# Now check anchor sigs and make sure they're the same. # Broadcast anchors
$PREFIX ./check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb > A-anchor.tx $CLI sendrawtransaction `cut -d: -f1 A-anchor.tx` > A-anchor.txid
$PREFIX ./check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb > B-anchor.tx $CLI sendrawtransaction `cut -d: -f1 B-anchor.tx` > B-anchor.txid
cmp A-anchor.tx B-anchor.tx
# Broadcast
$CLI sendrawtransaction `cut -d: -f1 A-anchor.tx` > anchor.txid
# # Wait for confirms # # 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. # 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. # 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 --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-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-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-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-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-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 # 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. # Now you pay me 1000.
$PREFIX ./update-channel --from-them=1000 $A_SEED A-update-1.pb > A-update-2.pb $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-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-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-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-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-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 # 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 if [ x"$1" = x--steal ]; then
# A stupidly broadcasts a revoked transaction. # A stupidly broadcasts a revoked transaction.
@@ -152,8 +153,8 @@ if [ x"$1" = x--unilateral ]; then
fi fi
# Now close channel by mutual consent. # 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 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-anchor.tx B-open.pb A-open.pb $B_TMPKEY A-update-1.pb A-update-2.pb > B-close-complete.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-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 ./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 $CLI sendrawtransaction `cut -d: -f1 A-close.tx` > close.txid

View File

@@ -22,24 +22,24 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); 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; OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
Update *update; Update *update;
struct bitcoin_tx *anchor, *commit; struct bitcoin_tx *commit;
struct sha256_double anchor_txid; struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt; struct pkt *pkt;
struct bitcoin_signature sig; struct signature sigs[2];
struct privkey privkey; struct privkey privkey;
bool testnet; bool testnet;
struct pubkey pubkey1, pubkey2; struct pubkey pubkey1, pubkey2, final1, final2;
u8 *redeemscript;
int64_t delta; int64_t delta;
size_t i, p2sh_out; size_t i, inmap[2];
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Accept a new update message",
"Print this 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))) if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
anchor = bitcoin_tx_from_file(ctx, argv[2]); o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
bitcoin_txid(anchor, &anchor_txid); proto_to_sha256(o1->escape_hash, &escape_hash1);
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
o2 = pkt_from_file(argv[4], 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[5], strlen(argv[5]), &testnet, &privkey, &pubkey1)) if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[5]); errx(1, "Invalid private key '%s'", argv[6]);
if (!testnet) 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. */ /* Figure out cumulative delta since anchor. */
delta = update->delta; 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; Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta; delta += u->delta;
} }
/* Get next revocation hash. */ /* Get next revocation hash. */
shachain_from_seed(&seed, argc - 6, &revocation_hash); shachain_from_seed(&seed, argc - 7, &revocation_hash);
sha256(&revocation_hash, sha256(&revocation_hash,
revocation_hash.u.u8, sizeof(revocation_hash.u.u8)); revocation_hash.u.u8, sizeof(revocation_hash.u.u8));
/* Get pubkeys */ /* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o1->commitkey, &pubkey2))
errx(1, "Invalid o1 commit pubkey"); errx(1, "Invalid o1 commit pubkey");
if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2)
|| memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0)
errx(1, "o1 pubkey != this privkey"); 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"); errx(1, "Invalid o2 final pubkey");
/* This is what the anchor pays to; figure out whick output. */ /* Now create THEIR new commitment tx to spend 2/2 outputs of anchors. */
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
p2sh_out = find_p2sh_out(anchor, redeemscript);
/* Now create THEIR new commitment tx to spend 2/2 output of anchor. */
proto_to_sha256(update->revocation_hash, &their_rhash); proto_to_sha256(update->revocation_hash, &their_rhash);
commit = create_commit_tx(ctx, o2, o1, &their_rhash, delta, 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 contributions don't exceed fees, this fails. */
if (!commit) if (!commit)
errx(1, "Delta too large"); errx(1, "Delta too large");
/* Sign it for them. */ /* Sign it for them (since its theirs, reverse args). */
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript), if (!sign_anchor_spend(commit, inmap, &pubkey2, &final2, &escape_hash2,
&privkey, &pubkey1, &sig.sig); &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))) if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet"); err(1, "Writing out packet");

View File

@@ -24,45 +24,49 @@ int main(int argc, char *argv[])
const tal_t *ctx = tal_arr(NULL, char, 0); const tal_t *ctx = tal_arr(NULL, char, 0);
struct sha256 seed, revocation_hash, our_rhash, their_rhash, preimage; struct sha256 seed, revocation_hash, our_rhash, their_rhash, preimage;
OpenChannel *o1, *o2; OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
UpdateSignature *us; UpdateSignature *us;
Update *update; Update *update;
struct pkt *pkt; struct pkt *pkt;
struct bitcoin_tx *anchor, *commit; struct bitcoin_tx *commit;
struct pubkey pubkey1, pubkey2; struct pubkey pubkey1, pubkey2, final1, final2;
size_t i, num_updates, p2sh_out; size_t i, num_updates, inmap[2];
struct sha256_double anchor_txid; struct sha256_double anchor_txid1, anchor_txid2;
struct bitcoin_signature sig; struct sha256 escape_hash1, escape_hash2;
int64_t delta; int64_t delta;
u8 *redeemscript;
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create a new update-complete message",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 7) if (argc < 8)
opt_usage_exit_fail("Expected 6+ arguments"); opt_usage_exit_fail("Expected 7+ arguments");
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
anchor = bitcoin_tx_from_file(ctx, argv[2]); o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
bitcoin_txid(anchor, &anchor_txid); proto_to_sha256(o1->escape_hash, &escape_hash1);
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
o2 = pkt_from_file(argv[4], PKT__PKT_OPEN)->open; proto_to_sha256(o2->escape_hash, &escape_hash2);
update = pkt_from_file(argv[5], PKT__PKT_UPDATE)->update; oa1 = pkt_from_file(argv[4], PKT__PKT_OPEN_ANCHOR)->open_anchor;
us = pkt_from_file(argv[6], PKT__PKT_UPDATE_SIGNATURE)->update_signature; 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), /* We need last revocation hash (either in update or update-accept),
* and the delta */ * and the delta */
proto_to_sha256(o2->revocation_hash, &revocation_hash); proto_to_sha256(o2->revocation_hash, &revocation_hash);
num_updates = 0; num_updates = 0;
delta = update->delta; delta = update->delta;
for (i = 7; i < argc; i++) { for (i = 8; i < argc; i++) {
Pkt *p = any_pkt_from_file(argv[i]); Pkt *p = any_pkt_from_file(argv[i]);
switch (p->pkt_case) { switch (p->pkt_case) {
case PKT__PKT_UPDATE: case PKT__PKT_UPDATE:
@@ -89,30 +93,30 @@ int main(int argc, char *argv[])
errx(1, "Their preimage was incorrect"); errx(1, "Their preimage was incorrect");
/* Get pubkeys */ /* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey1)) if (!proto_to_pubkey(o1->commitkey, &pubkey1))
errx(1, "Invalid o1 commit pubkey"); 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"); 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. */ /* Check their signature signs our new commit tx correctly. */
shachain_from_seed(&seed, num_updates + 1, &preimage); shachain_from_seed(&seed, num_updates + 1, &preimage);
sha256(&our_rhash, &preimage, sizeof(preimage)); sha256(&our_rhash, &preimage, sizeof(preimage));
commit = create_commit_tx(ctx, o1, o2, &our_rhash, delta, 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) if (!commit)
errx(1, "Delta too large"); errx(1, "Delta too large");
sig.stype = SIGHASH_ALL; if (!check_anchor_spend(commit, inmap,
if (!proto_to_signature(us->sig, &sig.sig)) &pubkey1, &final1, &escape_hash1,
errx(1, "Invalid update-signature signature"); &pubkey2, &final2, &escape_hash2,
&pubkey2, us->sigs))
if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript), errx(1, "Bad signatures");
&pubkey2, &sig))
errx(1, "Invalid signature.");
/* Hand over our preimage for previous tx. */ /* Hand over our preimage for previous tx. */
shachain_from_seed(&seed, num_updates, &preimage); shachain_from_seed(&seed, num_updates, &preimage);

View File

@@ -22,107 +22,110 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const tal_t *ctx = tal_arr(NULL, char, 0); 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; OpenChannel *o1, *o2;
OpenAnchor *oa1, *oa2;
UpdateAccept *ua; UpdateAccept *ua;
Update *update; Update *update;
struct bitcoin_tx *anchor, *commit; struct bitcoin_tx *commit;
struct sha256_double anchor_txid; struct sha256_double anchor_txid1, anchor_txid2;
struct pkt *pkt; struct pkt *pkt;
struct bitcoin_signature sig; struct signature sigs[2];
struct privkey privkey; struct privkey privkey;
bool testnet; bool testnet;
struct pubkey pubkey1, pubkey2; struct pubkey pubkey1, pubkey2, final1, final2;
u8 *redeemscript;
int64_t delta; int64_t delta;
size_t i, p2sh_out; size_t i, inmap[2];
err_set_progname(argv[0]); err_set_progname(argv[0]);
opt_register_noarg("--help|-h", opt_usage_and_exit, 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", "Create a new update-channel-signature message",
"Print this message."); "Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit); opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc < 8) if (argc < 9)
opt_usage_exit_fail("Expected 7+ arguments"); opt_usage_exit_fail("Expected 8+ arguments");
if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed))) if (!hex_decode(argv[1], strlen(argv[1]), &seed, sizeof(seed)))
errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]); errx(1, "Invalid seed '%s' - need 256 hex bits", argv[1]);
anchor = bitcoin_tx_from_file(ctx, argv[2]); o1 = pkt_from_file(argv[2], PKT__PKT_OPEN)->open;
bitcoin_txid(anchor, &anchor_txid); proto_to_sha256(o1->escape_hash, &escape_hash1);
o1 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open; o2 = pkt_from_file(argv[3], PKT__PKT_OPEN)->open;
o2 = pkt_from_file(argv[4], 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[5], strlen(argv[5]), &testnet, &privkey, &pubkey1)) if (!key_from_base58(argv[6], strlen(argv[6]), &testnet, &privkey, &pubkey1))
errx(1, "Invalid private key '%s'", argv[5]); errx(1, "Invalid private key '%s'", argv[6]);
if (!testnet) 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;
ua = pkt_from_file(argv[7], PKT__PKT_UPDATE_ACCEPT)->update_accept; ua = pkt_from_file(argv[8], PKT__PKT_UPDATE_ACCEPT)->update_accept;
sig.stype = SIGHASH_ALL;
if (!proto_to_signature(ua->sig, &sig.sig))
errx(1, "Invalid update signature");
/* Figure out cumulative delta since anchor. */ /* Figure out cumulative delta since anchor. */
delta = 0; 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; Update *u = pkt_from_file(argv[i], PKT__PKT_UPDATE)->update;
delta += u->delta; delta += u->delta;
} }
/* Give up revocation preimage for old tx. */ /* 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 */ /* Get pubkeys */
if (!proto_to_pubkey(o1->anchor->pubkey, &pubkey2)) if (!proto_to_pubkey(o1->commitkey, &pubkey2))
errx(1, "Invalid o1 commit pubkey"); errx(1, "Invalid o1 commit pubkey");
if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2)
|| memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0)
errx(1, "o1 pubkey != this privkey"); 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"); 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. */ /* Check our new commit is signed correctly by them. */
proto_to_sha256(update->revocation_hash, &revocation_hash); proto_to_sha256(update->revocation_hash, &revocation_hash);
commit = create_commit_tx(ctx, o1, o2, &revocation_hash, delta, 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) if (!commit)
errx(1, "Delta too large"); errx(1, "Delta too large");
/* Check their signature signs this input correctly. */ /* Check their signatures sign this input correctly. */
if (!check_tx_sig(commit, 0, redeemscript, tal_count(redeemscript), if (!check_anchor_spend(commit, inmap, &pubkey1, &final1, &escape_hash1,
&pubkey2, &sig)) &pubkey2, &final2, &escape_hash2,
errx(1, "Invalid signature."); &pubkey2, ua->sigs))
errx(1, "Invalid signatures");
/* Now create THEIR new commitment tx to spend 2/2 output of anchor. */ /* Now create THEIR new commitment tx to spend 2/2 output of anchor. */
proto_to_sha256(ua->revocation_hash, &revocation_hash); proto_to_sha256(ua->revocation_hash, &revocation_hash);
commit = create_commit_tx(ctx, o2, o1, &revocation_hash, -delta, commit = create_commit_tx(ctx, o2, o1, &revocation_hash, -delta,
&anchor_txid, &anchor_txid2, oa2->index, o2->total_input,
find_p2sh_out(anchor, redeemscript)); &anchor_txid1, oa1->index, o1->total_input,
inmap);
/* If contributions don't exceed fees, this fails. */ /* If contributions don't exceed fees, this fails. */
if (!commit) if (!commit)
errx(1, "Delta too large"); errx(1, "Delta too large");
/* Their pubkey must be valid */ /* Sign it for them (since its theirs, reverse args). */
if (!proto_to_pubkey(o2->anchor->pubkey, &pubkey2)) if (!sign_anchor_spend(commit, inmap, &pubkey2, &final2, &escape_hash2,
errx(1, "Invalid public open-channel-file2"); &pubkey1, &final1, &escape_hash1,
&pubkey1, &privkey, sigs))
errx(1, "Failed creating signatures");
/* Sign it for them. */ pkt = update_signature_pkt(ctx, sigs, &preimage);
sign_tx_input(ctx, commit, 0, redeemscript, tal_count(redeemscript),
&privkey, &pubkey1, &sig.sig);
pkt = update_signature_pkt(ctx, &sig.sig, &preimage);
if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt))) if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt)))
err(1, "Writing out packet"); err(1, "Writing out packet");

View File

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