Browse Source
This is a major change; instead of creating a mutual anchor (funding) transaction, each side creates its own. We use escape transactions in case anything goes wrong; these will be revoked later. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
10 years ago
33 changed files with 1607 additions and 1586 deletions
@ -1,165 +1,200 @@ |
|||
#include <ccan/err/err.h> |
|||
#include "anchor.h" |
|||
#include "bitcoin/pubkey.h" |
|||
#include "bitcoin/script.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "overflows.h" |
|||
#include "permute_tx.h" |
|||
#include "pkt.h" |
|||
#include "protobuf_convert.h" |
|||
|
|||
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx, |
|||
const OpenChannel *o1, |
|||
const OpenChannel *o2, |
|||
size_t **inmapp, size_t **outmapp) |
|||
#undef DEBUG |
|||
#ifdef DEBUG |
|||
#include <stdio.h> |
|||
#include "bitcoin/pubkey.h" |
|||
|
|||
static void dump_anchor_spend(const char *what, |
|||
size_t input, |
|||
const struct pubkey *commitkey1, |
|||
const struct pubkey *commitkey2, |
|||
const struct pubkey *finalkey, |
|||
const struct sha256 *escapehash, |
|||
const struct pubkey *signingkey, |
|||
const struct signature *sig) |
|||
{ |
|||
size_t i; |
|||
fprintf(stderr, "%s input %zu:", what, input); |
|||
fprintf(stderr, " commitkey1="); |
|||
for (i = 0; i < pubkey_len(commitkey1); i++) |
|||
fprintf(stderr, "%02x", commitkey1->key[i]); |
|||
fprintf(stderr, " commitkey2="); |
|||
for (i = 0; i < pubkey_len(commitkey2); i++) |
|||
fprintf(stderr, "%02x", commitkey2->key[i]); |
|||
fprintf(stderr, " finalkey="); |
|||
for (i = 0; i < pubkey_len(finalkey); i++) |
|||
fprintf(stderr, "%02x", finalkey->key[i]); |
|||
fprintf(stderr, " escapehash="); |
|||
for (i = 0; i < sizeof(escapehash->u.u8); i++) |
|||
fprintf(stderr, "%02x", escapehash->u.u8[i]); |
|||
fprintf(stderr, " signingkey="); |
|||
for (i = 0; i < pubkey_len(signingkey); i++) |
|||
fprintf(stderr, "%02x", signingkey->key[i]); |
|||
fprintf(stderr, " -> sig {r="); |
|||
for (i = 0; i < sizeof(sig->r); i++) |
|||
fprintf(stderr, "%02x", sig->r[i]); |
|||
fprintf(stderr, ", s="); |
|||
for (i = 0; i < sizeof(sig->s); i++) |
|||
fprintf(stderr, "%02x", sig->s[i]); |
|||
fprintf(stderr, "}\n"); |
|||
} |
|||
#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 |
|||
|
|||
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]) |
|||
{ |
|||
uint64_t i, n_out; |
|||
struct bitcoin_tx *tx; |
|||
const tal_t *ctx = tal(NULL, char); |
|||
u8 *redeemscript; |
|||
size_t *inmap, *outmap; |
|||
struct pubkey key1, key2; |
|||
uint64_t total_in = 0, total_change = 0; |
|||
|
|||
if (add_overflows_size_t(o1->anchor->n_inputs, o2->anchor->n_inputs)) |
|||
return NULL; |
|||
|
|||
n_out = 1 + !!o1->anchor->change + !!o2->anchor->change; |
|||
tx = bitcoin_tx(ctx, o1->anchor->n_inputs+o2->anchor->n_inputs, n_out); |
|||
|
|||
/* Override version to use lesser of two versions. */ |
|||
if (o1->tx_version < o2->tx_version) |
|||
tx->version = o1->tx_version; |
|||
else |
|||
tx->version = o2->tx_version; |
|||
|
|||
/* Populate inputs. */ |
|||
for (i = 0; i < o1->anchor->n_inputs; i++) { |
|||
BitcoinInput *pb = o1->anchor->inputs[i]; |
|||
struct bitcoin_tx_input *in = &tx->input[i]; |
|||
proto_to_sha256(pb->txid, &in->txid.sha); |
|||
in->index = pb->output; |
|||
in->input_amount = pb->amount; |
|||
if (add_overflows_u64(total_in, in->input_amount)) |
|||
return tal_free(tx); |
|||
total_in += in->input_amount; |
|||
/* Leave inputs as stubs for now, for signing. */ |
|||
} |
|||
for (i = 0; i < o2->anchor->n_inputs; i++) { |
|||
BitcoinInput *pb = o2->anchor->inputs[i]; |
|||
struct bitcoin_tx_input *in |
|||
= &tx->input[o1->anchor->n_inputs + i]; |
|||
proto_to_sha256(pb->txid, &in->txid.sha); |
|||
in->index = pb->output; |
|||
in->input_amount = pb->amount; |
|||
if (add_overflows_u64(total_in, in->input_amount)) |
|||
return tal_free(tx); |
|||
total_in += in->input_amount; |
|||
/* Leave inputs as stubs for now, for signing. */ |
|||
} |
|||
|
|||
/* 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; |
|||
bool ret; |
|||
|
|||
/* Sign input for our anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey, |
|||
their_finalkey, my_escapehash); |
|||
ret = sign_tx_input(ctx, tx, inmap[0], |
|||
redeemscript, tal_count(redeemscript), |
|||
signing_privkey, signing_pubkey, &sig[inmap[0]]); |
|||
dump_anchor_spend("signed from_mine", inmap[0], |
|||
my_commitkey, their_commitkey, their_finalkey, |
|||
my_escapehash, signing_pubkey, &sig[inmap[0]]); |
|||
|
|||
/* Sign input for their anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey, |
|||
my_finalkey, their_escapehash); |
|||
ret &= sign_tx_input(ctx, tx, inmap[1], |
|||
redeemscript, tal_count(redeemscript), |
|||
signing_privkey, signing_pubkey, &sig[inmap[1]]); |
|||
|
|||
dump_anchor_spend("signed from_yours", inmap[1], |
|||
their_commitkey, my_commitkey, my_finalkey, |
|||
their_escapehash, signing_pubkey, &sig[inmap[1]]); |
|||
tal_free(ctx); |
|||
return ret; |
|||
} |
|||
|
|||
/* This may create an invalid anchor. That's actually OK, as the bitcoin
|
|||
* network won't accept it and we'll ds our way out. */ |
|||
bool anchor_add_scriptsigs(struct bitcoin_tx *anchor, |
|||
OpenAnchorScriptsigs *ssigs1, |
|||
OpenAnchorScriptsigs *ssigs2, |
|||
const size_t *inmap) |
|||
/* Check that their sigs sign this tx as expected. */ |
|||
bool check_anchor_spend(struct bitcoin_tx *tx, |
|||
const size_t inmap[2], |
|||
const struct pubkey *my_commitkey, |
|||
const struct pubkey *my_finalkey, |
|||
const struct sha256 *my_escapehash, |
|||
const struct pubkey *their_commitkey, |
|||
const struct pubkey *their_finalkey, |
|||
const struct sha256 *their_escapehash, |
|||
const struct pubkey *signing_pubkey, |
|||
const AnchorSpend *their_sigs) |
|||
{ |
|||
size_t i; |
|||
const tal_t *ctx; |
|||
u8 *redeemscript; |
|||
bool ret; |
|||
struct bitcoin_signature sigs[2]; |
|||
|
|||
if (ssigs1->n_script + ssigs2->n_script != anchor->input_count) |
|||
return NULL; |
|||
sigs[0].stype = sigs[1].stype = SIGHASH_ALL; |
|||
|
|||
for (i = 0; i < ssigs1->n_script; i++) { |
|||
size_t n = inmap[i]; |
|||
anchor->input[n].script = ssigs1->script[i].data; |
|||
anchor->input[n].script_length = ssigs1->script[i].len; |
|||
} |
|||
if (!proto_to_signature(their_sigs->sig0, &sigs[0].sig) |
|||
|| !proto_to_signature(their_sigs->sig1, &sigs[1].sig)) |
|||
return false; |
|||
|
|||
for (i = 0; i < ssigs2->n_script; i++) { |
|||
size_t n = inmap[ssigs1->n_script + i]; |
|||
anchor->input[n].script = ssigs2->script[i].data; |
|||
anchor->input[n].script_length = ssigs2->script[i].len; |
|||
} |
|||
ctx = tal(NULL, char); |
|||
|
|||
return true; |
|||
/* Input for our anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey, |
|||
their_finalkey, my_escapehash); |
|||
ret = check_tx_sig(tx, inmap[0], redeemscript, tal_count(redeemscript), |
|||
signing_pubkey, &sigs[inmap[0]]); |
|||
|
|||
dump_anchor_spend("checking from_mine", inmap[0], |
|||
my_commitkey, their_commitkey, their_finalkey, |
|||
my_escapehash, signing_pubkey, &sigs[inmap[0]].sig); |
|||
|
|||
/* Input for their anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey, |
|||
my_finalkey, their_escapehash); |
|||
ret &= check_tx_sig(tx, inmap[1], redeemscript, tal_count(redeemscript), |
|||
signing_pubkey, &sigs[inmap[1]]); |
|||
|
|||
dump_anchor_spend("checking from_yours", inmap[1], |
|||
their_commitkey, my_commitkey, my_finalkey, |
|||
their_escapehash, signing_pubkey, &sigs[inmap[1]].sig); |
|||
|
|||
tal_free(ctx); |
|||
return ret; |
|||
} |
|||
|
|||
void anchor_txid(struct bitcoin_tx *anchor, struct sha256_double *txid) |
|||
|
|||
/* Set up input scriptsigs for this transaction. */ |
|||
bool populate_anchor_inscripts(const tal_t *ctx, |
|||
struct bitcoin_tx *tx, |
|||
const size_t inmap[2], |
|||
const struct pubkey *my_commitkey, |
|||
const struct pubkey *my_finalkey, |
|||
const struct sha256 *my_escapehash, |
|||
const struct pubkey *their_commitkey, |
|||
const struct pubkey *their_finalkey, |
|||
const struct sha256 *their_escapehash, |
|||
const AnchorSpend *my_sigs, |
|||
const AnchorSpend *their_sigs) |
|||
{ |
|||
bitcoin_txid(anchor, txid); |
|||
u8 *redeemscript; |
|||
struct bitcoin_signature theirs[2], mine[2]; |
|||
|
|||
theirs[0].stype = theirs[1].stype = mine[0].stype = mine[1].stype |
|||
= SIGHASH_ALL; |
|||
|
|||
if (!proto_to_signature(their_sigs->sig0, &theirs[0].sig) |
|||
|| !proto_to_signature(their_sigs->sig1, &theirs[1].sig) |
|||
|| !proto_to_signature(my_sigs->sig0, &mine[0].sig) |
|||
|| !proto_to_signature(my_sigs->sig1, &mine[1].sig)) |
|||
return false; |
|||
|
|||
/* Input for our anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, my_commitkey, their_commitkey, |
|||
their_finalkey, my_escapehash); |
|||
|
|||
tx->input[inmap[0]].script |
|||
= scriptsig_p2sh_anchor_commit(ctx, |
|||
&theirs[inmap[0]], |
|||
&mine[inmap[0]], |
|||
redeemscript, |
|||
tal_count(redeemscript)); |
|||
tal_free(redeemscript); |
|||
|
|||
/* Input for their anchor. */ |
|||
redeemscript = bitcoin_redeem_anchor(ctx, their_commitkey, my_commitkey, |
|||
my_finalkey, their_escapehash); |
|||
/* They created their anchor to expect sigs in other order. */ |
|||
tx->input[inmap[1]].script |
|||
= scriptsig_p2sh_anchor_commit(ctx, |
|||
&mine[inmap[1]], |
|||
&theirs[inmap[1]], |
|||
redeemscript, |
|||
tal_count(redeemscript)); |
|||
tal_free(redeemscript); |
|||
|
|||
/* Set up lengths. */ |
|||
tx->input[0].script_length = tal_count(tx->input[0].script); |
|||
tx->input[1].script_length = tal_count(tx->input[1].script); |
|||
|
|||
return true; |
|||
} |
|||
|
@ -1,31 +1,45 @@ |
|||
#ifndef LIGHTNING_ANCHOR_H |
|||
#define LIGHTNING_ANCHOR_H |
|||
#include <ccan/tal/tal.h> |
|||
#include "bitcoin/signature.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "lightning.pb-c.h" |
|||
|
|||
struct sha256_double; |
|||
/* Sign this transaction which spends the anchors. */ |
|||
bool sign_anchor_spend(struct bitcoin_tx *tx, |
|||
const size_t inmap[2], |
|||
const struct pubkey *my_commitkey, |
|||
const struct pubkey *my_finalkey, |
|||
const struct sha256 *my_escapehash, |
|||
const struct pubkey *their_commitkey, |
|||
const struct pubkey *their_finalkey, |
|||
const struct sha256 *their_escapehash, |
|||
const struct pubkey *signing_pubkey, |
|||
const struct privkey *signing_privkey, |
|||
struct signature sig[2]); |
|||
|
|||
/* Create an anchor transaction based on both sides' requests.
|
|||
* The scriptSigs are left empty. |
|||
* |
|||
* Allocate an input and output map (if non-NULL); the first |
|||
* o1->anchor->n_inputs of inmap are the location of o1's inputs, the |
|||
* next o2->anchor->n_inputs are o2's. outmap[0] is the location of |
|||
* output for the commitment tx, then o1's change (if |
|||
* o1->anchor->change), then o2's change if o2->anchor->change. |
|||
*/ |
|||
struct bitcoin_tx *anchor_tx_create(const tal_t *ctx, |
|||
const OpenChannel *o1, |
|||
const OpenChannel *o2, |
|||
size_t **inmap, size_t **outmap); |
|||
/* Check that their sigs sign this tx as expected. */ |
|||
bool check_anchor_spend(struct bitcoin_tx *tx, |
|||
const size_t inmap[2], |
|||
const struct pubkey *my_commitkey, |
|||
const struct pubkey *my_finalkey, |
|||
const struct sha256 *my_escapehash, |
|||
const struct pubkey *their_commitkey, |
|||
const struct pubkey *their_finalkey, |
|||
const struct sha256 *their_escapehash, |
|||
const struct pubkey *signing_pubkey, |
|||
const AnchorSpend *their_sigs); |
|||
|
|||
/* Add these scriptsigs to the anchor transaction. */ |
|||
bool anchor_add_scriptsigs(struct bitcoin_tx *anchor, |
|||
OpenAnchorScriptsigs *ssigs1, |
|||
OpenAnchorScriptsigs *ssigs2, |
|||
const size_t *inmap); |
|||
|
|||
/* We wouldn't need the leak files if we had normalized txids! */ |
|||
void anchor_txid(struct bitcoin_tx *anchor, |
|||
struct sha256_double *txid); |
|||
/* Set up input scriptsigs for this transaction. */ |
|||
bool populate_anchor_inscripts(const tal_t *ctx, |
|||
struct bitcoin_tx *tx, |
|||
const size_t inmap[2], |
|||
const struct pubkey *my_commitkey, |
|||
const struct pubkey *my_finalkey, |
|||
const struct sha256 *my_escapehash, |
|||
const struct pubkey *their_commitkey, |
|||
const struct pubkey *their_finalkey, |
|||
const struct sha256 *their_escapehash, |
|||
const AnchorSpend *my_sigs, |
|||
const AnchorSpend *their_sigs); |
|||
#endif /* LIGHTNING_ANCHOR_H */ |
|||
|
File diff suppressed because it is too large
@ -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; |
|||
} |
|||
|
@ -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; |
|||
} |
@ -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; |
|||
} |
Loading…
Reference in new issue