Browse Source

elements,pset: populate elements specific data for PSBTs

PSETs have a bit different requirements. The witness_utxo needs
the asset tag + values, and these should also be added to the PSET
struct separately as well. To do this, we create a new 'init' method for
elements inputs, which takes care of the elements specific things.
paymod-04
niftynei 4 years ago
committed by Rusty Russell
parent
commit
f5f85b389d
  1. 2
      bitcoin/chainparams.h
  2. 116
      bitcoin/psbt.c
  3. 18
      bitcoin/psbt.h
  4. 56
      bitcoin/tx.c
  5. 15
      wallet/db.c

2
bitcoin/chainparams.h

@ -9,6 +9,8 @@
#include <common/bip32.h>
#include <stdbool.h>
#define ELEMENTS_ASSET_LEN 33
struct chainparams {
const char *network_name;
const char *bip173_name;

116
bitcoin/psbt.c

@ -267,6 +267,16 @@ bool psbt_input_set_partial_sig(struct wally_psbt *psbt, size_t in,
sizeof(sig->s.data)) == WALLY_OK;
}
static void psbt_input_set_witness_utxo(struct wally_psbt *psbt, size_t in,
struct wally_tx_output *txout)
{
int wally_err;
assert(psbt->num_inputs > in);
wally_err = wally_psbt_input_set_witness_utxo(&psbt->inputs[in],
txout);
assert(wally_err == WALLY_OK);
}
void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in,
const u8 *scriptPubkey, struct amount_sat amt)
{
@ -274,7 +284,6 @@ void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in,
int wally_err;
u8 *scriptpk;
assert(psbt->num_inputs > in);
if (scriptPubkey) {
assert(is_p2wsh(scriptPubkey, NULL) || is_p2wpkh(scriptPubkey, NULL)
|| is_p2sh(scriptPubkey, NULL));
@ -293,10 +302,34 @@ void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in,
tal_bytelen(scriptpk),
&prev_out);
assert(wally_err == WALLY_OK);
wally_err = wally_psbt_input_set_witness_utxo(&psbt->inputs[in],
prev_out);
psbt_input_set_witness_utxo(psbt, in, prev_out);
}
static void psbt_input_set_elements_prev_utxo(struct wally_psbt *psbt,
size_t in,
const u8 *scriptPubkey,
struct amount_asset *asset,
const u8 *nonce)
{
struct wally_tx_output *prev_out;
int wally_err;
u8 *prefixed_value = amount_asset_extract_value(psbt, asset);
wally_err =
wally_tx_elements_output_init_alloc(scriptPubkey,
tal_bytelen(scriptPubkey),
asset->asset,
sizeof(asset->asset),
prefixed_value,
tal_bytelen(prefixed_value),
nonce,
tal_bytelen(nonce),
NULL, 0,
NULL, 0,
&prev_out);
assert(wally_err == WALLY_OK);
tal_steal(psbt, psbt->inputs[in].witness_utxo);
psbt_input_set_witness_utxo(psbt, in, prev_out);
}
void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in,
@ -316,6 +349,76 @@ void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in,
psbt_input_set_prev_utxo(psbt, in, scriptPubkey, amt);
}
static void
psbt_input_set_elements_prev_utxo_wscript(struct wally_psbt *psbt,
size_t in,
const u8 *wscript,
struct amount_asset *asset,
const u8 *nonce)
{
int wally_err;
const u8 *scriptPubkey;
if (wscript) {
scriptPubkey = scriptpubkey_p2wsh(psbt, wscript);
wally_err = wally_psbt_input_set_witness_script(
&psbt->inputs[in],
cast_const(u8 *, wscript),
tal_bytelen(wscript));
assert(wally_err == WALLY_OK);
} else
scriptPubkey = NULL;
psbt_input_set_elements_prev_utxo(psbt, in, scriptPubkey,
asset, nonce);
}
void psbt_elements_input_init_witness(struct wally_psbt *psbt, size_t in,
const u8 *witscript,
struct amount_asset *asset,
const u8 *nonce)
{
psbt_input_set_elements_prev_utxo_wscript(
psbt, in, witscript,
asset, nonce);
if (asset->value > 0)
wally_psbt_elements_input_set_value(&psbt->inputs[in],
asset->value);
/* PSET expects an asset tag without the prefix */
if (wally_psbt_elements_input_set_asset(&psbt->inputs[in],
asset->asset + 1,
ELEMENTS_ASSET_LEN - 1) != WALLY_OK)
abort();
}
void psbt_elements_input_init(struct wally_psbt *psbt, size_t in,
const u8 *scriptPubkey,
struct amount_asset *asset,
const u8 *nonce)
{
psbt_input_set_elements_prev_utxo(psbt, in,
scriptPubkey,
asset, nonce);
if (asset->value > 0) {
if (wally_psbt_elements_input_set_value(
&psbt->inputs[in],
asset->value) != WALLY_OK)
abort();
}
/* PSET expects an asset tag without the prefix */
/* FIXME: Verify that we're sending unblinded asset tag */
if (wally_psbt_elements_input_set_asset(
&psbt->inputs[in],
asset->asset + 1,
ELEMENTS_ASSET_LEN - 1) != WALLY_OK)
abort();
}
bool psbt_input_set_redeemscript(struct wally_psbt *psbt, size_t in,
const u8 *redeemscript)
{
@ -333,7 +436,10 @@ struct amount_sat psbt_input_get_amount(struct wally_psbt *psbt,
struct amount_sat val;
assert(in < psbt->num_inputs);
if (psbt->inputs[in].witness_utxo) {
val.satoshis = psbt->inputs[in].witness_utxo->satoshi; /* Raw: type conversion */
struct amount_asset amt_asset =
wally_tx_output_get_amount(psbt->inputs[in].witness_utxo);
assert(amount_asset_is_main(&amt_asset));
val = amount_asset_to_sat(&amt_asset);
} else if (psbt->inputs[in].non_witness_utxo) {
int idx = psbt->tx->inputs[in].index;
struct wally_tx *prev_tx = psbt->inputs[in].non_witness_utxo;

18
bitcoin/psbt.h

@ -10,6 +10,7 @@ struct wally_tx_output;
struct wally_psbt;
struct wally_psbt_input;
struct wally_tx;
struct amount_asset;
struct amount_sat;
struct bitcoin_signature;
struct pubkey;
@ -55,10 +56,21 @@ WARN_UNUSED_RESULT bool psbt_input_set_partial_sig(struct wally_psbt *psbt, size
const struct pubkey *pubkey,
const struct bitcoin_signature *sig);
void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in,
const u8 *wscript, struct amount_sat amt);
void psbt_input_set_prev_utxo(struct wally_psbt *psbt,
size_t in,
const u8 *wscript,
struct amount_sat amt);
void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in,
const u8 *wscript, struct amount_sat amt);
const u8 *wscript,
struct amount_sat amt);
void psbt_elements_input_init(struct wally_psbt *psbt, size_t in,
const u8 *scriptPubkey,
struct amount_asset *asset,
const u8 *nonce);
void psbt_elements_input_init_witness(struct wally_psbt *psbt, size_t in,
const u8 *witscript,
struct amount_asset *asset,
const u8 *nonce);
bool psbt_input_set_redeemscript(struct wally_psbt *psbt, size_t in,
const u8 *redeemscript);
struct amount_sat psbt_input_get_amount(struct wally_psbt *psbt,

56
bitcoin/tx.c

@ -207,18 +207,51 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid,
if (input_wscript) {
/* Add the prev output's data into the PSBT struct */
psbt_input_set_prev_utxo_wscript(tx->psbt, i, input_wscript, amount);
if (is_elements(chainparams)) {
struct amount_asset asset;
/*FIXME: persist asset tags */
asset = amount_sat_to_asset(
&amount,
chainparams->fee_asset_tag);
psbt_elements_input_init_witness(tx->psbt, i,
input_wscript,
&asset, NULL);
} else
psbt_input_set_prev_utxo_wscript(tx->psbt, i,
input_wscript,
amount);
} else if (scriptPubkey) {
if (is_p2wsh(scriptPubkey, NULL) || is_p2wpkh(scriptPubkey, NULL) ||
/* FIXME: assert that p2sh inputs are witness/are accompanied by a redeemscript+witnessscript */
if (is_p2wsh(scriptPubkey, NULL) ||
is_p2wpkh(scriptPubkey, NULL) ||
/* FIXME: assert that p2sh inputs are
* witness/are accompanied by a
* redeemscript+witnessscript */
is_p2sh(scriptPubkey, NULL)) {
/* the only way to get here currently with a p2sh script is via a p2sh-p2wpkh script
/* the only way to get here currently with
* a p2sh script is via a p2sh-p2wpkh script
* that we've created ...*/
/* Relevant section from bip-0174, emphasis mine:
* ** Value: The entire transaction output in network serialization which the current input spends from.
* This should only be present for inputs which spend segwit outputs, _including P2SH embedded ones._
/* BIP0174:
* ** Value: The entire transaction output in
* network serialization which the
* current input spends from.
* This should only be present for
* inputs which spend segwit outputs,
* including P2SH embedded ones.
*/
psbt_input_set_prev_utxo(tx->psbt, i, scriptPubkey, amount);
if (is_elements(chainparams)) {
struct amount_asset asset;
/*FIXME: persist asset tags */
asset = amount_sat_to_asset(
&amount,
chainparams->fee_asset_tag);
/* FIXME: persist nonces */
psbt_elements_input_init(tx->psbt, i,
scriptPubkey,
&asset, NULL);
} else
psbt_input_set_prev_utxo(tx->psbt, i,
scriptPubkey,
amount);
}
}
@ -722,10 +755,9 @@ wally_tx_output_get_amount(const struct wally_tx_output *output)
if (chainparams->is_elements) {
assert(output->asset_len == sizeof(amount.asset));
memcpy(&amount.asset, output->asset, sizeof(amount.asset));
/* We currently only support explicit value asset tags, others
* are confidential, so don't even try to assign a value to
* it. */
/* We currently only support explicit value
* asset tags, others are confidential, so
* don't even try to assign a value to it. */
if (output->asset[0] == 0x01) {
memcpy(&raw, output->value + 1, sizeof(raw));
amount.value = be64_to_cpu(raw);

15
wallet/db.c

@ -1165,9 +1165,18 @@ void migrate_last_tx_to_psbt(struct lightningd *ld, struct db *db)
funding_wscript = bitcoin_redeem_2of2(stmt, &local_funding_pubkey,
&remote_funding_pubkey);
psbt_input_set_prev_utxo_wscript(last_tx->psbt,
0, funding_wscript,
funding_sat);
if (is_elements(chainparams)) {
/*FIXME: persist asset tags */
struct amount_asset asset;
asset = amount_sat_to_asset(&funding_sat,
chainparams->fee_asset_tag);
psbt_elements_input_init_witness(last_tx->psbt,
0, funding_wscript,
&asset, NULL);
} else
psbt_input_set_prev_utxo_wscript(last_tx->psbt,
0, funding_wscript,
funding_sat);
if (!db_column_signature(stmt, 5, &last_sig.s))
abort();

Loading…
Cancel
Save