mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 10:46:58 +01:00
check-anchor-scriptsigs: dump out anchor tx if scriptsigs make expected tx.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
a6d1c65683
commit
617d21eb43
6 changed files with 276 additions and 15 deletions
6
Makefile
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
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
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
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;
|
||||
}
|
||||
|
|
|
@ -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
Normal file
83
check-anchor-scriptsigs.c
Normal file
|
@ -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…
Add table
Reference in a new issue