Browse Source

check-anchor-scriptsigs: dump out anchor tx if scriptsigs make expected tx.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 10 years ago
parent
commit
617d21eb43
  1. 6
      Makefile
  2. 42
      anchor.c
  3. 6
      anchor.h
  4. 151
      bitcoin_tx.c
  5. 3
      bitcoin_tx.h
  6. 83
      check-anchor-scriptsigs.c

6
Makefile

@ -3,7 +3,7 @@
# Needs to have oneof support: Ubuntu vivid's is too old :(
PROTOCC:=protoc-c
PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig
PROGRAMS := open-channel open-anchor-scriptsigs leak-anchor-sigs open-commit-sig check-commit-sig check-anchor-scriptsigs
HELPER_OBJS := base58.o lightning.pb-c.o shadouble.o pkt.o bitcoin_script.o permute_tx.o signature.o bitcoin_tx.o bitcoin_address.o anchor.o commit_tx.o pubkey.o
@ -13,6 +13,7 @@ OPEN_CHANNEL_OBJS := open-channel.o
OPEN_ANCHOR_SCRIPTSIGS_OBJS := open-anchor-scriptsigs.o
LEAK_ANCHOR_SIGS_OBJS := leak-anchor-sigs.o
OPEN_COMMIT_SIG_OBJS := open-commit-sig.o
CHECK_ANCHOR_SCRIPTSIGS_OBJS := check-anchor-scriptsigs.o
HEADERS := $(wildcard *.h)
@ -40,6 +41,9 @@ $(OPEN_COMMIT_SIG_OBJS): $(HEADERS)
check-commit-sig: $(CHECK_COMMIT_SIG_OBJS) $(HELPER_OBJS) $(CCAN_OBJS)
$(CHECK_COMMIT_SIG_OBJS): $(HEADERS)
check-anchor-scriptsigs: $(CHECK_ANCHOR_SCRIPTSIGS_OBJS) $(HELPER_OBJS) $(CCAN_OBJS)
$(CHECK_ANCHOR_SCRIPTSIGS_OBJS): $(HEADERS)
distclean: clean
$(RM) lightning.pb-c.c lightning.pb-c.h

42
anchor.c

@ -95,6 +95,33 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
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;
if (ssigs1->n_script + ssigs2->n_script != anchor->input_count)
return NULL;
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;
}
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;
}
return true;
}
void anchor_txid(struct bitcoin_tx *anchor,
const char *leakfile1, const char *leakfile2,
const size_t *inmap,
@ -102,30 +129,17 @@ void anchor_txid(struct bitcoin_tx *anchor,
{
Pkt *p1, *p2;
LeakAnchorSigsAndPretendWeDidnt *leak1, *leak2;
size_t i;
p1 = pkt_from_file(leakfile1, PKT__PKT_OMG_FAIL);
p2 = pkt_from_file(leakfile2, PKT__PKT_OMG_FAIL);
leak1 = p1->omg_fail;
leak2 = p2->omg_fail;
if (leak1->sigs->n_script + leak2->sigs->n_script != anchor->input_count)
if (!anchor_add_scriptsigs(anchor, leak1->sigs, leak2->sigs, inmap))
errx(1, "Expected %llu total inputs, not %zu + %zu",
(long long)anchor->input_count,
leak1->sigs->n_script, leak2->sigs->n_script);
for (i = 0; i < leak1->sigs->n_script; i++) {
size_t n = inmap[i];
anchor->input[n].script = leak1->sigs->script[i].data;
anchor->input[n].script_length = leak1->sigs->script[i].len;
}
for (i = 0; i < leak2->sigs->n_script; i++) {
size_t n = inmap[leak1->sigs->n_script + i];
anchor->input[n].script = leak2->sigs->script[i].data;
anchor->input[n].script_length = leak2->sigs->script[i].len;
}
bitcoin_txid(anchor, txid);
pkt__free_unpacked(p1, NULL);

6
anchor.h

@ -19,6 +19,12 @@ struct bitcoin_tx *anchor_tx_create(const tal_t *ctx,
const OpenChannel *o2,
size_t **inmap, size_t **outmap);
/* 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,
const char *leakfile1, const char *leakfile2,

151
bitcoin_tx.c

@ -1,5 +1,8 @@
#include "bitcoin_tx.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/err/err.h>
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/str/hex/hex.h>
#include <ccan/endian/endian.h>
#include <assert.h>
@ -136,3 +139,151 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count,
return tx;
}
/* Sets *cursor to NULL and returns NULL when a pull fails. */
static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n)
{
const u8 *p = *cursor;
if (*max < n) {
*cursor = NULL;
*max = 0;
/* Just make sure we don't leak uninitialized mem! */
if (copy)
memset(copy, 0, n);
return NULL;
}
*cursor += n;
*max -= n;
if (copy)
memcpy(copy, p, n);
return p;
}
static u64 pull_varint(const u8 **cursor, size_t *max)
{
u64 ret;
const u8 *p;
p = pull(cursor, max, NULL, 1);
if (!p)
return 0;
if (*p < 0xfd) {
ret = *p;
} else if (*p == 0xfd) {
p = pull(cursor, max, NULL, 2);
if (!p)
return 0;
ret = ((u64)p[2] << 8) + p[1];
} else if (*p == 0xfe) {
p = pull(cursor, max, NULL, 4);
if (!p)
return 0;
ret = ((u64)p[4] << 24) + ((u64)p[3] << 16)
+ ((u64)p[2] << 8) + p[1];
} else {
p = pull(cursor, max, NULL, 8);
if (!p)
return 0;
ret = ((u64)p[8] << 56) + ((u64)p[7] << 48)
+ ((u64)p[6] << 40) + ((u64)p[5] << 32)
+ ((u64)p[4] << 24) + ((u64)p[3] << 16)
+ ((u64)p[2] << 8) + p[1];
}
return ret;
}
static u32 pull_le32(const u8 **cursor, size_t *max)
{
le32 ret;
if (!pull(cursor, max, &ret, sizeof(ret)))
return 0;
return le32_to_cpu(ret);
}
static u64 pull_le64(const u8 **cursor, size_t *max)
{
le64 ret;
if (!pull(cursor, max, &ret, sizeof(ret)))
return 0;
return le64_to_cpu(ret);
}
static bool pull_sha256_double(const u8 **cursor, size_t *max,
struct sha256_double *h)
{
return pull(cursor, max, h, sizeof(*h));
}
static void pull_input(const tal_t *ctx, const u8 **cursor, size_t *max,
struct bitcoin_tx_input *input)
{
pull_sha256_double(cursor, max, &input->txid);
input->index = pull_le32(cursor, max);
input->script_length = pull_varint(cursor, max);
input->script = tal_arr(ctx, u8, input->script_length);
pull(cursor, max, input->script, input->script_length);
input->sequence_number = pull_le32(cursor, max);
}
static void pull_output(const tal_t *ctx, const u8 **cursor, size_t *max,
struct bitcoin_tx_output *output)
{
output->amount = pull_le64(cursor, max);
output->script_length = pull_varint(cursor, max);
output->script = tal_arr(ctx, u8, output->script_length);
pull(cursor, max, output->script, output->script_length);
}
static struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx,
const u8 **cursor, size_t *max)
{
struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx);
size_t i;
tx->version = pull_le32(cursor, max);
tx->input_count = pull_varint(cursor, max);
tx->input = tal_arr(tx, struct bitcoin_tx_input, tx->input_count);
for (i = 0; i < tx->input_count; i++)
pull_input(tx, cursor, max, tx->input + i);
tx->output_count = pull_varint(cursor, max);
tx->output = tal_arr(ctx, struct bitcoin_tx_output, tx->output_count);
for (i = 0; i < tx->output_count; i++)
pull_output(tx, cursor, max, tx->output + i);
tx->lock_time = pull_le32(cursor, max);
/* If we ran short, or have bytes left over, fail. */
if (!*cursor || *max != 0)
tx = tal_free(tx);
return tx;
}
struct bitcoin_tx *bitcoin_tx_from_file(const tal_t *ctx,
const char *filename)
{
char *hex;
u8 *linear_tx;
const u8 *p;
struct bitcoin_tx *tx;
size_t len;
/* Grabs file, add nul at end. */
hex = grab_file(ctx, filename);
if (!hex)
err(1, "Opening %s", filename);
len = hex_data_size(tal_count(hex)-1);
p = linear_tx = tal_arr(hex, u8, len);
if (!hex_decode(hex, tal_count(hex)-1, linear_tx, len))
errx(1, "Bad hex string in %s", filename);
tx = pull_bitcoin_tx(ctx, &p, &len);
if (!tx)
errx(1, "Bad transaction in %s", filename);
tal_free(hex);
return tx;
}

