mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 23:54:22 +01:00
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:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -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
|
||||||
|
|
||||||
|
|||||||
339
anchor.c
339
anchor.c
@@ -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]]);
|
||||||
|
|
||||||
for (i = 0; i < ssigs2->n_script; i++) {
|
/* Sign input for their anchor. */
|
||||||
size_t n = inmap[ssigs1->n_script + i];
|
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey,
|
||||||
anchor->input[n].script = ssigs2->script[i].data;
|
my_finalkey, their_escapehash);
|
||||||
anchor->input[n].script_length = ssigs2->script[i].len;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that their sigs sign this tx as expected. */
|
||||||
|
bool check_anchor_spend(struct bitcoin_tx *tx,
|
||||||
|
const size_t inmap[2],
|
||||||
|
const struct pubkey *my_commitkey,
|
||||||
|
const struct pubkey *my_finalkey,
|
||||||
|
const struct sha256 *my_escapehash,
|
||||||
|
const struct pubkey *their_commitkey,
|
||||||
|
const struct pubkey *their_finalkey,
|
||||||
|
const struct sha256 *their_escapehash,
|
||||||
|
const struct pubkey *signing_pubkey,
|
||||||
|
const AnchorSpend *their_sigs)
|
||||||
|
{
|
||||||
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
60
anchor.h
60
anchor.h
@@ -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 */
|
||||||
|
|||||||
32
close_tx.c
32
close_tx.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
37
commit_tx.c
37
commit_tx.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
771
lightning.pb-c.c
771
lightning.pb-c.c
File diff suppressed because it is too large
Load Diff
338
lightning.pb-c.h
338
lightning.pb-c.h
@@ -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;
|
||||||
|
|||||||
@@ -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
72
pkt.c
@@ -33,24 +33,25 @@ static struct pkt *to_pkt(const tal_t *ctx, Pkt__PktCase type, void *msg)
|
|||||||
|
|
||||||
struct pkt *openchannel_pkt(const tal_t *ctx,
|
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 *sig)
|
struct pkt *open_commit_sig_pkt(const tal_t *ctx, const struct signature *sigs)
|
||||||
{
|
{
|
||||||
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
48
pkt.h
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -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
188
test-cli/create-anchor-tx.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
79
test-cli/open-anchor-id.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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");
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
TXID=`$CLI listunspent | sed -n 's/^ *"txid" *: *"\([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`
|
OUTNUM=`$CLI listunspent | sed -n 's/^ *"vout" *: *\([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1`
|
||||||
$CLI dumpprivkey $ADDR
|
AMOUNT=`$CLI listunspent | sed -n 's/^ *"amount" *: *\([0-9.]*\),$/\1/p' | tail -n +$NUM | head -n1 | tr -d . | sed 's/^0*//'`
|
||||||
else
|
SCRIPT=`$CLI listunspent | sed -n 's/^ *"scriptPubKey" *: *"\([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`
|
ADDR=`$CLI listunspent | sed -n 's/^ *"address" *: *"\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1`
|
||||||
OUTNUM=`$CLI listunspent | sed -n 's/^ *"vout" *: *\([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1`
|
PRIVKEY=`$CLI dumpprivkey $ADDR`
|
||||||
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`
|
|
||||||
|
|
||||||
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT
|
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT/$PRIVKEY
|
||||||
fi
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 final pubkey");
|
errx(1, "Invalid o2 commit pubkey");
|
||||||
|
if (!proto_to_pubkey(o1->final, &final1))
|
||||||
/* This is what the anchor pays to; figure out whick output. */
|
errx(1, "Invalid o1 final pubkey");
|
||||||
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
|
if (!proto_to_pubkey(o2->final, &final2))
|
||||||
p2sh_out = find_p2sh_out(anchor, redeemscript);
|
errx(1, "Invalid o2 final pubkey");
|
||||||
|
|
||||||
/* 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");
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user