Browse Source

devtools: have mkcommit support HTLCs.

This allows for complete channel simulation, including HTLC
transactions, but means we use higher-level primitives to
make the easy.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pull/2938/head
Rusty Russell 6 years ago
committed by neil saitug
parent
commit
12d8be4fdc
  1. 2
      devtools/Makefile
  2. 362
      devtools/mkcommit.c

2
devtools/Makefile

@ -61,7 +61,7 @@ devtools/gen_print_onion_wire.o: devtools/gen_print_onion_wire.h devtools/print_
devtools/bolt11-cli: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/bolt11-cli.o
devtools/mkcommit: $(DEVTOOLS_COMMON_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) common/derive_basepoints.o common/keyset.o common/key_derive.o common/initial_commit_tx.o common/permute_tx.o wire/fromwire.o wire/towire.o devtools/mkcommit.o
devtools/mkcommit: $(DEVTOOLS_COMMON_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) common/derive_basepoints.o common/keyset.o common/key_derive.o common/initial_commit_tx.o common/permute_tx.o wire/fromwire.o wire/towire.o devtools/mkcommit.o channeld/full_channel.o common/initial_channel.o common/htlc_state.o common/pseudorand.o common/htlc_tx.o channeld/commit_tx.o common/htlc_trim.o
devtools/mkfunding: $(DEVTOOLS_COMMON_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o common/funding_tx.o common/utxo.o common/permute_tx.o common/key_derive.o devtools/mkfunding.o

362
devtools/mkcommit.c

@ -10,17 +10,36 @@
#include <bitcoin/tx.h>
#include <ccan/err/err.h>
#include <ccan/str/hex/hex.h>
#include <channeld/full_channel.h>
#include <common/amount.h>
#include <common/derive_basepoints.h>
#include <common/initial_commit_tx.h>
#include <common/htlc_wire.h>
#include <common/key_derive.h>
#include <common/keyset.h>
#include <common/status.h>
#include <common/type_to_string.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
static bool verbose = false;
void status_fmt(enum log_level level, const char *fmt, ...)
{
if (verbose) {
va_list ap;
va_start(ap, fmt);
printf("#TRACE: ");
vprintf(fmt, ap);
printf("\n");
va_end(ap);
}
}
void status_failed(enum status_failreason reason, const char *fmt, ...)
{
abort();
}
/* Code to make a commitment tx, useful for generating test cases. */
@ -111,24 +130,25 @@ static void print_basepoints(const char *desc,
type_to_string(NULL, struct pubkey, &per_commitment_point));
}
struct settings {
u32 to_self_delay;
struct amount_sat dustlimit;
struct amount_sat reserve;
};
static int parse_settings(char *argv[],
struct settings *settings,
const char *desc)
static int parse_config(char *argv[],
struct channel_config *config,
const char *desc)
{
int argnum = 0;
settings->to_self_delay = atoi(argv[argnum]);
config->id = 0;
/* FIXME: Allow overriding these on cmdline! */
config->max_htlc_value_in_flight = AMOUNT_MSAT(-1ULL);
config->htlc_minimum = AMOUNT_MSAT(0);
config->max_accepted_htlcs = 483;
config->to_self_delay = atoi(argv[argnum]);
argnum++;
if (!parse_amount_sat(&settings->dustlimit,
if (!parse_amount_sat(&config->dust_limit,
argv[argnum], strlen(argv[argnum])))
errx(1, "Bad %s dustlimit", desc);
argnum++;
if (!parse_amount_sat(&settings->reserve,
if (!parse_amount_sat(&config->channel_reserve,
argv[argnum], strlen(argv[argnum])))
errx(1, "Bad %s reserve", desc);
argnum++;
@ -145,6 +165,58 @@ static char *sig_as_hex(const struct bitcoin_signature *sig)
return tal_hexstr(NULL, compact_sig, sizeof(compact_sig));
}
static int parse_htlc(char *argv[],
struct added_htlc **htlcs,
enum htlc_state **htlc_states,
struct preimage **preimages)
{
struct added_htlc add;
int argnum = 0;
struct preimage preimage;
add.id = tal_count(*htlcs);
if (streq(argv[argnum], "local"))
tal_arr_expand(htlc_states, SENT_ADD_ACK_REVOCATION);
else if (streq(argv[argnum], "remote"))
tal_arr_expand(htlc_states, RCVD_ADD_ACK_REVOCATION);
else
errx(1, "Bad htlc offer: %s should be 'local' or 'remote'",
argv[argnum]);
argnum++;
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
&preimage, sizeof(preimage)))
errx(1, "Bad payment-preimage %s", argv[argnum]);
tal_arr_expand(preimages, preimage);
sha256(&add.payment_hash, &preimage, sizeof(preimage));
argnum++;
if (!parse_amount_msat(&add.amount,
argv[argnum], strlen(argv[argnum])))
errx(1, "Bad htlc amount %s", argv[argnum]);
argnum++;
add.cltv_expiry = atoi(argv[argnum]);
argnum++;
printf("# HTLC %"PRIu64": %s amount=%s preimage=%s payment_hash=%s cltv=%u\n",
add.id, argv[0],
type_to_string(tmpctx, struct amount_msat, &add.amount),
type_to_string(tmpctx, struct preimage, &preimage),
type_to_string(tmpctx, struct sha256, &add.payment_hash),
add.cltv_expiry);
tal_arr_expand(htlcs, add);
return argnum;
}
static const struct preimage *preimage_of(const struct sha256 *hash,
const struct added_htlc *htlcs,
const struct preimage *preimages)
{
for (size_t i = 0; i < tal_count(preimages); i++)
if (sha256_eq(hash, &htlcs[i].payment_hash))
return preimages + i;
abort();
}
int main(int argc, char *argv[])
{
struct secrets local, remote;
@ -155,26 +227,38 @@ int main(int argc, char *argv[])
struct amount_sat funding_amount;
struct bitcoin_txid funding_txid;
unsigned int funding_outnum;
unsigned int feerate_per_kw;
u32 feerate_per_kw[NUM_SIDES];
struct pubkey local_per_commit_point, remote_per_commit_point;
struct keyset localkeys, remotekeys;
struct bitcoin_signature local_sig, remote_sig;
struct settings localsettings, remotesettings;
struct channel_config localconfig, remoteconfig;
struct amount_msat local_msat, remote_msat;
int argnum;
struct bitcoin_tx *local_tx, *remote_tx;
struct bitcoin_tx **local_txs, **remote_txs;
enum side fee_payer;
char *err;
u8 **witness;
const u8 **wscripts;
struct channel *channel;
struct added_htlc *htlcs = tal_arr(NULL, struct added_htlc, 0);
enum htlc_state *hstates = tal_arr(NULL, enum htlc_state, 0);
struct preimage *preimages = tal_arr(NULL, struct preimage, 0);
const struct htlc **htlcmap;
struct privkey local_htlc_privkey, remote_htlc_privkey;
struct pubkey local_htlc_pubkey, remote_htlc_pubkey;
setup_locale();
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
SECP256K1_CONTEXT_SIGN);
if (argc != 1 + 7 + 3*2 + 6*2)
errx(1, "Usage: mkcommit <commitnum> <funding-txid> <funding-txout> <funding-amount> <feerate-per-kw> <local-msat> <fee-payer> <localsettings> <remotesettings> <remote-reserve> <localsecrets> <remotesecrets>\n"
"Where <settings> are:\n"
if (argv[1] && streq(argv[1], "-v")) {
verbose = true;
argv++;
argc--;
}
if (argc < 1 + 7 + 3*2 + 6*2)
errx(1, "Usage: mkcommit [-v] <commitnum> <funding-txid> <funding-txout> <funding-amount> <feerate-per-kw> <local-msat> <fee-payer> <localconfig> <remoteconfig> <remote-reserve> <localsecrets> <remotesecrets> [<htlc>...]\n"
"Where <config> are:\n"
" <to-self-delay>\n"
" <dustlimit>\n"
" <reserve-sat>\n"
@ -184,7 +268,12 @@ int main(int argc, char *argv[])
" <revocation-base-secret>\n"
" <payment-base-secret>\n"
" <delayed-payment-base-secret>\n"
" <htlc-base-secret>");
" <htlc-base-secret>\n"
"Where <htlc>s are:\n"
" <offer-side>\n"
" <payment-preimage>\n"
" <amount-msat>\n"
" <cltv-expiry>\n");
argnum = 1;
commitnum = atol(argv[argnum++]);
@ -196,7 +285,7 @@ int main(int argc, char *argv[])
if (!parse_amount_sat(&funding_amount, argv[argnum], strlen(argv[argnum])))
errx(1, "Bad funding-amount");
argnum++;
feerate_per_kw = atoi(argv[argnum++]);
feerate_per_kw[LOCAL] = feerate_per_kw[REMOTE] = atoi(argv[argnum++]);
if (!parse_amount_msat(&local_msat,
argv[argnum], strlen(argv[argnum])))
errx(1, "Bad local-msat");
@ -209,8 +298,8 @@ int main(int argc, char *argv[])
errx(1, "fee-payer must be 'local' or 'remote'");
argnum++;
argnum += parse_settings(argv + argnum, &localsettings, "local");
argnum += parse_settings(argv + argnum, &remotesettings, "remote");
argnum += parse_config(argv + argnum, &localconfig, "local");
argnum += parse_config(argv + argnum, &remoteconfig, "remote");
argnum += parse_secrets(argv + argnum, &local, &localseed, "local");
argnum += parse_secrets(argv + argnum, &remote, &remoteseed, "remote");
@ -218,6 +307,11 @@ int main(int argc, char *argv[])
if (!amount_sat_sub_msat(&remote_msat, funding_amount, local_msat))
errx(1, "Can't afford local_msat");
printf("## HTLCs\n");
while (argnum < argc)
argnum += parse_htlc(argv + argnum, &htlcs, &hstates, &preimages);
printf("\n");
if (!pubkey_from_privkey(&local.funding_privkey, &funding_localkey)
|| !pubkey_from_secret(&local.revocation_basepoint_secret,
&localbase.revocation)
@ -247,6 +341,21 @@ int main(int argc, char *argv[])
&remote, &remoteseed,
&remotebase, &funding_remotekey, commitnum);
channel = new_full_channel(NULL,
&chainparams_for_network("regtest")
->genesis_blockhash,
&funding_txid, funding_outnum, 1,
funding_amount,
local_msat,
feerate_per_kw,
&localconfig, &remoteconfig,
&localbase, &remotebase,
&funding_localkey, &funding_remotekey,
fee_payer);
if (!channel_force_htlcs(channel, htlcs, hstates, NULL, NULL, NULL, NULL))
errx(1, "Cannot add HTLCs");
u8 *funding_wscript = bitcoin_redeem_2of2(NULL,
&funding_localkey,
&funding_remotekey);
@ -255,27 +364,8 @@ int main(int argc, char *argv[])
if (!per_commit_point(&localseed, &local_per_commit_point, commitnum))
errx(1, "Bad deriving local per-commitment-point");
if (!derive_keyset(&local_per_commit_point, &localbase, &remotebase,
&localkeys))
errx(1, "Bad deriving local keyset");
local_tx = initial_commit_tx(NULL, &funding_txid, funding_outnum,
funding_amount, fee_payer,
localsettings.to_self_delay,
&localkeys,
feerate_per_kw,
localsettings.dustlimit,
local_msat,
remote_msat,
localsettings.reserve,
commitnum
^ commit_number_obscurer(&localbase.payment,
&remotebase.payment),
LOCAL, &err);
if (!local_tx)
errx(1, "Can't make local commit tx: %s", err);
local_tx->input_amounts[0]
= tal_dup(local_tx, struct amount_sat, &funding_amount);
local_txs = channel_txs(NULL, &htlcmap, &wscripts, channel,
&local_per_commit_point, commitnum, LOCAL);
printf("## local_commitment\n"
"# input amount %s, funding_wscript %s, key %s\n",
@ -283,16 +373,16 @@ int main(int argc, char *argv[])
tal_hex(NULL, funding_wscript),
type_to_string(NULL, struct pubkey, &funding_localkey));
printf("# unsigned local commitment tx: %s\n",
tal_hex(NULL, linearize_tx(NULL, local_tx)));
tal_hex(NULL, linearize_tx(NULL, local_txs[0])));
sign_tx_input(local_tx, 0, NULL, funding_wscript,
sign_tx_input(local_txs[0], 0, NULL, funding_wscript,
&local.funding_privkey,
&funding_localkey,
SIGHASH_ALL,
&local_sig);
printf("localsig_on_local: %s\n", sig_as_hex(&local_sig));
sign_tx_input(local_tx, 0, NULL, funding_wscript,
sign_tx_input(local_txs[0], 0, NULL, funding_wscript,
&remote.funding_privkey,
&funding_remotekey,
SIGHASH_ALL,
@ -302,36 +392,83 @@ int main(int argc, char *argv[])
witness =
bitcoin_witness_2of2(NULL, &local_sig, &remote_sig,
&funding_localkey, &funding_remotekey);
bitcoin_tx_input_set_witness(local_tx, 0, witness);
printf("# signed local commitment: %s\n\n",
tal_hex(NULL, linearize_tx(NULL, local_tx)));
bitcoin_tx_input_set_witness(local_txs[0], 0, witness);
printf("# signed local commitment: %s\n",
tal_hex(NULL, linearize_tx(NULL, local_txs[0])));
if (!derive_simple_privkey(&local.htlc_basepoint_secret,
&localbase.htlc,
&local_per_commit_point,
&local_htlc_privkey))
errx(1, "Failure deriving local htlc privkey");
if (!derive_simple_key(&localbase.htlc,
&local_per_commit_point,
&local_htlc_pubkey))
errx(1, "Failure deriving local htlc pubkey");
if (!derive_simple_privkey(&remote.htlc_basepoint_secret,
&remotebase.htlc,
&local_per_commit_point,
&remote_htlc_privkey))
errx(1, "Failure deriving remote htlc privkey");
if (!derive_simple_key(&remotebase.htlc,
&local_per_commit_point,
&remote_htlc_pubkey))
errx(1, "Failure deriving remote htlc pubkey");
for (size_t i = 0; i < tal_count(htlcmap); i++) {
struct bitcoin_signature local_htlc_sig, remote_htlc_sig;
struct amount_sat amt;
if (!htlcmap[i])
continue;
printf("# Output %zu: %s HTLC %"PRIu64"\n",
i, side_to_str(htlc_owner(htlcmap[i])), htlcmap[i]->id);
printf("# unsigned htlc tx for output %zu: %s\n",
i, tal_hex(NULL, linearize_tx(NULL, local_txs[1+i])));
amt = amount_msat_to_sat_round_down(htlcmap[i]->amount);
local_txs[1+i]->input_amounts[0]
= tal_dup(local_txs[1+i], struct amount_sat, &amt);
printf("# wscript: %s\n", tal_hex(NULL, wscripts[1+i]));
sign_tx_input(local_txs[1+i], 0, NULL, wscripts[1+i],
&local_htlc_privkey, &local_htlc_pubkey,
SIGHASH_ALL, &local_htlc_sig);
sign_tx_input(local_txs[1+i], 0, NULL, wscripts[1+i],
&remote_htlc_privkey, &remote_htlc_pubkey,
SIGHASH_ALL, &remote_htlc_sig);
printf("localsig_on_local output %zu: %s\n",
i, sig_as_hex(&local_htlc_sig));
printf("remotesig_on_local output %zu: %s\n",
i, sig_as_hex(&remote_htlc_sig));
if (htlc_owner(htlcmap[i]) == LOCAL)
witness = bitcoin_witness_htlc_timeout_tx(NULL,
&local_htlc_sig,
&remote_htlc_sig,
wscripts[1+i]);
else
witness = bitcoin_witness_htlc_success_tx(NULL,
&local_htlc_sig,
&remote_htlc_sig,
preimage_of(&htlcmap[i]->rhash, htlcs, preimages),
wscripts[1+i]);
bitcoin_tx_input_set_witness(local_txs[1+i], 0, witness);
printf("htlc tx for output %zu: %s\n",
i, tal_hex(NULL, linearize_tx(NULL, local_txs[1+i])));
}
printf("\n");
/* Create the remote commitment tx */
if (!per_commit_point(&remoteseed, &remote_per_commit_point, commitnum))
errx(1, "Bad deriving remote per-commitment-point");
if (!derive_keyset(&remote_per_commit_point, &remotebase, &localbase,
&remotekeys))
errx(1, "Bad deriving remote keyset");
remote_tx = initial_commit_tx(NULL, &funding_txid, funding_outnum,
funding_amount,
fee_payer,
remotesettings.to_self_delay,
&remotekeys,
feerate_per_kw,
remotesettings.dustlimit,
remote_msat,
local_msat,
remotesettings.reserve,
commitnum
^ commit_number_obscurer(&localbase.payment,
&remotebase.payment),
REMOTE, &err);
if (!remote_tx)
errx(1, "Can't make remote commit tx: %s", err);
remote_tx->input_amounts[0]
= tal_dup(remote_tx, struct amount_sat, &funding_amount);
remote_txs = channel_txs(NULL, &htlcmap, &wscripts, channel,
&remote_per_commit_point, commitnum, REMOTE);
remote_txs[0]->input_amounts[0]
= tal_dup(remote_txs[0], struct amount_sat, &funding_amount);
printf("## remote_commitment\n"
"# input amount %s, funding_wscript %s, key %s\n",
@ -339,16 +476,16 @@ int main(int argc, char *argv[])
tal_hex(NULL, funding_wscript),
type_to_string(NULL, struct pubkey, &funding_remotekey));
printf("# unsigned remote commitment tx: %s\n",
tal_hex(NULL, linearize_tx(NULL, remote_tx)));
tal_hex(NULL, linearize_tx(NULL, remote_txs[0])));
sign_tx_input(remote_tx, 0, NULL, funding_wscript,
sign_tx_input(remote_txs[0], 0, NULL, funding_wscript,
&local.funding_privkey,
&funding_localkey,
SIGHASH_ALL,
&local_sig);
printf("localsig_on_remote: %s\n", sig_as_hex(&local_sig));
sign_tx_input(remote_tx, 0, NULL, funding_wscript,
sign_tx_input(remote_txs[0], 0, NULL, funding_wscript,
&remote.funding_privkey,
&funding_remotekey,
SIGHASH_ALL,
@ -358,10 +495,75 @@ int main(int argc, char *argv[])
witness =
bitcoin_witness_2of2(NULL, &local_sig, &remote_sig,
&funding_localkey, &funding_remotekey);
bitcoin_tx_input_set_witness(remote_tx, 0, witness);
bitcoin_tx_input_set_witness(remote_txs[0], 0, witness);
printf("# signed remote commitment: %s\n",
tal_hex(NULL, linearize_tx(NULL, remote_tx)));
tal_hex(NULL, linearize_tx(NULL, remote_txs[0])));
if (!derive_simple_privkey(&local.htlc_basepoint_secret,
&localbase.htlc,
&remote_per_commit_point,
&local_htlc_privkey))
errx(1, "Failure deriving local htlc privkey");
if (!derive_simple_key(&localbase.htlc,
&remote_per_commit_point,
&local_htlc_pubkey))
errx(1, "Failure deriving local htlc pubkey");
if (!derive_simple_privkey(&remote.htlc_basepoint_secret,
&remotebase.htlc,
&remote_per_commit_point,
&remote_htlc_privkey))
errx(1, "Failure deriving remote htlc privkey");
if (!derive_simple_key(&remotebase.htlc,
&remote_per_commit_point,
&remote_htlc_pubkey))
errx(1, "Failure deriving remote htlc pubkey");
for (size_t i = 0; i < tal_count(htlcmap); i++) {
struct bitcoin_signature local_htlc_sig, remote_htlc_sig;
struct amount_sat amt;
if (!htlcmap[i])
continue;
printf("# Output %zu: %s HTLC %"PRIu64"\n",
i, side_to_str(htlc_owner(htlcmap[i])), htlcmap[i]->id);
printf("# unsigned htlc tx for output %zu: %s\n",
i, tal_hex(NULL, linearize_tx(NULL, remote_txs[1+i])));
amt = amount_msat_to_sat_round_down(htlcmap[i]->amount);
remote_txs[1+i]->input_amounts[0]
= tal_dup(remote_txs[1+i], struct amount_sat, &amt);
printf("# wscript: %s\n", tal_hex(NULL, wscripts[1+i]));
sign_tx_input(remote_txs[1+i], 0, NULL, wscripts[1+i],
&local_htlc_privkey, &local_htlc_pubkey,
SIGHASH_ALL, &local_htlc_sig);
sign_tx_input(remote_txs[1+i], 0, NULL, wscripts[1+i],
&remote_htlc_privkey, &remote_htlc_pubkey,
SIGHASH_ALL, &remote_htlc_sig);
printf("localsig_on_remote output %zu: %s\n",
i, sig_as_hex(&local_htlc_sig));
printf("remotesig_on_remote output %zu: %s\n",
i, sig_as_hex(&remote_htlc_sig));
if (htlc_owner(htlcmap[i]) == REMOTE)
witness = bitcoin_witness_htlc_timeout_tx(NULL,
&remote_htlc_sig,
&local_htlc_sig,
wscripts[1+i]);
else
witness = bitcoin_witness_htlc_success_tx(NULL,
&remote_htlc_sig,
&local_htlc_sig,
preimage_of(&htlcmap[i]->rhash, htlcs, preimages),
wscripts[1+i]);
bitcoin_tx_input_set_witness(remote_txs[1+i], 0, witness);
printf("htlc tx for output %zu: %s\n",
i, tal_hex(NULL, linearize_tx(NULL, remote_txs[1+i])));
}
printf("\n");
return 0;
}

Loading…
Cancel
Save