mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
devtools: add mkfunding and mkcommit.
These utilities allow us to create valid test txs and information given both sides' complete set of secrets. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
1e6eabf018
commit
8b09a9ad06
@ -6,6 +6,7 @@
|
||||
#include <common/amount.h>
|
||||
#include <common/htlc.h>
|
||||
|
||||
struct bitcoin_txid;
|
||||
struct keyset;
|
||||
|
||||
/* BOLT #3:
|
||||
|
@ -1,6 +1,6 @@
|
||||
DEVTOOLS_SRC := devtools/gen_print_wire.c devtools/gen_print_onion_wire.c devtools/print_wire.c
|
||||
DEVTOOLS_OBJS := $(DEVTOOLS_SRC:.c=.o)
|
||||
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore
|
||||
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding
|
||||
DEVTOOLS_TOOL_SRC := $(DEVTOOLS:=.c)
|
||||
DEVTOOLS_TOOL_OBJS := $(DEVTOOLS_TOOL_SRC:.c=.o)
|
||||
|
||||
@ -61,6 +61,10 @@ 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/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
|
||||
|
||||
# Make sure these depend on everything.
|
||||
ALL_PROGRAMS += $(DEVTOOLS)
|
||||
ALL_OBJS += $(DEVTOOLS_OBJS) $(DEVTOOLS_TOOL_OBJS)
|
||||
|
367
devtools/mkcommit.c
Normal file
367
devtools/mkcommit.c
Normal file
@ -0,0 +1,367 @@
|
||||
/* For example, in the spec tests we use the following:
|
||||
*
|
||||
* lightning/devtools/mkcommit 0 41085b995c1f591cfc3ae79ccde012bf0b37c7bde23d80a61c9732bdd6210b2f 0 999878sat 253 999878sat local \
|
||||
6 546 9900sat \
|
||||
6 546 9900sat \
|
||||
0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000021 0000000000000000000000000000000000000000000000000000000000000022 0000000000000000000000000000000000000000000000000000000000000023 0000000000000000000000000000000000000000000000000000000000000024 \
|
||||
0000000000000000000000000000000000000000000000000000000000000010 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 0000000000000000000000000000000000000000000000000000000000000011 0000000000000000000000000000000000000000000000000000000000000012 0000000000000000000000000000000000000000000000000000000000000013 0000000000000000000000000000000000000000000000000000000000000014
|
||||
*/
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/derive_basepoints.h>
|
||||
#include <common/initial_commit_tx.h>
|
||||
#include <common/keyset.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void status_fmt(enum log_level level, const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
/* Code to make a commitment tx, useful for generating test cases. */
|
||||
static int parse_secrets(char *argv[],
|
||||
struct secrets *secrets,
|
||||
struct sha256 *seed,
|
||||
const char *desc)
|
||||
{
|
||||
int argnum = 0;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&secrets->funding_privkey,
|
||||
sizeof(secrets->funding_privkey)))
|
||||
errx(1, "Parsing %s.funding_privkey", desc);
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
seed, sizeof(*seed)))
|
||||
errx(1, "Parsing %s seed", desc);
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&secrets->revocation_basepoint_secret,
|
||||
sizeof(secrets->revocation_basepoint_secret)))
|
||||
errx(1, "Parsing %s.revocation_basepoint_secret", desc);
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&secrets->payment_basepoint_secret,
|
||||
sizeof(secrets->payment_basepoint_secret)))
|
||||
errx(1, "Parsing %s.payment_basepoint_secret", desc);
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&secrets->delayed_payment_basepoint_secret,
|
||||
sizeof(secrets->delayed_payment_basepoint_secret)))
|
||||
errx(1, "Parsing %s.delayed_payment_basepoint_secret", desc);
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&secrets->htlc_basepoint_secret,
|
||||
sizeof(secrets->htlc_basepoint_secret)))
|
||||
errx(1, "Parsing %s.htlc_basepoint_secret", desc);
|
||||
argnum++;
|
||||
return argnum;
|
||||
}
|
||||
|
||||
static void print_basepoints(const char *desc,
|
||||
const struct secrets *secrets,
|
||||
const struct sha256 *shaseed,
|
||||
const struct basepoints *basepoints,
|
||||
const struct pubkey *fundingkey,
|
||||
u64 commitnum)
|
||||
{
|
||||
struct secret per_commitment_secret;
|
||||
struct pubkey per_commitment_point;
|
||||
|
||||
printf("## %s\n", desc);
|
||||
printf("# funding_privkey=%s\n",
|
||||
type_to_string(NULL, struct secret, &secrets->funding_privkey.secret));
|
||||
printf("funding_pubkey=%s\n",
|
||||
type_to_string(NULL, struct pubkey, fundingkey));
|
||||
printf("# revocation_basepoint_secret=%s\n",
|
||||
type_to_string(NULL, struct secret,
|
||||
&secrets->revocation_basepoint_secret));
|
||||
printf("revocation_basepoint=%s\n",
|
||||
type_to_string(NULL, struct pubkey, &basepoints->revocation));
|
||||
printf("# payment_basepoint_secret=%s\n",
|
||||
type_to_string(NULL, struct secret,
|
||||
&secrets->payment_basepoint_secret));
|
||||
printf("payment_basepoint=%s\n",
|
||||
type_to_string(NULL, struct pubkey, &basepoints->payment));
|
||||
printf("# delayed_payment_basepoint_secret=%s\n",
|
||||
type_to_string(NULL, struct secret,
|
||||
&secrets->delayed_payment_basepoint_secret));
|
||||
printf("delayed_payment_basepoint=%s\n",
|
||||
type_to_string(NULL, struct pubkey, &basepoints->delayed_payment));
|
||||
printf("# htlc_basepoint_secret=%s\n",
|
||||
type_to_string(NULL, struct secret,
|
||||
&secrets->htlc_basepoint_secret));
|
||||
printf("htlc_basepoint=%s\n",
|
||||
type_to_string(NULL, struct pubkey, &basepoints->htlc));
|
||||
if (!per_commit_secret(shaseed, &per_commitment_secret, commitnum))
|
||||
errx(1, "Bad deriving %s per_commitment_secret", desc);
|
||||
if (!per_commit_point(shaseed, &per_commitment_point, commitnum))
|
||||
errx(1, "Bad deriving %s per_commitment_point", desc);
|
||||
printf("# shachain seed=%s\n",
|
||||
type_to_string(NULL, struct sha256, shaseed));
|
||||
printf("# per_commitment_secret %"PRIu64"=%s\n",
|
||||
commitnum,
|
||||
type_to_string(NULL, struct secret, &per_commitment_secret));
|
||||
printf("per_commitment_point %"PRIu64"=%s\n\n",
|
||||
commitnum,
|
||||
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)
|
||||
{
|
||||
int argnum = 0;
|
||||
settings->to_self_delay = atoi(argv[argnum]);
|
||||
argnum++;
|
||||
if (!parse_amount_sat(&settings->dustlimit,
|
||||
argv[argnum], strlen(argv[argnum])))
|
||||
errx(1, "Bad %s dustlimit", desc);
|
||||
argnum++;
|
||||
if (!parse_amount_sat(&settings->reserve,
|
||||
argv[argnum], strlen(argv[argnum])))
|
||||
errx(1, "Bad %s reserve", desc);
|
||||
argnum++;
|
||||
return argnum;
|
||||
}
|
||||
|
||||
static char *sig_as_hex(const struct bitcoin_signature *sig)
|
||||
{
|
||||
u8 compact_sig[64];
|
||||
|
||||
secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx,
|
||||
compact_sig,
|
||||
&sig->s);
|
||||
return tal_hexstr(NULL, compact_sig, sizeof(compact_sig));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct secrets local, remote;
|
||||
struct sha256 localseed, remoteseed;
|
||||
struct basepoints localbase, remotebase;
|
||||
struct pubkey funding_localkey, funding_remotekey;
|
||||
u64 commitnum;
|
||||
struct amount_sat funding_amount;
|
||||
struct bitcoin_txid funding_txid;
|
||||
unsigned int funding_outnum;
|
||||
unsigned int feerate_per_kw;
|
||||
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 amount_msat local_msat, remote_msat;
|
||||
int argnum;
|
||||
struct bitcoin_tx *local_tx, *remote_tx;
|
||||
enum side fee_payer;
|
||||
char *err;
|
||||
u8 **witness;
|
||||
|
||||
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"
|
||||
" <to-self-delay>\n"
|
||||
" <dustlimit>\n"
|
||||
" <reserve-sat>\n"
|
||||
"Where <secrets> are:\n"
|
||||
" <funding-privkey>\n"
|
||||
" <shachain-seed>\n"
|
||||
" <revocation-base-secret>\n"
|
||||
" <payment-base-secret>\n"
|
||||
" <delayed-payment-base-secret>\n"
|
||||
" <htlc-base-secret>");
|
||||
|
||||
argnum = 1;
|
||||
commitnum = atol(argv[argnum++]);
|
||||
if (!bitcoin_txid_from_hex(argv[argnum],
|
||||
strlen(argv[argnum]), &funding_txid))
|
||||
errx(1, "Bad funding-txid");
|
||||
argnum++;
|
||||
funding_outnum = atoi(argv[argnum++]);
|
||||
if (!parse_amount_sat(&funding_amount, argv[argnum], strlen(argv[argnum])))
|
||||
errx(1, "Bad funding-amount");
|
||||
argnum++;
|
||||
feerate_per_kw = atoi(argv[argnum++]);
|
||||
if (!parse_amount_msat(&local_msat,
|
||||
argv[argnum], strlen(argv[argnum])))
|
||||
errx(1, "Bad local-msat");
|
||||
argnum++;
|
||||
if (streq(argv[argnum], "local"))
|
||||
fee_payer = LOCAL;
|
||||
else if (streq(argv[argnum], "remote"))
|
||||
fee_payer = REMOTE;
|
||||
else
|
||||
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_secrets(argv + argnum, &local, &localseed, "local");
|
||||
argnum += parse_secrets(argv + argnum, &remote, &remoteseed, "remote");
|
||||
|
||||
if (!amount_sat_sub_msat(&remote_msat, funding_amount, local_msat))
|
||||
errx(1, "Can't afford local_msat");
|
||||
|
||||
if (!pubkey_from_privkey(&local.funding_privkey, &funding_localkey)
|
||||
|| !pubkey_from_secret(&local.revocation_basepoint_secret,
|
||||
&localbase.revocation)
|
||||
|| !pubkey_from_secret(&local.payment_basepoint_secret,
|
||||
&localbase.payment)
|
||||
|| !pubkey_from_secret(&local.delayed_payment_basepoint_secret,
|
||||
&localbase.delayed_payment)
|
||||
|| !pubkey_from_secret(&local.htlc_basepoint_secret,
|
||||
&localbase.htlc))
|
||||
errx(1, "Bad deriving local basepoints");
|
||||
|
||||
if (!pubkey_from_privkey(&remote.funding_privkey, &funding_remotekey)
|
||||
|| !pubkey_from_secret(&remote.revocation_basepoint_secret,
|
||||
&remotebase.revocation)
|
||||
|| !pubkey_from_secret(&remote.payment_basepoint_secret,
|
||||
&remotebase.payment)
|
||||
|| !pubkey_from_secret(&remote.delayed_payment_basepoint_secret,
|
||||
&remotebase.delayed_payment)
|
||||
|| !pubkey_from_secret(&remote.htlc_basepoint_secret,
|
||||
&remotebase.htlc))
|
||||
errx(1, "Bad deriving remote basepoints");
|
||||
|
||||
print_basepoints("local",
|
||||
&local, &localseed,
|
||||
&localbase, &funding_localkey, commitnum);
|
||||
print_basepoints("remote",
|
||||
&remote, &remoteseed,
|
||||
&remotebase, &funding_remotekey, commitnum);
|
||||
|
||||
u8 *funding_wscript = bitcoin_redeem_2of2(NULL,
|
||||
&funding_localkey,
|
||||
&funding_remotekey);
|
||||
|
||||
/* Create the local commitment_tx */
|
||||
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);
|
||||
|
||||
printf("## local_commitment\n"
|
||||
"# input amount %s, funding_wscript %s, key %s\n",
|
||||
type_to_string(NULL, struct amount_sat, &funding_amount),
|
||||
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)));
|
||||
|
||||
sign_tx_input(local_tx, 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,
|
||||
&remote.funding_privkey,
|
||||
&funding_remotekey,
|
||||
SIGHASH_ALL,
|
||||
&remote_sig);
|
||||
printf("remotesig_on_local: %s\n", sig_as_hex(&remote_sig));
|
||||
|
||||
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)));
|
||||
|
||||
/* 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);
|
||||
|
||||
printf("## remote_commitment\n"
|
||||
"# input amount %s, funding_wscript %s, key %s\n",
|
||||
type_to_string(NULL, struct amount_sat, &funding_amount),
|
||||
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)));
|
||||
|
||||
sign_tx_input(remote_tx, 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,
|
||||
&remote.funding_privkey,
|
||||
&funding_remotekey,
|
||||
SIGHASH_ALL,
|
||||
&remote_sig);
|
||||
printf("remotesig_on_remote: %s\n", sig_as_hex(&remote_sig));
|
||||
|
||||
witness =
|
||||
bitcoin_witness_2of2(NULL, &local_sig, &remote_sig,
|
||||
&funding_localkey, &funding_remotekey);
|
||||
bitcoin_tx_input_set_witness(remote_tx, 0, witness);
|
||||
|
||||
printf("# signed remote commitment: %s\n",
|
||||
tal_hex(NULL, linearize_tx(NULL, remote_tx)));
|
||||
|
||||
return 0;
|
||||
}
|
133
devtools/mkfunding.c
Normal file
133
devtools/mkfunding.c
Normal file
@ -0,0 +1,133 @@
|
||||
/* For example, in the spec tests we use the following keys:
|
||||
*
|
||||
* lightning/devtools/mkfunding 16835ac8c154b616baac524163f41fb0c4f82c7b972ad35d4d6f18d854f6856b 1 0.01btc 253 76edf0c303b9e692da9cb491abedef46ca5b81d32f102eb4648461b239cb0f99 0000000000000000000000000000000000000000000000000000000000000010 0000000000000000000000000000000000000000000000000000000000000020
|
||||
*/
|
||||
#include <bitcoin/address.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/derive_basepoints.h>
|
||||
#include <common/funding_tx.h>
|
||||
#include <common/initial_commit_tx.h>
|
||||
#include <common/keyset.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utxo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void status_fmt(enum log_level level, const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
static char *sig_as_hex(const struct bitcoin_signature *sig)
|
||||
{
|
||||
u8 compact_sig[64];
|
||||
|
||||
secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx,
|
||||
compact_sig,
|
||||
&sig->s);
|
||||
return tal_hexstr(NULL, compact_sig, sizeof(compact_sig));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct privkey input_privkey;
|
||||
struct privkey local_funding_privkey, remote_funding_privkey;
|
||||
struct pubkey funding_localkey, funding_remotekey, inputkey;
|
||||
struct amount_sat fee, funding_amount;
|
||||
unsigned int feerate_per_kw;
|
||||
int argnum;
|
||||
struct bitcoin_tx *tx;
|
||||
u16 outnum;
|
||||
size_t weight;
|
||||
struct utxo input;
|
||||
const struct utxo **utxomap;
|
||||
struct bitcoin_signature sig;
|
||||
struct bitcoin_txid txid;
|
||||
|
||||
setup_locale();
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY |
|
||||
SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
if (argc != 1 + 7)
|
||||
errx(1, "Usage: mkfunding <input-txid> <input-txout> <input-amount> <feerate-per-kw> <input-privkey> <local-funding-privkey> <remote-funding-privkey>");
|
||||
|
||||
input.is_p2sh = false;
|
||||
input.close_info = NULL;
|
||||
|
||||
argnum = 1;
|
||||
if (!bitcoin_txid_from_hex(argv[argnum],
|
||||
strlen(argv[argnum]), &input.txid))
|
||||
errx(1, "Bad input-txid");
|
||||
argnum++;
|
||||
input.outnum = atoi(argv[argnum++]);
|
||||
if (!parse_amount_sat(&input.amount, argv[argnum], strlen(argv[argnum])))
|
||||
errx(1, "Bad input-amount");
|
||||
argnum++;
|
||||
feerate_per_kw = atoi(argv[argnum++]);
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&input_privkey, sizeof(input_privkey)))
|
||||
errx(1, "Parsing input-privkey");
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&local_funding_privkey, sizeof(local_funding_privkey)))
|
||||
errx(1, "Parsing local-funding-privkey");
|
||||
argnum++;
|
||||
if (!hex_decode(argv[argnum], strlen(argv[argnum]),
|
||||
&remote_funding_privkey, sizeof(remote_funding_privkey)))
|
||||
errx(1, "Parsing remote-funding-privkey");
|
||||
argnum++;
|
||||
|
||||
if (!pubkey_from_privkey(&input_privkey, &inputkey)
|
||||
|| !pubkey_from_privkey(&local_funding_privkey, &funding_localkey)
|
||||
|| !pubkey_from_privkey(&remote_funding_privkey, &funding_remotekey))
|
||||
errx(1, "Bad privkeys");
|
||||
|
||||
/* nVersion, input count, output count, nLocktime */
|
||||
weight = 4 * (4 + 1 + 1 + 4);
|
||||
/* Single output: Satoshis, script length, p2wsh. */
|
||||
weight += 4 * (8 + 1 + BITCOIN_SCRIPTPUBKEY_P2WSH_LEN);
|
||||
/* Single input: txid, index, scriptlen, nSequence */
|
||||
weight += 4 * (32 + 4 + 1 + 4);
|
||||
/* Single witness: witness element count, len[0], sig, len[2], key */
|
||||
weight += 1 + (1 + 73 + 1 + 33);
|
||||
|
||||
fee = amount_tx_fee(feerate_per_kw, weight);
|
||||
if (!amount_sat_sub(&funding_amount, input.amount, fee))
|
||||
errx(1, "Input %s can't afford fee %s",
|
||||
type_to_string(NULL, struct amount_sat, &input.amount),
|
||||
type_to_string(NULL, struct amount_sat, &fee));
|
||||
|
||||
/* funding_tx wants a utxo array. */
|
||||
utxomap = tal_arr(tmpctx, const struct utxo *, 1);
|
||||
utxomap[0] = &input;
|
||||
|
||||
/* No change output, so we don't need a bip32 base. */
|
||||
tx = funding_tx(NULL, &outnum, utxomap, funding_amount,
|
||||
&funding_localkey, &funding_remotekey,
|
||||
AMOUNT_SAT(0), NULL, NULL);
|
||||
|
||||
/* P2WSH of inputkey */
|
||||
bitcoin_tx_input_set_script(tx, 0, NULL);
|
||||
sign_tx_input(tx, 0, NULL, p2wpkh_scriptcode(NULL, &inputkey),
|
||||
&input_privkey, &inputkey,
|
||||
SIGHASH_ALL, &sig);
|
||||
|
||||
printf("# funding sig: %s\n", sig_as_hex(&sig));
|
||||
printf("# funding amount: %s\n",
|
||||
type_to_string(NULL, struct amount_sat, &funding_amount));
|
||||
|
||||
bitcoin_txid(tx, &txid);
|
||||
printf("# funding txid: %s\n",
|
||||
type_to_string(NULL, struct bitcoin_txid, &txid));
|
||||
|
||||
bitcoin_tx_input_set_witness(
|
||||
tx, 0, bitcoin_witness_p2wpkh(NULL, &sig, &inputkey));
|
||||
|
||||
printf("tx: %s\n", tal_hex(NULL, linearize_tx(NULL, tx)));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user