Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bitcoin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ BITCOIN_SRC := \
bitcoin/base58.c \
bitcoin/block.c \
bitcoin/chainparams.c \
bitcoin/feerate.c \
bitcoin/locktime.c \
bitcoin/preimage.c \
bitcoin/privkey.c \
Expand Down
40 changes: 40 additions & 0 deletions bitcoin/feerate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <bitcoin/feerate.h>
#include <limits.h>
#include <stdlib.h>

u32 feerate_from_style(u32 feerate, enum feerate_style style)
{
switch (style) {
case FEERATE_PER_KSIPA:
return feerate;
case FEERATE_PER_KBYTE:
/* Everyone uses satoshi per kbyte, but we use satoshi per ksipa
* (don't round down to zero though)! */
return (feerate + 3) / 4;
}
abort();
}

u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style)
{
switch (style) {
case FEERATE_PER_KSIPA:
return feerate_perkw;
case FEERATE_PER_KBYTE:
if ((u64)feerate_perkw * 4 > UINT_MAX)
return UINT_MAX;
return feerate_perkw * 4;
}
abort();
}

const char *feerate_style_name(enum feerate_style style)
{
switch (style) {
case FEERATE_PER_KBYTE:
return "perkb";
case FEERATE_PER_KSIPA:
return "perkw";
}
abort();
}
11 changes: 11 additions & 0 deletions bitcoin/feerate.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "config.h"
#include <ccan/build_assert/build_assert.h>
#include <ccan/short_types/short_types.h>
#include <common/amount.h>

/* bitcoind considers 250 satoshi per kw to be the minimum acceptable fee:
* less than this won't even relay.
Expand Down Expand Up @@ -33,6 +34,11 @@
*/
#define FEERATE_FLOOR 253

enum feerate_style {
FEERATE_PER_KSIPA,
FEERATE_PER_KBYTE
};

static inline u32 feerate_floor(void)
{
/* Assert that bitcoind will see this as above minRelayTxFee */
Expand All @@ -47,4 +53,9 @@ static inline u32 feerate_floor(void)

return FEERATE_FLOOR;
}

u32 feerate_from_style(u32 feerate, enum feerate_style style);
u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style);
const char *feerate_style_name(enum feerate_style style);

#endif /* LIGHTNING_BITCOIN_FEERATE_H */
9 changes: 6 additions & 3 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_greater_eq */
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
/* Generated stub for amount_tx_fee */
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
Expand Down
9 changes: 6 additions & 3 deletions bitcoin/test/run-tx-encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_greater_eq */
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
/* Generated stub for amount_tx_fee */
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
Expand Down
17 changes: 17 additions & 0 deletions bitcoin/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,3 +803,20 @@ size_t bitcoin_tx_simple_input_weight(bool p2sh)

return weight;
}

struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw)
{
size_t outweight;

/* Must be able to pay for its own additional weight */
outweight = bitcoin_tx_output_weight(BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN);
if (!amount_sat_sub(&excess,
excess, amount_tx_fee(feerate_perkw, outweight)))
return AMOUNT_SAT(0);

/* Must be non-dust */
if (!amount_sat_greater_eq(excess, chainparams->dust_limit))
return AMOUNT_SAT(0);

return excess;
}
11 changes: 11 additions & 0 deletions bitcoin/tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,15 @@ size_t bitcoin_tx_input_sig_weight(void);
/* We only do segwit inputs, and we assume witness is sig + key */
size_t bitcoin_tx_simple_input_weight(bool p2sh);

/**
* change_amount - Is it worth making a P2WPKH change output at this feerate?
* @excess: input amount we have above the tx fee and other outputs.
* @feerate_perkw: feerate.
*
* If it's not worth (or possible) to make change, returns AMOUNT_SAT(0).
* Otherwise returns the amount of the change output to add (@excess minus
* the additional fee for the change output itself).
*/
struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw);

#endif /* LIGHTNING_BITCOIN_TX_H */
9 changes: 6 additions & 3 deletions cli/test/run-large-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_greater_eq */
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
/* Generated stub for amount_tx_fee */
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
/* Generated stub for fromwire_amount_msat */
struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); }
Expand Down
9 changes: 6 additions & 3 deletions cli/test/run-remove-hint.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,17 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_greater_eq */
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
/* Generated stub for amount_tx_fee */
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
/* Generated stub for fromwire_amount_msat */
struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); }
Expand Down
175 changes: 175 additions & 0 deletions common/json_tok.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/chainparams.h>
#include <bitcoin/feerate.h>
#include <bitcoin/script.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/bech32.h>
#include <common/channel_id.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
Expand Down Expand Up @@ -330,3 +336,172 @@ struct command_result *param_secrets_array(struct command *cmd,
}
return NULL;
}

