diff --git a/Makefile b/Makefile index 44fd2d0d1..5b0dc9959 100644 --- a/Makefile +++ b/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 diff --git a/anchor.c b/anchor.c index 470f54215..a9f2f5292 100644 --- a/anchor.c +++ b/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); diff --git a/anchor.h b/anchor.h index d26922eb2..e15626211 100644 --- a/anchor.h +++ b/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, diff --git a/bitcoin_tx.c b/bitcoin_tx.c index 5a0ca0a98..3dde38194 100644 --- a/bitcoin_tx.c +++ b/bitcoin_tx.c @@ -1,5 +1,8 @@ #include "bitcoin_tx.h" #include +#include +#include +#include #include #include @@ -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; +} diff --git a/bitcoin_tx.h b/bitcoin_tx.h index 2c0d4dd53..0590b6014 100644 --- a/bitcoin_tx.h +++ b/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 */ diff --git a/check-anchor-scriptsigs.c b/check-anchor-scriptsigs.c new file mode 100644 index 000000000..8485ff729 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#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 +#include + +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, + " \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; +} +