3
bitcoin_tx.h

@ -47,4 +47,7 @@ u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx);
struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count,
varint_t output_count);
struct bitcoin_tx *bitcoin_tx_from_file(const tal_t *ctx,
const char *filename);
#endif /* LIGHTNING_BITCOIN_TX_H */

83
check-anchor-scriptsigs.c

@ -0,0 +1,83 @@
/* My example:
* ./check-anchor-scriptsigs A-open.pb B-open.pb A-anchor-scriptsigs.pb B-anchor-scriptsigs.pb A-commit.tx B-commit.tx > A-anchor.tx
* ./check-anchor-scriptsigs B-open.pb A-open.pb B-anchor-scriptsigs.pb A-anchor-scriptsigs.pb B-commit.tx A-commit.tx > B-anchor.tx
*/
#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 <ccan/structeq/structeq.h>
#include "lightning.pb-c.h"
#include "anchor.h"
#include "base58.h"
#include "pkt.h"
#include "bitcoin_script.h"
#include "permute_tx.h"
#include "signature.h"
#include "commit_tx.h"
#include "pubkey.h"
#include <openssl/ec.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, *commit1, *commit2;
struct sha256_double txid;
u8 *tx_arr;
size_t *inmap, *outmap;
char *tx_hex;
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> <commit-tx1> <commit-tx2>\n"
"Output the anchor transaction by merging the scriptsigs",
"Print this message.");
opt_parse(&argc, argv, opt_log_stderr_exit);
if (argc != 7)
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;
commit1 = bitcoin_tx_from_file(ctx, argv[5]);
commit2 = bitcoin_tx_from_file(ctx, argv[6]);
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);
/* Now check that the txid is spent by the commitment txs we created */
assert(commit1->input_count == 1 && commit2->input_count == 1);
if (!structeq(&txid, &commit1->input[0].txid))
errx(1, "%s doesn't spend this anchor", argv[5]);
if (!structeq(&txid, &commit2->input[0].txid))
errx(1, "%s doesn't spend this anchor", argv[6]);
/* Print it out in hex. */
tx_arr = linearize_tx(ctx, anchor);
tx_hex = tal_arr(tx_arr, char, hex_str_size(tal_count(tx_arr)));
hex_encode(tx_arr, tal_count(tx_arr), tx_hex, tal_count(tx_hex));
if (!write_all(STDOUT_FILENO, tx_hex, strlen(tx_hex)))
err(1, "Writing out anchor transaction");
tal_free(ctx);
return 0;
}
Loading…
Cancel
Save