struct command_result *param_feerate_val(struct command *cmd,
const char *name, const char *buffer,
const jsmntok_t *tok,
u32 **feerate_per_kw)
{
jsmntok_t base = *tok, suffix = *tok;
enum feerate_style style;
unsigned int num;

/* We have to split the number and suffix. */
suffix.start = suffix.end;
while (suffix.start > base.start && !isdigit(buffer[suffix.start-1])) {
suffix.start--;
base.end--;
}

if (!json_to_number(buffer, &base, &num)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"'%s' prefix should be an integer, not '%.*s'",
name, base.end - base.start,
buffer + base.start);
}

if (suffix.end == suffix.start
|| json_tok_streq(buffer, &suffix,
feerate_style_name(FEERATE_PER_KBYTE))) {
style = FEERATE_PER_KBYTE;
} else if (json_tok_streq(buffer, &suffix,
feerate_style_name(FEERATE_PER_KSIPA))) {
style = FEERATE_PER_KSIPA;
} else {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"'%s' suffix should be '%s' or '%s', not '%.*s'",
name,
feerate_style_name(FEERATE_PER_KSIPA),
feerate_style_name(FEERATE_PER_KBYTE),
suffix.end - suffix.start,
buffer + suffix.start);
}

*feerate_per_kw = tal(cmd, u32);
**feerate_per_kw = feerate_from_style(num, style);
if (**feerate_per_kw < FEERATE_FLOOR)
**feerate_per_kw = FEERATE_FLOOR;
return NULL;
}

/**
* segwit_addr_net_decode - Try to decode a Bech32 address and detect
* testnet/mainnet/regtest/signet
*
* This processes the address and returns a string if it is a Bech32
* address specified by BIP173. The string is set whether it is
* testnet ("tb"), mainnet ("bc"), regtest ("bcrt"), or signet ("sb")
* It does not check, witness version and program size restrictions.
*
* Out: witness_version: Pointer to an int that will be updated to contain
* the witness program version (between 0 and 16 inclusive).
* witness_program: Pointer to a buffer of size 40 that will be updated
* to contain the witness program bytes.
* witness_program_len: Pointer to a size_t that will be updated to
* contain the length of bytes in witness_program.
* In: addrz: Pointer to the null-terminated address.
* Returns string containing the human readable segment of bech32 address
*/
static const char *segwit_addr_net_decode(int *witness_version,
uint8_t *witness_program,
size_t *witness_program_len,
const char *addrz,
const struct chainparams *chainparams)
{
if (segwit_addr_decode(witness_version, witness_program,
witness_program_len, chainparams->bip173_name,
addrz))
return chainparams->bip173_name;
else
return NULL;
}

enum address_parse_result
json_to_address_scriptpubkey(const tal_t *ctx,
const struct chainparams *chainparams,
const char *buffer,
const jsmntok_t *tok, const u8 **scriptpubkey)
{
struct bitcoin_address destination;
int witness_version;
/* segwit_addr_net_decode requires a buffer of size 40, and will
* not write to the buffer if the address is too long, so a buffer
* of fixed size 40 will not overflow. */
uint8_t witness_program[40];
size_t witness_program_len;

char *addrz;
const char *bip173;

bool parsed;
bool right_network;
u8 addr_version;

parsed =
ripemd160_from_base58(&addr_version, &destination.addr,
buffer + tok->start, tok->end - tok->start);

if (parsed) {
if (addr_version == chainparams->p2pkh_version) {
*scriptpubkey = scriptpubkey_p2pkh(ctx, &destination);
return ADDRESS_PARSE_SUCCESS;
} else if (addr_version == chainparams->p2sh_version) {
*scriptpubkey =
scriptpubkey_p2sh_hash(ctx, &destination.addr);
return ADDRESS_PARSE_SUCCESS;
} else {
return ADDRESS_PARSE_WRONG_NETWORK;
}
/* Insert other parsers that accept pointer+len here. */
}

/* Generate null-terminated address. */
addrz = tal_dup_arr(ctx, char, buffer + tok->start, tok->end - tok->start, 1);
addrz[tok->end - tok->start] = '\0';

bip173 = segwit_addr_net_decode(&witness_version, witness_program,
&witness_program_len, addrz, chainparams);

if (bip173) {
bool witness_ok = false;
if (witness_version == 0 && (witness_program_len == 20 ||
witness_program_len == 32)) {
witness_ok = true;
}
/* Insert other witness versions here. */

if (witness_ok) {
*scriptpubkey = scriptpubkey_witness_raw(ctx, witness_version,
witness_program, witness_program_len);
parsed = true;
right_network = streq(bip173, chainparams->bip173_name);
}
}
/* Insert other parsers that accept null-terminated string here. */

tal_free(addrz);

if (parsed) {
if (right_network)
return ADDRESS_PARSE_SUCCESS;
else
return ADDRESS_PARSE_WRONG_NETWORK;
}

return ADDRESS_PARSE_UNRECOGNIZED;
}

struct command_result *param_txid(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct bitcoin_txid **txid)
{
*txid = tal(cmd, struct bitcoin_txid);
if (json_to_txid(buffer, tok, *txid))
return NULL;
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"'%s' should be txid, not '%.*s'",
name, json_tok_full_len(tok),
json_tok_full(buffer, tok));
}
Loading