mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 06:41:44 +01:00
lightningd/funding_tx.c: helper to create a funding transaction (with change).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
1bb66cde2a
commit
be46fdf254
4 changed files with 223 additions and 0 deletions
|
@ -29,6 +29,7 @@ LIGHTNINGD_OLD_HEADERS := $(LIGHTNINGD_OLD_SRC:.c=.h)
|
|||
LIGHTNINGD_LIB_SRC := \
|
||||
lightningd/channel_config.c \
|
||||
lightningd/cryptomsg.c \
|
||||
lightningd/funding_tx.c \
|
||||
lightningd/key_derive.c
|
||||
|
||||
LIGHTNINGD_LIB_OBJS := $(LIGHTNINGD_LIB_SRC:.c=.o)
|
||||
|
|
67
lightningd/funding_tx.c
Normal file
67
lightningd/funding_tx.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "funding_tx.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <permute_tx.h>
|
||||
|
||||
#ifndef SUPERVERBOSE
|
||||
#define SUPERVERBOSE(...)
|
||||
#endif
|
||||
|
||||
struct bitcoin_tx *funding_tx(const tal_t *ctx,
|
||||
const struct sha256_double *input_txid,
|
||||
unsigned int input_txout,
|
||||
u64 input_satoshis,
|
||||
u64 funding_satoshis,
|
||||
const struct pubkey *local_fundingkey,
|
||||
const struct pubkey *remote_fundingkey,
|
||||
const struct pubkey *changekey,
|
||||
u64 feerate_per_kw,
|
||||
u64 dust_limit_satoshis)
|
||||
{
|
||||
struct bitcoin_tx *tx = bitcoin_tx(ctx, 1, 2);
|
||||
u8 *wscript;
|
||||
u64 fee, weight;
|
||||
|
||||
tx->input[0].txid = *input_txid;
|
||||
tx->input[0].index = input_txout;
|
||||
tx->input[0].amount = tal_dup(tx, u64, &input_satoshis);
|
||||
|
||||
tx->output[0].amount = funding_satoshis;
|
||||
wscript = bitcoin_redeem_2of2(tx, local_fundingkey, remote_fundingkey);
|
||||
SUPERVERBOSE("# funding witness script = %s\n",
|
||||
tal_hex(wscript, wscript));
|
||||
tx->output[0].script = scriptpubkey_p2wsh(tx, wscript);
|
||||
tal_free(wscript);
|
||||
|
||||
assert(input_satoshis >= funding_satoshis);
|
||||
tx->output[1].script = scriptpubkey_p2wpkh(tx, changekey);
|
||||
|
||||
/* Calculate what weight will be once we've signed. */
|
||||
weight = measure_tx_cost(tx) + 4 * (73 + 34);
|
||||
fee = weight * feerate_per_kw / 1000;
|
||||
|
||||
/* Too small an output after fee? Drop it. */
|
||||
if (input_satoshis - funding_satoshis < dust_limit_satoshis + fee)
|
||||
tal_resize(&tx->output, 1);
|
||||
else {
|
||||
tx->output[1].amount = input_satoshis - funding_satoshis - fee;
|
||||
permute_outputs(tx->output, tal_count(tx->output), NULL);
|
||||
}
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
void sign_funding_tx(struct bitcoin_tx *funding,
|
||||
const struct pubkey *inputkey,
|
||||
const struct privkey *input_privkey)
|
||||
{
|
||||
secp256k1_ecdsa_signature sig;
|
||||
u8 *subscript = scriptpubkey_p2pkh(funding, inputkey);
|
||||
|
||||
sign_tx_input(funding, 0, subscript, NULL, input_privkey, inputkey,
|
||||
&sig);
|
||||
tal_free(subscript);
|
||||
|
||||
funding->input[0].script = bitcoin_redeem_p2pkh(funding, inputkey, &sig);
|
||||
}
|
29
lightningd/funding_tx.h
Normal file
29
lightningd/funding_tx.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef LIGHTNING_LIGHTNINGD_FUNDING_TX_H
|
||||
#define LIGHTNING_LIGHTNINGD_FUNDING_TX_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
struct bitcoin_tx;
|
||||
struct privkey;
|
||||
struct pubkey;
|
||||
struct sha256_double;
|
||||
|
||||
/* Create funding tx which spends a single P2PKH input, produces a
|
||||
* P2WPKH change output (if over dust limit). */
|
||||
struct bitcoin_tx *funding_tx(const tal_t *ctx,
|
||||
const struct sha256_double *input_txid,
|
||||
unsigned int input_txout,
|
||||
u64 input_satoshis,
|
||||
u64 funding_satoshis,
|
||||
const struct pubkey *local_fundingkey,
|
||||
const struct pubkey *remote_fundingkey,
|
||||
const struct pubkey *changekey,
|
||||
u64 feerate_per_kw,
|
||||
u64 dust_limit_satoshis);
|
||||
|
||||
void sign_funding_tx(struct bitcoin_tx *funding,
|
||||
const struct pubkey *inputkey,
|
||||
const struct privkey *input_privkey);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_FUNDING_TX_H */
|
126
lightningd/test/run-funding_tx.c
Normal file
126
lightningd/test/run-funding_tx.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include <bitcoin/base58.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <type_to_string.h>
|
||||
#include <utils.h>
|
||||
#define SUPERVERBOSE printf
|
||||
#include "../funding_tx.c"
|
||||
|
||||
#if 0
|
||||
static struct sha256 sha256_from_hex(const char *hex)
|
||||
{
|
||||
struct sha256 sha256;
|
||||
if (strstarts(hex, "0x"))
|
||||
hex += 2;
|
||||
if (!hex_decode(hex, strlen(hex), &sha256, sizeof(sha256)))
|
||||
abort();
|
||||
return sha256;
|
||||
}
|
||||
|
||||
static struct privkey privkey_from_hex(const char *hex)
|
||||
{
|
||||
struct privkey pk;
|
||||
size_t len;
|
||||
if (strstarts(hex, "0x"))
|
||||
hex += 2;
|
||||
len = strlen(hex);
|
||||
if (len == 66 && strends(hex, "01"))
|
||||
len -= 2;
|
||||
if (!hex_decode(hex, len, &pk, sizeof(pk)))
|
||||
abort();
|
||||
return pk;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tal_t *tmpctx = tal_tmpctx(NULL);
|
||||
struct bitcoin_tx *input, *funding;
|
||||
struct sha256_double txid;
|
||||
u64 feerate_per_kw;
|
||||
struct pubkey local_funding_pubkey, remote_funding_pubkey;
|
||||
struct privkey input_privkey;
|
||||
struct pubkey inputkey;
|
||||
bool testnet;
|
||||
unsigned int input_txout;
|
||||
u64 input_satoshis;
|
||||
u64 funding_satoshis;
|
||||
int funding_outnum;
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* Block 1 coinbase transaction: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000
|
||||
*/
|
||||
input = bitcoin_tx_from_hex(tmpctx,
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000",
|
||||
strlen("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000"));
|
||||
assert(input);
|
||||
|
||||
/* BOLT #3:
|
||||
* Block 1 coinbase privkey: cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz
|
||||
*/
|
||||
if (!key_from_base58("cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz", strlen("cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz"),
|
||||
&testnet, &input_privkey, &inputkey))
|
||||
abort();
|
||||
assert(testnet);
|
||||
printf("* Block 1 coinbase privkey: %s01\n",
|
||||
type_to_string(tmpctx, struct privkey, &input_privkey));
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* The funding transaction is paid to the following keys:
|
||||
*
|
||||
* local_funding_pubkey: 023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb
|
||||
* remote_funding_pubkey: 030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1
|
||||
*/
|
||||
if (!pubkey_from_hexstr("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb",
|
||||
strlen("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb"),
|
||||
&local_funding_pubkey))
|
||||
abort();
|
||||
if (!pubkey_from_hexstr("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1",
|
||||
strlen("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1"),
|
||||
&remote_funding_pubkey))
|
||||
abort();
|
||||
|
||||
bitcoin_txid(input, &txid);
|
||||
input_txout = 0;
|
||||
input_satoshis = 5000000000;
|
||||
funding_satoshis = 10000000;
|
||||
feerate_per_kw = 15000;
|
||||
|
||||
printf("input[0] txid: %s\n", tal_hexstr(tmpctx, &txid, sizeof(txid)));
|
||||
printf("input[0] input: %u\n", input_txout);
|
||||
printf("input[0] satoshis: %"PRIu64"\n", input_satoshis);
|
||||
printf("funding satoshis: %"PRIu64"\n", funding_satoshis);
|
||||
|
||||
funding = funding_tx(tmpctx, &txid, input_txout, input_satoshis,
|
||||
funding_satoshis,
|
||||
&local_funding_pubkey,
|
||||
&remote_funding_pubkey,
|
||||
&inputkey,
|
||||
feerate_per_kw,
|
||||
0);
|
||||
funding_outnum = (funding->output[0].amount == funding_satoshis ? 0 : 1);
|
||||
printf("# feerate_per_kw: %"PRIu64"\n", feerate_per_kw);
|
||||
printf("change satoshis: %"PRIu64"\n",
|
||||
funding->output[!funding_outnum].amount);
|
||||
|
||||
printf("funding output: %u\n", funding_outnum);
|
||||
|
||||
sign_funding_tx(funding, &inputkey, &input_privkey);
|
||||
printf("funding tx: %s\n",
|
||||
tal_hex(tmpctx, linearize_tx(tmpctx, funding)));
|
||||
|
||||
/* No memory leaks please */
|
||||
secp256k1_context_destroy(secp256k1_ctx);
|
||||
tal_free(tmpctx);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue