elements: Add amount_asset to support more than just plain satoshis

Currently the only source for amount_asset is the value getter on a tx output,
and we don't hand it too far around (mainly ignoring it if it isn't the
chain's main currency). Eventually we could bubble them up to the wallet, use
them to select outputs or actually support assets in the channels.

Since we don't hand them around too widely I thought it was ok for them to be
pass-by-value rather than having to allocate them and pass them around by
reference. They're just 41 bytes currently so the overhead should be ok.

Signed-off-by: Christian Decker <@cdecker>
This commit is contained in:
Christian Decker 2019-09-26 21:07:20 +02:00 committed by Rusty Russell
parent c38afc5512
commit 7283efa5b5
31 changed files with 248 additions and 49 deletions

View File

@ -6,6 +6,12 @@
#include <assert.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -7,6 +7,12 @@
#include <common/utils.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -75,6 +75,7 @@ static bool elements_tx_output_is_fee(const struct bitcoin_tx *tx, int outnum)
static struct amount_sat bitcoin_tx_compute_fee(const struct bitcoin_tx *tx)
{
struct amount_sat fee = AMOUNT_SAT(0), value;
struct amount_asset asset;
bool ok;
for (size_t i = 0; i < tal_count(tx->input_amounts); i++) {
@ -84,10 +85,12 @@ static struct amount_sat bitcoin_tx_compute_fee(const struct bitcoin_tx *tx)
}
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
if (elements_tx_output_is_fee(tx, i))
asset = bitcoin_tx_output_get_amount(tx, i);
if (elements_tx_output_is_fee(tx, i) ||
!amount_asset_is_main(&asset))
continue;
value = bitcoin_tx_output_get_amount(tx, i);
value = amount_asset_to_sat(&asset);
ok = amount_sat_sub(&fee, fee, value);
assert(ok);
}
@ -201,34 +204,31 @@ const u8 *bitcoin_tx_output_get_script(const tal_t *ctx,
return res;
}
struct amount_sat bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
int outnum)
struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
int outnum)
{
struct amount_sat amount;
struct amount_asset amount;
struct wally_tx_output *output;
u64 satoshis;
const u8 *fee_asset_tag;
be64 raw;
assert(tx->chainparams);
assert(outnum < tx->wtx->num_outputs);
output = &tx->wtx->outputs[outnum];
fee_asset_tag = tx->chainparams->fee_asset_tag;
if (fee_asset_tag) {
if (memeq(fee_asset_tag, 33, output->asset, output->asset_len)) {
be64 raw;
memcpy(&raw, output->value + 1, sizeof(raw));
satoshis = be64_to_cpu(raw);
} else {
/* If this is an asset based tx, and we don't know the
* asset type, i.e., it's not bitcoin, return a 0
* amount */
satoshis = 0;
}
if (chainparams->is_elements) {
/* We currently only support v1 asset tags */
assert(output->asset_len == sizeof(amount.asset) &&
output->asset[0] == 0x01);
memcpy(&amount.asset, output->asset, sizeof(amount.asset));
memcpy(&raw, output->value + 1, sizeof(raw));
amount.value = be64_to_cpu(raw);
} else {
satoshis = tx->wtx->outputs[outnum].satoshi;
/* Do not assign amount.asset, we should never touch it in
* non-elements scenarios. */
amount.value = tx->wtx->outputs[outnum].satoshi;
}
amount.satoshis = satoshis; /* Raw: helper */
return amount;
}

View File

@ -110,8 +110,8 @@ const u8 *bitcoin_tx_output_get_script(const tal_t *ctx, const struct bitcoin_tx
/**
* Helper to just get an amount_sat for the output amount.
*/
struct amount_sat bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
int outnum);
struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
int outnum);
/**
* Set the input witness.

View File

@ -27,6 +27,12 @@ int test_printf(const char *format, ...);
#undef main
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -30,6 +30,12 @@ int test_fputc(int c, FILE *stream);
#undef main
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -1,9 +1,11 @@
#include <assert.h>
#include <bitcoin/chainparams.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/overflows.h>
#include <common/type_to_string.h>
#include <common/utils.h>
#include <inttypes.h>
bool amount_sat_to_msat(struct amount_msat *msat,
@ -427,3 +429,23 @@ struct amount_sat amount_tx_fee(u32 fee_per_kw, size_t weight)
return fee;
}
bool amount_asset_is_main(struct amount_asset *amount)
{
/* If we're not on elements, there is only one asset. */
if (!chainparams->is_elements)
return true;
/* If we are on elements we better check against the chainparams. */
return memeq(amount->asset, sizeof(amount->asset),
chainparams->fee_asset_tag, sizeof(amount->asset));
}
/* Convert from a generic asset to the fee-paying asset if possible. */
struct amount_sat amount_asset_to_sat(struct amount_asset *amount)
{
struct amount_sat sats;
assert(amount_asset_is_main(amount));
sats.satoshis = amount->value; /* Raw: low-level conversion */
return sats;
}

View File

@ -22,6 +22,11 @@ struct amount_msat {
u64 millisatoshis;
};
struct amount_asset {
u64 value;
u8 asset[33]; /* 1 version byte + 32 byte asset_tag */
};
/* For constants only: others must be built from primitives! */
#if HAVE_BUILTIN_CONSTANT_P
#define AMOUNT_MUST_BE_CONST(c) BUILD_ASSERT_OR_ZERO(IS_COMPILE_CONSTANT(c))
@ -98,6 +103,13 @@ bool amount_msat_less_sat(struct amount_msat msat, struct amount_sat sat);
/* Is msat <= sat? */
bool amount_msat_less_eq_sat(struct amount_msat msat, struct amount_sat sat);
/* Check whether this asset is actually the main / fee-paying asset of the
* current chain. */
bool amount_asset_is_main(struct amount_asset *asset);
/* Convert from a generic asset to the fee-paying asset if possible. */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset);
/* Returns true if msat fits in a u32 value. */
WARN_UNUSED_RESULT bool amount_msat_to_u32(struct amount_msat msat,
u32 *millisatoshis);

View File

@ -12,6 +12,12 @@ static const char *reason;
#include <common/bigsize.c>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -8,6 +8,12 @@
#include <wire/wire_io.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -8,6 +8,12 @@
#include <wally_core.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -7,6 +7,12 @@
#include <wally_core.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -110,6 +110,7 @@ int main(void)
struct bitcoin_signature sig;
struct bitcoin_address addr;
struct amount_sat tmpamt;
struct amount_asset asset;
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_SIGN);
@ -184,7 +185,9 @@ int main(void)
printf("# fee: %s\n",
type_to_string(tmpctx, struct amount_sat, &fee));
tmpamt = bitcoin_tx_output_get_amount(funding, !funding_outnum);
asset = bitcoin_tx_output_get_amount(funding, !funding_outnum);
assert(amount_asset_is_main(&asset));
tmpamt = amount_asset_to_sat(&asset);
printf("change: %s\n",
type_to_string(tmpctx, struct amount_sat,
&tmpamt));

View File

@ -5,6 +5,12 @@
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -6,6 +6,12 @@
#include <ccan/mem/mem.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -6,6 +6,12 @@
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -4,6 +4,12 @@
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -9,6 +9,12 @@
#include "../key_derive.c"
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -8,6 +8,12 @@
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -12,6 +12,12 @@
#include <unistd.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -10,6 +10,12 @@
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -10,6 +10,12 @@
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,

View File

@ -849,11 +849,12 @@ static void process_getfilteredblock_step2(struct bitcoind *bitcoind,
tx = block->tx[i];
for (size_t j = 0; j < tx->wtx->num_outputs; j++) {
const u8 *script = bitcoin_tx_output_get_script(NULL, tx, j);
if (is_p2wsh(script, NULL)) {
struct amount_asset amount = bitcoin_tx_output_get_amount(tx, j);
if (amount_asset_is_main(&amount) && is_p2wsh(script, NULL)) {
/* This is an interesting output, remember it. */
o = tal(call->outpoints, struct filteredblock_outpoint);
bitcoin_txid(tx, &o->txid);
o->amount = bitcoin_tx_output_get_amount(tx, j);
o->amount = amount_asset_to_sat(&amount);
o->txindex = i;
o->outnum = j;
o->scriptPubKey = tal_steal(o, script);

View File

@ -658,12 +658,12 @@ static void topo_add_utxos(struct chain_topology *topo, struct block *b)
continue;
const u8 *script = bitcoin_tx_output_get_script(tmpctx, tx, j);
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, j);
struct amount_asset amt = bitcoin_tx_output_get_amount(tx, j);
if (is_p2wsh(script, NULL)) {
if (amount_asset_is_main(&amt) && is_p2wsh(script, NULL)) {
wallet_utxoset_add(topo->ld->wallet, tx, j,
b->height, i, script,
amt);
amount_asset_to_sat(&amt));
}
}
}

View File

@ -22,7 +22,8 @@
static struct amount_sat calc_tx_fee(struct amount_sat sat_in,
const struct bitcoin_tx *tx)
{
struct amount_sat amt, fee = sat_in;
struct amount_asset amt;
struct amount_sat fee = sat_in;
const u8 *oscript;
size_t scriptlen;
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
@ -34,7 +35,12 @@ static struct amount_sat calc_tx_fee(struct amount_sat sat_in,
if (chainparams->is_elements && scriptlen == 0)
continue;
if (!amount_sat_sub(&fee, fee, amt))
/* Ignore outputs that are not denominated in our main
* currency. */
if (!amount_asset_is_main(&amt))
continue;
if (!amount_sat_sub(&fee, fee, amount_asset_to_sat(&amt)))
fatal("Tx spends more than input %s? %s",
type_to_string(tmpctx, struct amount_sat, &sat_in),
type_to_string(tmpctx, struct bitcoin_tx, tx));

View File

@ -489,10 +489,13 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
if (!feerate) {
/* We have at least one data point: the last tx's feerate. */
struct amount_sat fee = channel->funding;
for (size_t i = 0; i < channel->last_tx->wtx->num_outputs; i++)
if (!amount_sat_sub(&fee, fee,
bitcoin_tx_output_get_amount(
channel->last_tx, i))) {
for (size_t i = 0; i < channel->last_tx->wtx->num_outputs; i++) {
struct amount_asset asset =
bitcoin_tx_output_get_amount(channel->last_tx, i);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (!amount_sat_sub(&fee, fee, amt)) {
log_broken(channel->log, "Could not get fee"
" funding %s tx %s",
type_to_string(tmpctx,
@ -503,6 +506,7 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
channel->last_tx));
return KEEP_WATCHING;
}
}
feerate = fee.satoshis / bitcoin_tx_weight(tx); /* Raw: reverse feerate extraction */
if (feerate < feerate_floor())

View File

@ -967,13 +967,16 @@ static bool check_funding_tx(const struct bitcoin_tx *tx,
const struct channel *channel)
{
u8 *wscript;
struct amount_asset asset =
bitcoin_tx_output_get_amount(tx, channel->funding_outnum);
if (!amount_asset_is_main(&asset))
return false;
if (channel->funding_outnum >= tx->wtx->num_outputs)
return false;
if (!amount_sat_eq(bitcoin_tx_output_get_amount(tx,
channel->funding_outnum),
channel->funding))
if (!amount_sat_eq(amount_asset_to_sat(&asset), channel->funding))
return false;
wscript = bitcoin_redeem_2of2(tmpctx,

View File

@ -3,6 +3,7 @@
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/derive_basepoints.h>
#include <common/htlc_tx.h>
#include <common/initial_commit_tx.h>
@ -163,11 +164,14 @@ static bool set_htlc_timeout_fee(struct bitcoin_tx *tx,
const struct bitcoin_signature *remotesig,
const u8 *wscript)
{
static struct amount_sat fee = AMOUNT_SAT_INIT(UINT64_MAX);
struct amount_sat amount = bitcoin_tx_output_get_amount(tx, 0);
static struct amount_sat amount, fee = AMOUNT_SAT_INIT(UINT64_MAX);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, 0);
size_t weight = elements_add_overhead(663, tx->wtx->num_inputs,
tx->wtx->num_outputs);
assert(amount_asset_is_main(&asset));
amount = amount_asset_to_sat(&asset);
/* BOLT #3:
*
* The fee for an HTLC-timeout transaction:
@ -202,6 +206,7 @@ static void set_htlc_success_fee(struct bitcoin_tx *tx,
const u8 *wscript)
{
static struct amount_sat amt, fee = AMOUNT_SAT_INIT(UINT64_MAX);
struct amount_asset asset;
size_t weight = elements_add_overhead(703, tx->wtx->num_inputs,
tx->wtx->num_outputs);
/* BOLT #3:
@ -225,7 +230,10 @@ static void set_htlc_success_fee(struct bitcoin_tx *tx,
return;
}
amt = bitcoin_tx_output_get_amount(tx, 0);
asset = bitcoin_tx_output_get_amount(tx, 0);
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (!amount_sat_sub(&amt, amt, fee))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Cannot deduct htlc-success fee %s from tx %s",
@ -934,6 +942,7 @@ static void resolve_htlc_tx(const struct chainparams *chainparams,
struct tracked_output *out;
struct bitcoin_tx *tx;
struct amount_sat amt;
struct amount_asset asset;
enum tx_type tx_type = OUR_DELAYED_RETURN_TO_WALLET;
u8 *wscript = bitcoin_wscript_htlc_tx(htlc_tx, to_self_delay[LOCAL],
&keyset->self_revocation_key,
@ -949,7 +958,9 @@ static void resolve_htlc_tx(const struct chainparams *chainparams,
* `to_self_delay` field) before spending that HTLC-timeout
* output.
*/
amt = bitcoin_tx_output_get_amount(htlc_tx, 0);
asset = bitcoin_tx_output_get_amount(htlc_tx, 0);
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
out = new_tracked_output(chainparams, outs, htlc_txid, tx_blockheight,
(*outs)[out_index]->resolved->tx_type,
0, amt,
@ -1796,7 +1807,11 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
const size_t *matches;
size_t which_htlc;
const u8 *oscript = bitcoin_tx_output_get_script(tmpctx, tx, i);
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, i);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, i);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (chainparams->is_elements &&
(oscript == NULL || tal_bytelen(oscript) == 0)) {
@ -2007,7 +2022,11 @@ static void tell_wallet_to_remote(const struct bitcoin_tx *tx,
const struct pubkey *per_commit_point,
bool option_static_remotekey)
{
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, outnum);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, outnum);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
/* A NULL per_commit_point is how we indicate the pubkey doesn't need
* changing. */
@ -2157,7 +2176,10 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
const size_t *matches;
size_t which_htlc;
const u8 *oscript = bitcoin_tx_output_get_script(tmpctx, tx, i);
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, i);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, i);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (chainparams->is_elements &&
(oscript == NULL || tal_bytelen(oscript) == 0)) {
@ -2391,7 +2413,10 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
const size_t *matches;
size_t which_htlc;
const u8 *oscript = bitcoin_tx_output_get_script(tmpctx, tx, i);
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, i);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, i);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (chainparams->is_elements &&
(oscript == NULL || tal_bytelen(oscript) == 0)) {
@ -2556,7 +2581,10 @@ static void handle_unknown_commitment(const struct bitcoin_tx *tx,
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
struct tracked_output *out;
const u8 *oscript = bitcoin_tx_output_get_script(tmpctx, tx, i);
struct amount_sat amt = bitcoin_tx_output_get_amount(tx, i);
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, i);
struct amount_sat amt;
assert(amount_asset_is_main(&asset));
amt = amount_asset_to_sat(&asset);
if (oscript != NULL && local_script
&& scripteq(oscript, local_script)) {

View File

@ -340,6 +340,7 @@ static struct command_result *tx_prepare_dryrun(struct command *cmd,
struct amount_sat funding;
bool funding_found;
u8 *placeholder = tal_hexdata(tmpctx, placeholder_script, strlen(placeholder_script));
struct amount_asset asset;
/* Stash the 'reserved' txid to unreserve later */
hex = json_strdup(tmpctx, buf, json_get_member(buf, result, "txid"));
@ -355,8 +356,15 @@ static struct command_result *tx_prepare_dryrun(struct command *cmd,
funding_found = false;
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
const u8 *output_script = bitcoin_tx_output_get_script(tmpctx, tx, i);
asset = bitcoin_tx_output_get_amount(tx, i);
/* We do not support funding a channel with anything but the
* main asset, for now. */
if (!amount_asset_is_main(&asset))
continue;
if (scripteq(output_script, placeholder)) {
funding = bitcoin_tx_output_get_amount(tx, i);
funding = amount_asset_to_sat(&asset);
funding_found = true;
break;
}

View File

@ -1520,6 +1520,10 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx,
u32 index;
bool is_p2sh;
const u8 *script;
struct amount_asset asset = bitcoin_tx_output_get_amount(tx, output);
if (!amount_asset_is_main(&asset))
continue;
script = bitcoin_tx_output_get_script(tmpctx, tx, output);
if (!script)
@ -1531,7 +1535,7 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx,
utxo = tal(w, struct utxo);
utxo->keyindex = index;
utxo->is_p2sh = is_p2sh;
utxo->amount = bitcoin_tx_output_get_amount(tx, output);
utxo->amount = amount_asset_to_sat(&asset);
utxo->status = output_state_available;
bitcoin_txid(tx, &utxo->txid);
utxo->outnum = output;

View File

@ -12,6 +12,12 @@
secp256k1_context *secp256k1_ctx;
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,