Update libwally to 0.8.8, support PSBTv2

Libwally update breaks compatibility, so
we do this in one large step.

Changelog-Changed: JSON-RPC: elements network PSET now only supports PSETv2.
Changelog-Added: JSON-RPC: PSBTv2 supported for fundchannel_complete, openchannel_update, reserveinputs, sendpsbt, signpsbt, withdraw and unreserveinputs parameter psbt, openchannel_init and openchannel_bump parameter initialpsbt, openchannel_signed parameter signed_psbt and utxopsbt parameter utxopsbt
This commit is contained in:
Greg Sanders
2023-02-01 11:37:59 -05:00
committed by Rusty Russell
parent 5eddf3cd73
commit 908f834d66
29 changed files with 476 additions and 265 deletions

View File

@@ -24,36 +24,26 @@ static struct wally_psbt *init_psbt(const tal_t *ctx, size_t num_inputs, size_t
tal_wally_start(); tal_wally_start();
if (is_elements(chainparams)) if (is_elements(chainparams))
wally_err = wally_psbt_elements_init_alloc(0, num_inputs, num_outputs, 0, &psbt); wally_err = wally_psbt_init_alloc(2, num_inputs, num_outputs, 0, WALLY_PSBT_INIT_PSET, &psbt);
else else
wally_err = wally_psbt_init_alloc(0, num_inputs, num_outputs, 0, &psbt); wally_err = wally_psbt_init_alloc(2, num_inputs, num_outputs, 0, 0, &psbt);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
/* By default we are modifying them internally; allow it */
wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS);
tal_add_destructor(psbt, psbt_destroy); tal_add_destructor(psbt, psbt_destroy);
tal_wally_end_onto(ctx, psbt, struct wally_psbt); tal_wally_end_onto(ctx, psbt, struct wally_psbt);
return psbt; return psbt;
} }
/* FIXME extremely thin wrapper; remove? */
struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime) struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime)
{ {
int wally_err;
struct wally_tx *wtx;
struct wally_psbt *psbt; struct wally_psbt *psbt;
tal_wally_start();
if (wally_tx_init_alloc(WALLY_TX_VERSION_2, locktime, num_inputs, num_outputs, &wtx) != WALLY_OK)
abort();
/* wtx is freed below */
tal_wally_end(NULL);
psbt = init_psbt(ctx, num_inputs, num_outputs); psbt = init_psbt(ctx, num_inputs, num_outputs);
wally_psbt_set_fallback_locktime(psbt, locktime);
tal_wally_start();
wally_err = wally_psbt_set_global_tx(psbt, wtx);
assert(wally_err == WALLY_OK);
tal_wally_end(psbt);
wally_tx_free(wtx);
return psbt; return psbt;
} }
@@ -72,17 +62,18 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx)
struct wally_psbt *psbt; struct wally_psbt *psbt;
int wally_err; int wally_err;
psbt = init_psbt(ctx, wtx->num_inputs, wtx->num_outputs); psbt = create_psbt(ctx, wtx->num_inputs, wtx->num_outputs, wtx->locktime);
tal_wally_start(); tal_wally_start();
/* Set directly: avoids psbt checks for non-NULL scripts/witnesses */
wally_err = wally_tx_clone_alloc(wtx, 0, &psbt->tx); /* locktime set in create_psbt for now */
assert(wally_err == WALLY_OK); wally_psbt_set_tx_version(psbt, wtx->version);
/* Inputs/outs are pre-allocated above, 'add' them as empty dummies */ wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS);
psbt->num_inputs = wtx->num_inputs;
psbt->num_outputs = wtx->num_outputs;
for (size_t i = 0; i < wtx->num_inputs; i++) { for (size_t i = 0; i < wtx->num_inputs; i++) {
wally_err = wally_psbt_add_tx_input_at(psbt, i, 0, &wtx->inputs[i]);
assert(wally_err == WALLY_OK);
/* add these scripts + witnesses to the psbt */ /* add these scripts + witnesses to the psbt */
if (wtx->inputs[i].script) { if (wtx->inputs[i].script) {
wally_err = wally_err =
@@ -90,24 +81,19 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx)
wtx->inputs[i].script, wtx->inputs[i].script,
wtx->inputs[i].script_len); wtx->inputs[i].script_len);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
/* Clear out script sig data */
psbt->tx->inputs[i].script_len = 0;
tal_free(psbt->tx->inputs[i].script);
psbt->tx->inputs[i].script = NULL;
} }
if (wtx->inputs[i].witness) { if (wtx->inputs[i].witness) {
wally_err = wally_err =
wally_psbt_input_set_final_witness(&psbt->inputs[i], wally_psbt_input_set_final_witness(&psbt->inputs[i],
wtx->inputs[i].witness); wtx->inputs[i].witness);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
/* Delete the witness data */
wally_tx_witness_stack_free(psbt->tx->inputs[i].witness);
psbt->tx->inputs[i].witness = NULL;
} }
} }
for (size_t i = 0; i < wtx->num_outputs; i++) {
wally_psbt_add_tx_output_at(psbt, i, 0, &wtx->outputs[i]);
}
tal_wally_end(psbt); tal_wally_end(psbt);
return psbt; return psbt;
} }
@@ -128,7 +114,7 @@ struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt,
int wally_err; int wally_err;
tal_wally_start(); tal_wally_start();
wally_err = wally_psbt_add_input_at(psbt, insert_at, flags, input); wally_err = wally_psbt_add_tx_input_at(psbt, insert_at, flags, input);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
tal_wally_end(psbt); tal_wally_end(psbt);
return &psbt->inputs[insert_at]; return &psbt->inputs[insert_at];
@@ -168,7 +154,7 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt,
abort(); abort();
} }
wally_err = wally_psbt_add_input_at(psbt, input_num, flags, tx_in); wally_err = wally_psbt_add_tx_input_at(psbt, input_num, flags, tx_in);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
wally_tx_input_free(tx_in); wally_tx_input_free(tx_in);
tal_wally_end(psbt); tal_wally_end(psbt);
@@ -204,7 +190,7 @@ struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt,
int wally_err; int wally_err;
tal_wally_start(); tal_wally_start();
wally_err = wally_psbt_add_output_at(psbt, insert_at, 0, output); wally_err = wally_psbt_add_tx_output_at(psbt, insert_at, 0, output);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
tal_wally_end(psbt); tal_wally_end(psbt);
return &psbt->outputs[insert_at]; return &psbt->outputs[insert_at];
@@ -217,7 +203,7 @@ struct wally_psbt_output *psbt_append_output(struct wally_psbt *psbt,
struct wally_psbt_output *out; struct wally_psbt_output *out;
struct wally_tx_output *tx_out = wally_tx_output(NULL, script, amount); struct wally_tx_output *tx_out = wally_tx_output(NULL, script, amount);
out = psbt_add_output(psbt, tx_out, psbt->tx->num_outputs); out = psbt_add_output(psbt, tx_out, psbt->num_outputs);
wally_tx_output_free(tx_out); wally_tx_output_free(tx_out);
return out; return out;
} }
@@ -264,7 +250,7 @@ void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in,
pubkey_to_der(pk_der, pubkey); pubkey_to_der(pk_der, pubkey);
tal_wally_start(); tal_wally_start();
wally_err = wally_psbt_input_add_keypath_item(&psbt->inputs[in], wally_err = wally_psbt_input_keypath_add(&psbt->inputs[in],
pk_der, sizeof(pk_der), pk_der, sizeof(pk_der),
fingerprint, sizeof(fingerprint), fingerprint, sizeof(fingerprint),
empty_path, ARRAY_SIZE(empty_path)); empty_path, ARRAY_SIZE(empty_path));
@@ -361,7 +347,7 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in,
tal_wally_start(); tal_wally_start();
if (asset->value > 0) if (asset->value > 0)
if (wally_psbt_input_set_value(&psbt->inputs[in], if (wally_psbt_input_set_amount(&psbt->inputs[in],
asset->value) != WALLY_OK) asset->value) != WALLY_OK)
abort(); abort();
@@ -375,7 +361,6 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in,
void psbt_elements_normalize_fees(struct wally_psbt *psbt) void psbt_elements_normalize_fees(struct wally_psbt *psbt)
{ {
struct amount_asset asset;
size_t fee_output_idx = psbt->num_outputs; size_t fee_output_idx = psbt->num_outputs;
if (!is_elements(chainparams)) if (!is_elements(chainparams))
@@ -383,15 +368,15 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt)
/* Elements requires that every input value is accounted for, /* Elements requires that every input value is accounted for,
* including the fees */ * including the fees */
struct amount_sat total_in = AMOUNT_SAT(0), val; struct amount_sat total_fee = AMOUNT_SAT(0), val;
for (size_t i = 0; i < psbt->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
val = psbt_input_get_amount(psbt, i); val = psbt_input_get_amount(psbt, i);
if (!amount_sat_add(&total_in, total_in, val)) if (!amount_sat_add(&total_fee, total_fee, val))
return; return;
} }
for (size_t i = 0; i < psbt->num_outputs; i++) { for (size_t i = 0; i < psbt->num_outputs; i++) {
asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); struct amount_asset output_amount = wally_psbt_output_get_amount(&psbt->outputs[i]);
if (elements_wtx_output_is_fee(psbt->tx, i)) { if (elements_psbt_output_is_fee(psbt, i)) {
if (fee_output_idx == psbt->num_outputs) { if (fee_output_idx == psbt->num_outputs) {
fee_output_idx = i; fee_output_idx = i;
continue; continue;
@@ -401,40 +386,47 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt)
psbt_rm_output(psbt, i--); psbt_rm_output(psbt, i--);
continue; continue;
} }
if (!amount_asset_is_main(&asset)) if (!amount_asset_is_main(&output_amount))
continue; continue;
if (!amount_sat_sub(&total_in, total_in, if (!amount_sat_sub(&total_fee, total_fee,
amount_asset_to_sat(&asset))) amount_asset_to_sat(&output_amount)))
return; return;
} }
if (amount_sat_eq(total_in, AMOUNT_SAT(0))) if (amount_sat_eq(total_fee, AMOUNT_SAT(0)))
return; return;
/* We need to add a fee output */ /* We need to add a fee output */
if (fee_output_idx == psbt->num_outputs) { if (fee_output_idx == psbt->num_outputs) {
psbt_append_output(psbt, NULL, total_in); psbt_append_output(psbt, NULL, total_fee);
} else { } else {
u64 sats = total_in.satoshis; /* Raw: wally API */ int ret;
struct wally_tx_output *out = &psbt->tx->outputs[fee_output_idx]; u64 sats = total_fee.satoshis; /* Raw: wally API */
if (wally_tx_confidential_value_from_satoshi( struct wally_psbt_output *out = &psbt->outputs[fee_output_idx];
sats, out->value, out->value_len) != WALLY_OK) ret = wally_psbt_output_set_amount(out, sats);
return; assert(ret == WALLY_OK);
} }
} }
void wally_psbt_input_get_txid(const struct wally_psbt_input *in,
struct bitcoin_txid *txid)
{
BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash));
memcpy(txid, in->txhash, sizeof(struct bitcoin_txid));
}
bool psbt_has_input(const struct wally_psbt *psbt, bool psbt_has_input(const struct wally_psbt *psbt,
const struct bitcoin_outpoint *outpoint) const struct bitcoin_outpoint *outpoint)
{ {
for (size_t i = 0; i < psbt->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
struct bitcoin_txid in_txid; struct bitcoin_txid in_txid;
struct wally_tx_input *in = &psbt->tx->inputs[i]; const struct wally_psbt_input *in = &psbt->inputs[i];
if (outpoint->n != in->index) if (outpoint->n != in->index)
continue; continue;
wally_tx_input_get_txid(in, &in_txid); wally_psbt_input_get_txid(in, &in_txid);
if (bitcoin_txid_eq(&outpoint->txid, &in_txid)) if (bitcoin_txid_eq(&outpoint->txid, &in_txid))
return true; return true;
} }
@@ -452,7 +444,7 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
assert(amount_asset_is_main(&amt_asset)); assert(amount_asset_is_main(&amt_asset));
val = amount_asset_to_sat(&amt_asset); val = amount_asset_to_sat(&amt_asset);
} else if (psbt->inputs[in].utxo) { } else if (psbt->inputs[in].utxo) {
int idx = psbt->tx->inputs[in].index; int idx = psbt->inputs[in].index;
struct wally_tx *prev_tx = psbt->inputs[in].utxo; struct wally_tx *prev_tx = psbt->inputs[in].utxo;
val = amount_sat(prev_tx->outputs[idx].satoshi); val = amount_sat(prev_tx->outputs[idx].satoshi);
} else } else
@@ -466,7 +458,7 @@ struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
{ {
struct amount_asset asset; struct amount_asset asset;
assert(out < psbt->num_outputs); assert(out < psbt->num_outputs);
asset = wally_tx_output_get_amount(&psbt->tx->outputs[out]); asset = wally_psbt_output_get_amount(&psbt->outputs[out]);
assert(amount_asset_is_main(&asset)); assert(amount_asset_is_main(&asset));
return amount_asset_to_sat(&asset); return amount_asset_to_sat(&asset);
} }
@@ -505,7 +497,7 @@ u8 *psbt_make_key(const tal_t *ctx, u8 key_subtype, const u8 *key_data)
*** <tt><data></tt> *** <tt><data></tt>
*/ */
u8 *key = tal_arr(ctx, u8, 0); u8 *key = tal_arr(ctx, u8, 0);
add_type(&key, PSBT_PROPRIETARY_TYPE); add_type(&key, WALLY_PSBT_PROPRIETARY_TYPE);
add_varint(&key, strlen(LIGHTNING_PROPRIETARY_PREFIX)); add_varint(&key, strlen(LIGHTNING_PROPRIETARY_PREFIX));
add(&key, LIGHTNING_PROPRIETARY_PREFIX, add(&key, LIGHTNING_PROPRIETARY_PREFIX,
strlen(LIGHTNING_PROPRIETARY_PREFIX)); strlen(LIGHTNING_PROPRIETARY_PREFIX));
@@ -616,9 +608,11 @@ bool psbt_finalize(struct wally_psbt *psbt)
for (size_t i = 0; i < psbt->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_psbt_input *input = &psbt->inputs[i];
struct wally_tx_witness_stack *stack; struct wally_tx_witness_stack *stack;
const struct wally_map_item *iws;
if (!is_anchor_witness_script(input->witness_script, iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05);
input->witness_script_len)) if (!iws || !is_anchor_witness_script(iws->value,
iws->value_len))
continue; continue;
if (input->signatures.num_items != 1) if (input->signatures.num_items != 1)
@@ -643,8 +637,8 @@ bool psbt_finalize(struct wally_psbt *psbt)
input->signatures.items[0].value, input->signatures.items[0].value,
input->signatures.items[0].value_len); input->signatures.items[0].value_len);
wally_tx_witness_stack_add(stack, wally_tx_witness_stack_add(stack,
input->witness_script, iws->value,
input->witness_script_len); iws->value_len);
wally_psbt_input_set_final_witness(input, stack); wally_psbt_input_set_final_witness(input, stack);
} }
@@ -662,7 +656,7 @@ struct wally_tx *psbt_final_tx(const tal_t *ctx, const struct wally_psbt *psbt)
return NULL; return NULL;
tal_wally_start(); tal_wally_start();
if (wally_psbt_extract(psbt, &wtx) == WALLY_OK) if (wally_psbt_extract(psbt, /* flags */ 0, &wtx) == WALLY_OK)
tal_add_destructor(wtx, wally_tx_destroy); tal_add_destructor(wtx, wally_tx_destroy);
else else
wtx = NULL; wtx = NULL;
@@ -679,7 +673,7 @@ struct wally_psbt *psbt_from_b64(const tal_t *ctx,
char *str = tal_strndup(tmpctx, b64, b64len); char *str = tal_strndup(tmpctx, b64, b64len);
tal_wally_start(); tal_wally_start();
if (wally_psbt_from_base64(str, &psbt) == WALLY_OK) if (wally_psbt_from_base64(str, /* flags */ 0, &psbt) == WALLY_OK)
tal_add_destructor(psbt, psbt_destroy); tal_add_destructor(psbt, psbt_destroy);
else else
psbt = NULL; psbt = NULL;
@@ -713,7 +707,9 @@ const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt,
return NULL; return NULL;
} }
wally_psbt_get_length(psbt, 0, &len); if (wally_psbt_get_length(psbt, 0, &len) != WALLY_OK) {
abort();
}
bytes = tal_arr(ctx, u8, len); bytes = tal_arr(ctx, u8, len);
if (wally_psbt_to_bytes(psbt, 0, bytes, len, bytes_written) != WALLY_OK || if (wally_psbt_to_bytes(psbt, 0, bytes, len, bytes_written) != WALLY_OK ||
@@ -730,7 +726,7 @@ struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes,
struct wally_psbt *psbt; struct wally_psbt *psbt;
tal_wally_start(); tal_wally_start();
if (wally_psbt_from_bytes(bytes, byte_len, &psbt) == WALLY_OK) if (wally_psbt_from_bytes(bytes, byte_len, /* flags */ 0, &psbt) == WALLY_OK)
tal_add_destructor(psbt, psbt_destroy); tal_add_destructor(psbt, psbt_destroy);
else else
psbt = NULL; psbt = NULL;
@@ -780,38 +776,23 @@ struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx,
return psbt; return psbt;
} }
/* This only works on a non-final psbt because we're ALL SEGWIT! */
void psbt_txid(const tal_t *ctx, void psbt_txid(const tal_t *ctx,
const struct wally_psbt *psbt, struct bitcoin_txid *txid, const struct wally_psbt *psbt,
struct bitcoin_txid *txid,
struct wally_tx **wtx) struct wally_tx **wtx)
{ {
struct wally_tx *tx; struct wally_tx *tx;
int wally_err;
assert(psbt->version == 2);
/* You can *almost* take txid of global tx. But @niftynei thought /* We rely on wally extractor to fill out all txid-related fields including scriptSigs */
* about this far more than me and pointed out that P2SH
* inputs would not be represented, so here we go. */
tal_wally_start(); tal_wally_start();
wally_tx_clone_alloc(psbt->tx, 0, &tx); wally_err = wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx);
assert(wally_err == WALLY_OK);
wally_err = wally_tx_get_txid(tx, txid->shad.sha.u.u8, sizeof(txid->shad.sha.u.u8));
assert(wally_err == WALLY_OK);
tal_wally_end(ctx);
for (size_t i = 0; i < tx->num_inputs; i++) {
if (psbt->inputs[i].final_scriptsig) {
wally_tx_set_input_script(tx, i,
psbt->inputs[i].final_scriptsig,
psbt->inputs[i].final_scriptsig_len);
} else if (psbt->inputs[i].redeem_script) {
u8 *script;
/* P2SH requires push of the redeemscript, from libwally src */
script = tal_arr(tmpctx, u8, 0);
script_push_bytes(&script,
psbt->inputs[i].redeem_script,
psbt->inputs[i].redeem_script_len);
wally_tx_set_input_script(tx, i, script, tal_bytelen(script));
}
}
tal_wally_end_onto(ctx, tx, struct wally_tx);
wally_txid(tx, txid);
if (wtx) if (wtx)
*wtx = tx; *wtx = tx;
else else
@@ -832,9 +813,9 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt)
} }
for (size_t i = 0; i < psbt->num_outputs; i++) { for (size_t i = 0; i < psbt->num_outputs; i++) {
asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); asset = wally_psbt_output_get_amount(&psbt->outputs[i]);
if (!amount_asset_is_main(&asset) if (!amount_asset_is_main(&asset)
|| elements_wtx_output_is_fee(psbt->tx, i)) || elements_psbt_output_is_fee(psbt, i))
continue; continue;
ok = amount_sat_sub(&fee, fee, amount_asset_to_sat(&asset)); ok = amount_sat_sub(&fee, fee, amount_asset_to_sat(&asset));
@@ -844,3 +825,93 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt)
return fee; return fee;
} }
bool wally_psbt_input_spends(const struct wally_psbt_input *input,
const struct bitcoin_outpoint *outpoint)
{
/* Useful, as tx_part can have some NULL inputs */
if (!input)
return false;
BUILD_ASSERT(sizeof(outpoint->txid) == sizeof(input->txhash));
if (input->index != outpoint->n)
return false;
if (memcmp(&outpoint->txid, input->txhash, sizeof(outpoint->txid)) != 0)
return false;
return true;
}
void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in,
struct bitcoin_outpoint *outpoint)
{
BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash));
memcpy(&outpoint->txid, in->txhash, sizeof(struct bitcoin_txid));
outpoint->n = in->index;
}
const u8 *wally_psbt_output_get_script(const tal_t *ctx,
const struct wally_psbt_output *output)
{
if (output->script == NULL) {
/* This can happen for coinbase transactions, pegin
* transactions, and elements fee outputs */
return NULL;
}
return tal_dup_arr(ctx, u8, output->script, output->script_len, 0);
}
/* FIXME(cdecker) Make the caller pass in a reference to amount_asset, and
* return false if unintelligible/encrypted. (WARN UNUSED). */
struct amount_asset
wally_psbt_output_get_amount(const struct wally_psbt_output *output)
{
struct amount_asset amount;
size_t asset_out;
if (chainparams->is_elements) {
if (wally_psbt_output_get_asset(output, amount.asset + 1, sizeof(amount.asset) - 1, &asset_out) != WALLY_OK) {
amount.value = 0;
return amount;
}
assert(asset_out == 32);
amount.asset[0] = 0x01; /* explicit */
/* We currently only support explicit value
* asset tags, others are confidential, so
* don't even try to assign a value to it. */
if (output->has_amount == true) {
amount.value = output->amount;
} else {
amount.value = 0;
}
} else {
/* Do not assign amount.asset, we should never touch it in
* non-elements scenarios. */
if (output->has_amount) {
amount.value = output->amount;
} else {
abort();
}
}
return amount;
}
bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum)
{
assert(outnum < psbt->num_outputs);
return chainparams->is_elements &&
psbt->outputs[outnum].script_len == 0;
}
bool psbt_set_version(struct wally_psbt *psbt, u32 version)
{
bool ok;
tal_wally_start();
ok = wally_psbt_set_version(psbt, 0, version) == WALLY_OK;
if (ok && version == 2) {
ok &= wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS) == WALLY_OK;
}
tal_wally_end(psbt);
return ok;
}

View File

@@ -29,7 +29,7 @@ struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_o
/* /*
* new_psbt - Create a PSBT, using the passed in tx * new_psbt - Create a PSBT, using the passed in tx
* as the global_tx * as the locktime/inputs/output psbt fields
* *
* @ctx - allocation context * @ctx - allocation context
* @wtx - global_tx starter kit * @wtx - global_tx starter kit
@@ -228,6 +228,33 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt);
bool psbt_has_input(const struct wally_psbt *psbt, bool psbt_has_input(const struct wally_psbt *psbt,
const struct bitcoin_outpoint *outpoint); const struct bitcoin_outpoint *outpoint);
/* wally_psbt_input_spends - Returns true if PSBT input spends given outpoint
*
* @input - psbt input
* @outpoint - outpoint
*/
bool wally_psbt_input_spends(const struct wally_psbt_input *input,
const struct bitcoin_outpoint *outpoint);
void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in,
struct bitcoin_outpoint *outpoint);
const u8 *wally_psbt_output_get_script(const tal_t *ctx,
const struct wally_psbt_output *output);
void wally_psbt_input_get_txid(const struct wally_psbt_input *in,
struct bitcoin_txid *txid);
struct amount_asset
wally_psbt_output_get_amount(const struct wally_psbt_output *output);
/* psbt_set_version - Returns false if there was any issue with the PSBT.
* Returns true if it was a well-formed PSET and treats it as a no-op
*/
bool psbt_set_version(struct wally_psbt *psbt, u32 version);
bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum);
struct wally_psbt *psbt_from_b64(const tal_t *ctx, struct wally_psbt *psbt_from_b64(const tal_t *ctx,
const char *b64, const char *b64,
size_t b64len); size_t b64len);

View File

@@ -72,9 +72,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN
/* Generated stub for pubkey_to_hash160 */ /* Generated stub for pubkey_to_hash160 */
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
{ fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); }
/* Generated stub for script_push_bytes */
void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "script_push_bytes called!\n"); abort(); }
/* Generated stub for scriptpubkey_p2wsh */ /* Generated stub for scriptpubkey_p2wsh */
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }

View File

@@ -53,9 +53,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN
/* Generated stub for pubkey_to_hash160 */ /* Generated stub for pubkey_to_hash160 */
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
{ fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); }
/* Generated stub for script_push_bytes */
void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "script_push_bytes called!\n"); abort(); }
/* Generated stub for scriptpubkey_p2wsh */ /* Generated stub for scriptpubkey_p2wsh */
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }
@@ -105,7 +102,8 @@ int main(int argc, char *argv[])
/* Witness/scriptsig data is saved down into psbt */ /* Witness/scriptsig data is saved down into psbt */
assert(tx2->psbt->num_inputs == 1); assert(tx2->psbt->num_inputs == 1);
assert(tx2->psbt->inputs[0].final_scriptsig_len > 0); const struct wally_map_item *final_scriptsig = wally_map_get_integer(&tx2->psbt->inputs[0].psbt_fields, /* PSBT_IN_FINAL_SCRIPTSIG */ 0x07);
assert(final_scriptsig->value_len > 0);
assert(tx2->psbt->inputs[0].final_witness != NULL); assert(tx2->psbt->inputs[0].final_witness != NULL);
common_shutdown(); common_shutdown();

View File

@@ -81,10 +81,6 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt UNNEEDED,
const u8 *input_wscript UNNEEDED, const u8 *input_wscript UNNEEDED,
const u8 *redeemscript UNNEEDED) const u8 *redeemscript UNNEEDED)
{ fprintf(stderr, "psbt_append_input called!\n"); abort(); } { fprintf(stderr, "psbt_append_input called!\n"); abort(); }
/* Generated stub for psbt_elements_input_set_asset */
void psbt_elements_input_set_asset(struct wally_psbt *psbt UNNEEDED, size_t in UNNEEDED,
struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "psbt_elements_input_set_asset called!\n"); abort(); }
/* Generated stub for psbt_final_tx */ /* Generated stub for psbt_final_tx */
struct wally_tx *psbt_final_tx(const tal_t *ctx UNNEEDED, const struct wally_psbt *psbt UNNEEDED) struct wally_tx *psbt_final_tx(const tal_t *ctx UNNEEDED, const struct wally_psbt *psbt UNNEEDED)
{ fprintf(stderr, "psbt_final_tx called!\n"); abort(); } { fprintf(stderr, "psbt_final_tx called!\n"); abort(); }

View File

@@ -73,9 +73,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN
/* Generated stub for pubkey_to_hash160 */ /* Generated stub for pubkey_to_hash160 */
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
{ fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); }
/* Generated stub for script_push_bytes */
void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "script_push_bytes called!\n"); abort(); }
/* Generated stub for scriptpubkey_p2wsh */ /* Generated stub for scriptpubkey_p2wsh */
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }

View File

@@ -180,7 +180,36 @@ static int elements_tx_add_fee_output(struct bitcoin_tx *tx)
void bitcoin_tx_set_locktime(struct bitcoin_tx *tx, u32 locktime) void bitcoin_tx_set_locktime(struct bitcoin_tx *tx, u32 locktime)
{ {
tx->wtx->locktime = locktime; tx->wtx->locktime = locktime;
tx->psbt->tx->locktime = locktime; tx->psbt->fallback_locktime = locktime;
tx->psbt->has_fallback_locktime = true;
}
/* FIXME Stolen from psbt_append_input; export? */
static struct wally_tx_input *wally_tx_input_from_outpoint_sequence(const struct bitcoin_outpoint *outpoint,
u32 sequence)
{
struct wally_tx_input *tx_in;
if (chainparams->is_elements) {
if (wally_tx_elements_input_init_alloc(outpoint->txid.shad.sha.u.u8,
sizeof(outpoint->txid.shad.sha.u.u8),
outpoint->n,
sequence, NULL, 0,
NULL,
NULL, 0,
NULL, 0, NULL, 0,
NULL, 0, NULL, 0,
NULL, 0, NULL,
&tx_in) != WALLY_OK)
abort();
} else {
if (wally_tx_input_init_alloc(outpoint->txid.shad.sha.u.u8,
sizeof(outpoint->txid.shad.sha.u.u8),
outpoint->n,
sequence, NULL, 0, NULL,
&tx_in) != WALLY_OK)
abort();
}
return tx_in;
} }
int bitcoin_tx_add_input(struct bitcoin_tx *tx, int bitcoin_tx_add_input(struct bitcoin_tx *tx,
@@ -191,6 +220,7 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx,
{ {
int wally_err; int wally_err;
int input_num = tx->wtx->num_inputs; int input_num = tx->wtx->num_inputs;
struct wally_tx_input *tx_input;
psbt_append_input(tx->psbt, outpoint, psbt_append_input(tx->psbt, outpoint,
sequence, scriptSig, sequence, scriptSig,
@@ -205,9 +235,11 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx,
scriptPubkey, amount); scriptPubkey, amount);
tal_wally_start(); tal_wally_start();
tx_input = wally_tx_input_from_outpoint_sequence(outpoint, sequence);
wally_err = wally_tx_add_input(tx->wtx, wally_err = wally_tx_add_input(tx->wtx,
&tx->psbt->tx->inputs[input_num]); tx_input);
assert(wally_err == WALLY_OK); assert(wally_err == WALLY_OK);
wally_tx_input_free(tx_input);
/* scriptsig isn't actually stored in psbt input, so add that now */ /* scriptsig isn't actually stored in psbt input, so add that now */
wally_tx_set_input_script(tx->wtx, input_num, wally_tx_set_input_script(tx->wtx, input_num,
@@ -215,12 +247,10 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx,
tal_wally_end(tx->wtx); tal_wally_end(tx->wtx);
if (is_elements(chainparams)) { if (is_elements(chainparams)) {
struct amount_asset asset;
/* FIXME: persist asset tags */ /* FIXME: persist asset tags */
asset = amount_sat_to_asset(&amount, amount_sat_to_asset(&amount,
chainparams->fee_asset_tag); chainparams->fee_asset_tag);
/* FIXME: persist nonces */ /* FIXME: persist nonces */
psbt_elements_input_set_asset(tx->psbt, input_num, &asset);
} }
return input_num; return input_num;
} }
@@ -258,10 +288,6 @@ void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum,
assert(ret == WALLY_OK); assert(ret == WALLY_OK);
} else { } else {
output->satoshi = satoshis; output->satoshi = satoshis;
/* update the global tx for the psbt also */
output = &tx->psbt->tx->outputs[outnum];
output->satoshi = satoshis;
} }
} }
@@ -291,14 +317,16 @@ u8 *bitcoin_tx_output_get_witscript(const tal_t *ctx, const struct bitcoin_tx *t
int outnum) int outnum)
{ {
struct wally_psbt_output *out; struct wally_psbt_output *out;
const struct wally_map_item *output_witness_script;
assert(outnum < tx->psbt->num_outputs); assert(outnum < tx->psbt->num_outputs);
out = &tx->psbt->outputs[outnum]; out = &tx->psbt->outputs[outnum];
if (out->witness_script_len == 0) output_witness_script = wally_map_get_integer(&out->psbt_fields, /* PSBT_OUT_WITNESS_SCRIPT */ 0x01);
if (output_witness_script->value_len == 0)
return NULL; return NULL;
return tal_dup_arr(ctx, u8, out->witness_script, out->witness_script_len, 0); return tal_dup_arr(ctx, u8, output_witness_script->value, output_witness_script->value_len, 0);
} }
struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx, struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
@@ -536,18 +564,21 @@ void bitcoin_tx_finalize(struct bitcoin_tx *tx)
struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psbt STEALS) struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psbt STEALS)
{ {
size_t locktime;
wally_psbt_get_locktime(psbt, &locktime);
struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams, struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams,
psbt->tx->num_inputs, psbt->num_inputs,
psbt->tx->num_outputs, psbt->num_outputs,
psbt->tx->locktime); locktime);
wally_tx_free(tx->wtx); wally_tx_free(tx->wtx);
psbt_finalize(psbt); psbt_finalize(psbt);
tx->wtx = psbt_final_tx(tx, psbt); tx->wtx = psbt_final_tx(tx, psbt);
if (!tx->wtx) { if (!tx->wtx) {
tal_wally_start(); tal_wally_start();
if (wally_tx_clone_alloc(psbt->tx, 0, &tx->wtx) != WALLY_OK) if (wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx->wtx) != WALLY_OK) {
tx->wtx = NULL; tx->wtx = NULL;
}
tal_wally_end_onto(tx, tx->wtx, struct wally_tx); tal_wally_end_onto(tx, tx->wtx, struct wally_tx);
if (!tx->wtx) if (!tx->wtx)
return tal_free(tx); return tal_free(tx);

View File

@@ -3,7 +3,6 @@
#include <wally_psbt.h> #include <wally_psbt.h>
static void swap_wally_outputs(struct wally_tx_output *outputs, static void swap_wally_outputs(struct wally_tx_output *outputs,
struct wally_tx_output *psbt_global_outs,
struct wally_psbt_output *psbt_outs, struct wally_psbt_output *psbt_outs,
const void **map, u32 *cltvs, const void **map, u32 *cltvs,
size_t i1, size_t i2) size_t i1, size_t i2)
@@ -18,12 +17,6 @@ static void swap_wally_outputs(struct wally_tx_output *outputs,
outputs[i1] = outputs[i2]; outputs[i1] = outputs[i2];
outputs[i2] = tmpoutput; outputs[i2] = tmpoutput;
/* For the PSBT, we swap the psbt outputs and
* the global tx's outputs */
tmpoutput = psbt_global_outs[i1];
psbt_global_outs[i1] = psbt_global_outs[i2];
psbt_global_outs[i2] = tmpoutput;
tmppsbtout = psbt_outs[i1]; tmppsbtout = psbt_outs[i1];
psbt_outs[i1] = psbt_outs[i2]; psbt_outs[i1] = psbt_outs[i2];
psbt_outs[i2] = tmppsbtout; psbt_outs[i2] = tmppsbtout;
@@ -106,7 +99,6 @@ void permute_outputs(struct bitcoin_tx *tx, u32 *cltvs, const void **map)
/* Swap best into first place. */ /* Swap best into first place. */
swap_wally_outputs(tx->wtx->outputs, swap_wally_outputs(tx->wtx->outputs,
tx->psbt->tx->outputs,
tx->psbt->outputs, tx->psbt->outputs,
map, cltvs, i, best_pos); map, cltvs, i, best_pos);
} }

View File

@@ -26,6 +26,7 @@ void psbt_finalize_input(const tal_t *ctx,
struct wally_psbt_input *in, struct wally_psbt_input *in,
const struct witness_element **elements) const struct witness_element **elements)
{ {
const struct wally_map_item *redeem_script;
psbt_input_set_final_witness_stack(ctx, in, elements); psbt_input_set_final_witness_stack(ctx, in, elements);
/* There's this horrible edgecase where we set the final_witnesses /* There's this horrible edgecase where we set the final_witnesses
@@ -35,18 +36,16 @@ void psbt_finalize_input(const tal_t *ctx,
* on these just .. ignores it!? Murder. Anyway, here we do a final * on these just .. ignores it!? Murder. Anyway, here we do a final
* scriptsig check -- if there's a redeemscript field still around we * scriptsig check -- if there's a redeemscript field still around we
* just go ahead and mush it into the final_scriptsig field. */ * just go ahead and mush it into the final_scriptsig field. */
if (in->redeem_script) { redeem_script = wally_map_get_integer(&in->psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
if (redeem_script) {
u8 *redeemscript = tal_dup_arr(NULL, u8, u8 *redeemscript = tal_dup_arr(NULL, u8,
in->redeem_script, redeem_script->value,
in->redeem_script_len, 0); redeem_script->value_len, 0);
in->final_scriptsig = u8 *final_scriptsig =
bitcoin_scriptsig_redeem(NULL, bitcoin_scriptsig_redeem(NULL,
take(redeemscript)); take(redeemscript));
in->final_scriptsig_len = wally_psbt_input_set_final_scriptsig(in, final_scriptsig, tal_bytelen(final_scriptsig));
tal_bytelen(in->final_scriptsig); wally_psbt_input_set_redeem_script(in, tal_arr(NULL, u8, 0), 0);
in->redeem_script = tal_free(in->redeem_script);
in->redeem_script_len = 0;
} }
} }

View File

@@ -14,7 +14,7 @@ void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *ma
u32 path[1]; u32 path[1];
path[0] = index; path[0] = index;
if (wally_map_add_keypath_item(map_in, if (wally_map_keypath_add(map_in,
ext->pub_key, sizeof(ext->pub_key), ext->pub_key, sizeof(ext->pub_key),
fingerprint, sizeof(fingerprint), fingerprint, sizeof(fingerprint),
path, 1) != WALLY_OK) path, 1) != WALLY_OK)

View File

@@ -58,17 +58,11 @@ static int compare_outputs_at(const struct output_set *a,
} }
static const u8 *linearize_input(const tal_t *ctx, static const u8 *linearize_input(const tal_t *ctx,
const struct wally_psbt_input *in, const struct wally_psbt_input *in)
const struct wally_tx_input *tx_in)
{ {
struct wally_psbt *psbt = create_psbt(NULL, 1, 0, 0); struct wally_psbt *psbt = create_psbt(NULL, 1, 0, 0);
size_t byte_len; size_t byte_len;
tal_wally_start();
if (wally_tx_add_input(psbt->tx, tx_in) != WALLY_OK)
abort();
tal_wally_end(psbt->tx);
psbt->inputs[0] = *in; psbt->inputs[0] = *in;
psbt->num_inputs++; psbt->num_inputs++;
@@ -77,11 +71,10 @@ static const u8 *linearize_input(const tal_t *ctx,
wally_map_sort(&psbt->inputs[0].unknowns, 0); wally_map_sort(&psbt->inputs[0].unknowns, 0);
/* signatures, keypaths, etc - we dont care if they change */ /* signatures, keypaths, etc - we dont care if they change */
psbt->inputs[0].final_witness = NULL; wally_psbt_input_set_final_witness(&psbt->inputs[0], NULL);
psbt->inputs[0].final_scriptsig_len = 0; wally_psbt_input_set_final_scriptsig(&psbt->inputs[0], NULL, 0);
psbt->inputs[0].witness_script = NULL; wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0);
psbt->inputs[0].witness_script_len = 0; wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0);
psbt->inputs[0].redeem_script_len = 0;
psbt->inputs[0].keypaths.num_items = 0; psbt->inputs[0].keypaths.num_items = 0;
psbt->inputs[0].signatures.num_items = 0; psbt->inputs[0].signatures.num_items = 0;
@@ -94,22 +87,16 @@ static const u8 *linearize_input(const tal_t *ctx,
} }
static const u8 *linearize_output(const tal_t *ctx, static const u8 *linearize_output(const tal_t *ctx,
const struct wally_psbt_output *out, const struct wally_psbt_output *out)
const struct wally_tx_output *tx_out)
{ {
struct wally_psbt *psbt = create_psbt(NULL, 1, 1, 0); struct wally_psbt *psbt = create_psbt(NULL, 1, 1, 0);
size_t byte_len; size_t byte_len;
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
/* Add a 'fake' input so this will linearize the tx */ /* Add a 'fake' non-zero input so libwally will agree to linearize the tx */
memset(&outpoint, 0, sizeof(outpoint)); memset(&outpoint, 1, sizeof(outpoint));
psbt_append_input(psbt, &outpoint, 0, NULL, NULL, NULL); psbt_append_input(psbt, &outpoint, 0, NULL, NULL, NULL);
tal_wally_start();
if (wally_tx_add_output(psbt->tx, tx_out) != WALLY_OK)
abort();
tal_wally_end(psbt->tx);
psbt->outputs[0] = *out; psbt->outputs[0] = *out;
psbt->num_outputs++; psbt->num_outputs++;
/* Sort the outputs, so serializing them is ok */ /* Sort the outputs, so serializing them is ok */
@@ -118,8 +105,8 @@ static const u8 *linearize_output(const tal_t *ctx,
/* We don't care if the keypaths change */ /* We don't care if the keypaths change */
psbt->outputs[0].keypaths.num_items = 0; psbt->outputs[0].keypaths.num_items = 0;
/* And you can add scripts, no problem */ /* And you can add scripts, no problem */
psbt->outputs[0].witness_script_len = 0; wally_psbt_output_set_witness_script(&psbt->outputs[0], NULL, 0);
psbt->outputs[0].redeem_script_len = 0; wally_psbt_output_set_redeem_script(&psbt->outputs[0], NULL, 0);
const u8 *bytes = psbt_get_bytes(ctx, psbt, &byte_len); const u8 *bytes = psbt_get_bytes(ctx, psbt, &byte_len);
@@ -135,11 +122,9 @@ static bool input_identical(const struct wally_psbt *a,
size_t b_index) size_t b_index)
{ {
const u8 *a_in = linearize_input(tmpctx, const u8 *a_in = linearize_input(tmpctx,
&a->inputs[a_index], &a->inputs[a_index]);
&a->tx->inputs[a_index]);
const u8 *b_in = linearize_input(tmpctx, const u8 *b_in = linearize_input(tmpctx,
&b->inputs[b_index], &b->inputs[b_index]);
&b->tx->inputs[b_index]);
return memeq(a_in, tal_bytelen(a_in), return memeq(a_in, tal_bytelen(a_in),
b_in, tal_bytelen(b_in)); b_in, tal_bytelen(b_in));
@@ -151,11 +136,9 @@ static bool output_identical(const struct wally_psbt *a,
size_t b_index) size_t b_index)
{ {
const u8 *a_out = linearize_output(tmpctx, const u8 *a_out = linearize_output(tmpctx,
&a->outputs[a_index], &a->outputs[a_index]);
&a->tx->outputs[a_index]);
const u8 *b_out = linearize_output(tmpctx, const u8 *b_out = linearize_output(tmpctx,
&b->outputs[b_index], &b->outputs[b_index]);
&b->tx->outputs[b_index]);
return memeq(a_out, tal_bytelen(a_out), return memeq(a_out, tal_bytelen(a_out),
b_out, tal_bytelen(b_out)); b_out, tal_bytelen(b_out));
} }
@@ -168,7 +151,6 @@ static void sort_inputs(struct wally_psbt *psbt)
psbt->num_inputs); psbt->num_inputs);
for (size_t i = 0; i < tal_count(set); i++) { for (size_t i = 0; i < tal_count(set); i++) {
set[i].tx_input = psbt->tx->inputs[i];
set[i].input = psbt->inputs[i]; set[i].input = psbt->inputs[i];
} }
@@ -178,7 +160,6 @@ static void sort_inputs(struct wally_psbt *psbt)
/* Put PSBT parts into place */ /* Put PSBT parts into place */
for (size_t i = 0; i < tal_count(set); i++) { for (size_t i = 0; i < tal_count(set); i++) {
psbt->inputs[i] = set[i].input; psbt->inputs[i] = set[i].input;
psbt->tx->inputs[i] = set[i].tx_input;
} }
tal_free(set); tal_free(set);
@@ -191,7 +172,6 @@ static void sort_outputs(struct wally_psbt *psbt)
struct output_set, struct output_set,
psbt->num_outputs); psbt->num_outputs);
for (size_t i = 0; i < tal_count(set); i++) { for (size_t i = 0; i < tal_count(set); i++) {
set[i].tx_output = psbt->tx->outputs[i];
set[i].output = psbt->outputs[i]; set[i].output = psbt->outputs[i];
} }
@@ -201,7 +181,6 @@ static void sort_outputs(struct wally_psbt *psbt)
/* Put PSBT parts into place */ /* Put PSBT parts into place */
for (size_t i = 0; i < tal_count(set); i++) { for (size_t i = 0; i < tal_count(set); i++) {
psbt->outputs[i] = set[i].output; psbt->outputs[i] = set[i].output;
psbt->tx->outputs[i] = set[i].tx_output;
} }
tal_free(set); tal_free(set);
@@ -217,7 +196,6 @@ void psbt_sort_by_serial_id(struct wally_psbt *psbt)
do { \ do { \
struct type##_set a; \ struct type##_set a; \
a.type = from->type##s[index]; \ a.type = from->type##s[index]; \
a.tx_##type = from->tx->type##s[index]; \
a.idx = index; \ a.idx = index; \
tal_arr_expand(&add_to, a); \ tal_arr_expand(&add_to, a); \
} while (0) } while (0)
@@ -398,6 +376,7 @@ bool psbt_has_required_fields(struct wally_psbt *psbt)
{ {
u64 serial_id; u64 serial_id;
for (size_t i = 0; i < psbt->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
const struct wally_map_item *redeem_script;
struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_psbt_input *input = &psbt->inputs[i];
if (!psbt_get_serial_id(&input->unknowns, &serial_id)) if (!psbt_get_serial_id(&input->unknowns, &serial_id))
@@ -408,13 +387,13 @@ bool psbt_has_required_fields(struct wally_psbt *psbt)
return false; return false;
/* If is P2SH, redeemscript must be present */ /* If is P2SH, redeemscript must be present */
assert(psbt->tx->inputs[i].index < input->utxo->num_outputs); assert(psbt->inputs[i].index < input->utxo->num_outputs);
const u8 *outscript = const u8 *outscript =
wally_tx_output_get_script(tmpctx, wally_tx_output_get_script(tmpctx,
&input->utxo->outputs[psbt->tx->inputs[i].index]); &input->utxo->outputs[psbt->inputs[i].index]);
if (is_p2sh(outscript, NULL) && input->redeem_script_len == 0) redeem_script = wally_map_get_integer(&psbt->inputs[i].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
if (is_p2sh(outscript, NULL) && (!redeem_script || redeem_script->value_len == 0))
return false; return false;
} }
for (size_t i = 0; i < psbt->num_outputs; i++) { for (size_t i = 0; i < psbt->num_outputs; i++) {
@@ -511,6 +490,8 @@ bool psbt_output_to_external(const struct wally_psbt_output *output)
bool psbt_contribs_changed(struct wally_psbt *orig, bool psbt_contribs_changed(struct wally_psbt *orig,
struct wally_psbt *new) struct wally_psbt *new)
{ {
assert(orig->version == 2 && new->version == 2);
struct psbt_changeset *cs; struct psbt_changeset *cs;
bool ok; bool ok;
cs = psbt_get_changeset(NULL, orig, new); cs = psbt_get_changeset(NULL, orig, new);

View File

@@ -15,14 +15,12 @@ struct wally_psbt_output;
struct wally_map; struct wally_map;
struct input_set { struct input_set {
struct wally_tx_input tx_input;
struct wally_psbt_input input; struct wally_psbt_input input;
/* index on PSBT of this input */ /* index on PSBT of this input */
size_t idx; size_t idx;
}; };
struct output_set { struct output_set {
struct wally_tx_output tx_output;
struct wally_psbt_output output; struct wally_psbt_output output;
/* index on PSBT of this output */ /* index on PSBT of this output */
size_t idx; size_t idx;

File diff suppressed because one or more lines are too long

View File

@@ -466,7 +466,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt)
struct privkey privkey; struct privkey privkey;
struct pubkey pubkey; struct pubkey pubkey;
if (!wally_tx_input_spends(&psbt->tx->inputs[j], if (!wally_psbt_input_spends(&psbt->inputs[j],
&utxo->outpoint)) &utxo->outpoint))
continue; continue;

View File

@@ -2180,11 +2180,11 @@ static void handle_validate_rbf(struct subd *dualopend,
list_for_each(&channel->inflights, inflight, list) { list_for_each(&channel->inflights, inflight, list) {
/* Remove every non-matching input from set */ /* Remove every non-matching input from set */
for (size_t i = 0; i < candidate_psbt->num_inputs; i++) { for (size_t i = 0; i < candidate_psbt->num_inputs; i++) {
struct wally_tx_input *input = const struct wally_psbt_input *input =
&candidate_psbt->tx->inputs[i]; &candidate_psbt->inputs[i];
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
wally_tx_input_get_outpoint(input, &outpoint); wally_psbt_input_get_outpoint(input, &outpoint);
if (!psbt_has_input(inflight->funding_psbt, if (!psbt_has_input(inflight->funding_psbt,
&outpoint)) &outpoint))
@@ -2793,6 +2793,11 @@ static struct command_result *json_openchannel_init(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
/* We only deal in v2 */
if (!psbt_set_version(psbt, 2)) {
return command_fail(cmd, LIGHTNINGD, "Could not set PSBT version.");
}
/* Gotta expect some rates ! */ /* Gotta expect some rates ! */
if (!amount_sat_zero(*request_amt) && !rates) if (!amount_sat_zero(*request_amt) && !rates)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, return command_fail(cmd, JSONRPC2_INVALID_PARAMS,

View File

@@ -1009,10 +1009,15 @@ static struct command_result *json_fundchannel_complete(struct command *cmd,
fc = peer->uncommitted_channel->fc; fc = peer->uncommitted_channel->fc;
/* We only deal with V2 internally */
if (!psbt_set_version(funding_psbt, 2)) {
return command_fail(cmd, LIGHTNINGD, "Could not set PSBT version.");
}
/* Figure out the correct output, and perform sanity checks. */ /* Figure out the correct output, and perform sanity checks. */
for (size_t i = 0; i < funding_psbt->tx->num_outputs; i++) { for (size_t i = 0; i < funding_psbt->num_outputs; i++) {
if (memeq(funding_psbt->tx->outputs[i].script, if (memeq(funding_psbt->outputs[i].script,
funding_psbt->tx->outputs[i].script_len, funding_psbt->outputs[i].script_len,
fc->funding_scriptpubkey, fc->funding_scriptpubkey,
tal_bytelen(fc->funding_scriptpubkey))) { tal_bytelen(fc->funding_scriptpubkey))) {
if (funding_txout_num) if (funding_txout_num)
@@ -1028,14 +1033,14 @@ static struct command_result *json_fundchannel_complete(struct command *cmd,
/* Can't really check amounts for elements. */ /* Can't really check amounts for elements. */
if (!chainparams->is_elements if (!chainparams->is_elements
&& !amount_sat_eq(amount_sat(funding_psbt->tx->outputs && !amount_sat_eq(amount_sat(funding_psbt->outputs
[*funding_txout_num].satoshi), [*funding_txout_num].amount),
fc->funding_sats)) fc->funding_sats))
return command_fail(cmd, FUNDING_PSBT_INVALID, return command_fail(cmd, FUNDING_PSBT_INVALID,
"Output to open channel is %"PRIu64"sat," "Output to open channel is %"PRIu64"sat,"
" should be %s", " should be %s",
funding_psbt->tx->outputs funding_psbt->outputs
[*funding_txout_num].satoshi, [*funding_txout_num].amount,
type_to_string(tmpctx, struct amount_sat, type_to_string(tmpctx, struct amount_sat,
&fc->funding_sats)); &fc->funding_sats));

View File

@@ -1891,6 +1891,8 @@ void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel)
void channel_watch_funding(struct lightningd *ld, struct channel *channel) void channel_watch_funding(struct lightningd *ld, struct channel *channel)
{ {
/* FIXME: Remove arg from cb? */ /* FIXME: Remove arg from cb? */
log_debug(channel->log, "Watching for funding txid: %s",
type_to_string(tmpctx, struct bitcoin_txid, &channel->funding.txid));
watch_txid(channel, ld->topology, channel, watch_txid(channel, ld->topology, channel,
&channel->funding.txid, funding_depth_cb); &channel->funding.txid, funding_depth_cb);
watch_txo(channel, ld->topology, channel, watch_txo(channel, ld->topology, channel,

View File

@@ -250,8 +250,8 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx,
in->input.utxo); in->input.utxo);
msg = towire_tx_add_input(ctx, cid, serial_id, msg = towire_tx_add_input(ctx, cid, serial_id,
prevtx, in->tx_input.index, prevtx, in->input.index,
in->tx_input.sequence); in->input.sequence);
tal_arr_remove(&set->added_ins, 0); tal_arr_remove(&set->added_ins, 0);
return msg; return msg;
@@ -274,10 +274,11 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx,
if (!psbt_get_serial_id(&out->output.unknowns, &serial_id)) if (!psbt_get_serial_id(&out->output.unknowns, &serial_id))
abort(); abort();
asset_amt = wally_tx_output_get_amount(&out->tx_output); asset_amt = wally_psbt_output_get_amount(&out->output);
sats = amount_asset_to_sat(&asset_amt); sats = amount_asset_to_sat(&asset_amt);
const u8 *script = wally_tx_output_get_script(ctx, const u8 *script = wally_psbt_output_get_script(ctx,
&out->tx_output); &out->output);
msg = towire_tx_add_output(ctx, cid, serial_id, msg = towire_tx_add_output(ctx, cid, serial_id,
sats.satoshis, /* Raw: wire interface */ sats.satoshis, /* Raw: wire interface */
@@ -596,12 +597,20 @@ static size_t psbt_input_weight(struct wally_psbt *psbt,
size_t in) size_t in)
{ {
size_t weight; size_t weight;
const struct wally_map_item *redeem_script;
redeem_script = wally_map_get_integer(&psbt->inputs[in].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
/* txid + txout + sequence */ /* txid + txout + sequence */
weight = (32 + 4 + 4) * 4; weight = (32 + 4 + 4) * 4;
weight += if (redeem_script) {
(psbt->inputs[in].redeem_script_len + weight +=
(varint_t) varint_size(psbt->inputs[in].redeem_script_len)) * 4; (redeem_script->value_len +
(varint_t) varint_size(redeem_script->value_len)) * 4;
} else {
/* zero scriptSig length */
weight += (varint_t) varint_size(0) * 4;
}
return weight; return weight;
} }
@@ -609,15 +618,15 @@ static size_t psbt_input_weight(struct wally_psbt *psbt,
static size_t psbt_output_weight(struct wally_psbt *psbt, static size_t psbt_output_weight(struct wally_psbt *psbt,
size_t outnum) size_t outnum)
{ {
return (8 + psbt->tx->outputs[outnum].script_len + return (8 + psbt->outputs[outnum].script_len +
varint_size(psbt->tx->outputs[outnum].script_len)) * 4; varint_size(psbt->outputs[outnum].script_len)) * 4;
} }
static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u32 *funding_txout) static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u32 *funding_txout)
{ {
for (size_t i = 0; i < psbt->num_outputs; i++) { for (size_t i = 0; i < psbt->num_outputs; i++) {
if (memeq(wscript, tal_bytelen(wscript), psbt->tx->outputs[i].script, if (memeq(wscript, tal_bytelen(wscript), psbt->outputs[i].script,
psbt->tx->outputs[i].script_len)) { psbt->outputs[i].script_len)) {
*funding_txout = i; *funding_txout = i;
return true; return true;
} }
@@ -2382,9 +2391,17 @@ static void accepter_start(struct state *state, const u8 *oc2_msg)
if (!tx_state->psbt) if (!tx_state->psbt)
tx_state->psbt = create_psbt(tx_state, 0, 0, tx_state->psbt = create_psbt(tx_state, 0, 0,
tx_state->tx_locktime); tx_state->tx_locktime);
else else {
/* Locktimes must match! */ /* Locktimes must match! */
tx_state->psbt->tx->locktime = tx_state->tx_locktime; tx_state->psbt->fallback_locktime = tx_state->tx_locktime;
if (!psbt_set_version(tx_state->psbt, 2)) {
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not set PSBT version: %s",
type_to_string(tmpctx,
struct wally_psbt,
tx_state->psbt));
}
}
/* BOLT- #2: /* BOLT- #2:
* *
@@ -2914,6 +2931,7 @@ static void opener_start(struct state *state, u8 *msg)
struct lease_rates *expected_rates; struct lease_rates *expected_rates;
struct tx_state *tx_state = state->tx_state; struct tx_state *tx_state = state->tx_state;
struct amount_sat *requested_lease; struct amount_sat *requested_lease;
size_t locktime;
if (!fromwire_dualopend_opener_init(state, msg, if (!fromwire_dualopend_opener_init(state, msg,
&tx_state->psbt, &tx_state->psbt,
@@ -2930,8 +2948,8 @@ static void opener_start(struct state *state, u8 *msg)
master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg);
state->our_role = TX_INITIATOR; state->our_role = TX_INITIATOR;
tx_state->tx_locktime = tx_state->psbt->tx->locktime; wally_psbt_get_locktime(tx_state->psbt, &locktime);
tx_state->tx_locktime = locktime;
open_tlv = tlv_opening_tlvs_new(tmpctx); open_tlv = tlv_opening_tlvs_new(tmpctx);
/* BOLT #2: /* BOLT #2:
@@ -3456,6 +3474,7 @@ static void rbf_local_start(struct state *state, u8 *msg)
/* tmpctx gets cleaned midway, so we have a context for this fn */ /* tmpctx gets cleaned midway, so we have a context for this fn */
char *rbf_ctx = notleak_with_children(tal(state, char)); char *rbf_ctx = notleak_with_children(tal(state, char));
size_t locktime;
/* We need a new tx_state! */ /* We need a new tx_state! */
tx_state = new_tx_state(rbf_ctx); tx_state = new_tx_state(rbf_ctx);
@@ -3490,8 +3509,8 @@ static void rbf_local_start(struct state *state, u8 *msg)
return; return;
} }
tx_state->tx_locktime = tx_state->psbt->tx->locktime; wally_psbt_get_locktime(tx_state->psbt, &locktime);
tx_state->tx_locktime = locktime;
/* For now, we always just echo/send the funding amount */ /* For now, we always just echo/send the funding amount */
init_rbf_tlvs->funding_output_contribution init_rbf_tlvs->funding_output_contribution
= tal(init_rbf_tlvs, u64); = tal(init_rbf_tlvs, u64);

View File

@@ -5,6 +5,7 @@
*/ */
#include "config.h" #include "config.h"
#include <bitcoin/feerate.h> #include <bitcoin/feerate.h>
#include <bitcoin/psbt.h>
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <ccan/json_out/json_out.h> #include <ccan/json_out/json_out.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
@@ -212,14 +213,14 @@ remember_channel_utxos(struct command *cmd,
signed_psbt); signed_psbt);
utxos_bin = tal_arr(cmd, u8, 0); utxos_bin = tal_arr(cmd, u8, 0);
for (size_t i = 0; i < signed_psbt->tx->num_inputs; i++) { for (size_t i = 0; i < signed_psbt->num_inputs; i++) {
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
/* Don't save peer's UTXOS */ /* Don't save peer's UTXOS */
if (!psbt_input_is_ours(&signed_psbt->inputs[i])) if (!psbt_input_is_ours(&signed_psbt->inputs[i]))
continue; continue;
wally_tx_input_get_outpoint(&signed_psbt->tx->inputs[i], wally_psbt_input_get_outpoint(&signed_psbt->inputs[i],
&outpoint); &outpoint);
towire_bitcoin_outpoint(&utxos_bin, &outpoint); towire_bitcoin_outpoint(&utxos_bin, &outpoint);
} }

View File

@@ -572,6 +572,14 @@ after_signpsbt(struct command *cmd,
json_tok_full_len(field), json_tok_full_len(field),
json_tok_full(buf, field)); json_tok_full(buf, field));
if (!psbt_set_version(psbt, 2)) {
/* It should be well-formed? */
plugin_err(mfc->cmd->plugin,
"mfc: could not set PSBT version: %s",
type_to_string(tmpctx, struct wally_psbt,
mfc->psbt));
}
if (!psbt_finalize(psbt)) if (!psbt_finalize(psbt))
plugin_err(mfc->cmd->plugin, plugin_err(mfc->cmd->plugin,
"mfc %"PRIu64": Signed PSBT won't finalize" "mfc %"PRIu64": Signed PSBT won't finalize"
@@ -831,11 +839,21 @@ perform_funding_tx_finalize(struct multifundchannel_command *mfc)
size_t v1_dest_count = dest_count(mfc, FUND_CHANNEL); size_t v1_dest_count = dest_count(mfc, FUND_CHANNEL);
size_t v2_dest_count = dest_count(mfc, OPEN_CHANNEL); size_t v2_dest_count = dest_count(mfc, OPEN_CHANNEL);
size_t i, deck_i; size_t i, deck_i;
u32 psbt_version = mfc->psbt->version;
plugin_log(mfc->cmd->plugin, LOG_DBG, plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64": Creating funding tx.", "mfc %"PRIu64": Creating funding tx.",
mfc->id); mfc->id);
/* We operate over PSBTv2 only */
if (!psbt_set_version(mfc->psbt, 2)) {
/* It should be well-formed? */
plugin_err(mfc->cmd->plugin,
"mfc: could not set PSBT version: %s",
type_to_string(tmpctx, struct wally_psbt,
mfc->psbt));
}
/* Construct a deck of destinations. */ /* Construct a deck of destinations. */
deck = tal_arr(tmpctx, struct multifundchannel_destination *, deck = tal_arr(tmpctx, struct multifundchannel_destination *,
v1_dest_count + mfc->change_needed); v1_dest_count + mfc->change_needed);
@@ -929,6 +947,14 @@ perform_funding_tx_finalize(struct multifundchannel_command *mfc)
mfc->txid), mfc->txid),
content); content);
if (!psbt_set_version(mfc->psbt, psbt_version)) {
/* It should be well-formed? */
plugin_err(mfc->cmd->plugin,
"mfc: could not set PSBT version: %s",
type_to_string(tmpctx, struct wally_psbt,
mfc->psbt));
}
/* Now we can feed the TXID and outnums to the peer. */ /* Now we can feed the TXID and outnums to the peer. */
return perform_fundchannel_complete(mfc); return perform_fundchannel_complete(mfc);
} }
@@ -1343,6 +1369,9 @@ after_fundpsbt(struct command *cmd,
if (!mfc->psbt) if (!mfc->psbt)
goto fail; goto fail;
if (!psbt_set_version(mfc->psbt, 2))
goto fail;
field = json_get_member(buf, result, "feerate_per_kw"); field = json_get_member(buf, result, "feerate_per_kw");
if (!field || !json_to_u32(buf, field, &mfc->feerate_per_kw)) if (!field || !json_to_u32(buf, field, &mfc->feerate_per_kw))
goto fail; goto fail;

View File

@@ -421,6 +421,8 @@ mw_after_fundpsbt(struct command *cmd,
field->end - field->start) : NULL; field->end - field->start) : NULL;
ok = ok && mw->psbt; ok = ok && mw->psbt;
ok = ok && psbt_set_version(mw->psbt, 2);
field = ok ? json_get_member(buf, result, "feerate_per_kw") : NULL; field = ok ? json_get_member(buf, result, "feerate_per_kw") : NULL;
ok = ok && field; ok = ok && field;
ok = ok && json_to_number(buf, field, &feerate_per_kw); ok = ok && json_to_number(buf, field, &feerate_per_kw);

View File

@@ -112,9 +112,16 @@ static bool update_parent_psbt(const tal_t *ctx,
if (s_idx != -1) if (s_idx != -1)
goto fail; goto fail;
psbt_add_input(clone, const struct wally_psbt_input *input = &changes->added_ins[i].input;
&changes->added_ins[i].tx_input, struct bitcoin_outpoint outpoint;
idx); wally_psbt_input_get_outpoint(input, &outpoint);
psbt_append_input(clone,
&outpoint,
input->sequence,
NULL /* scriptSig */,
NULL /* input_wscript */,
NULL /* redeemscript */);
/* Move the input over */ /* Move the input over */
clone->inputs[idx] = *in; clone->inputs[idx] = *in;
@@ -172,9 +179,9 @@ static bool update_parent_psbt(const tal_t *ctx,
if (s_idx != -1) if (s_idx != -1)
goto fail; goto fail;
psbt_add_output(clone, const struct wally_psbt_output *output = &changes->added_outs[i].output;
&changes->added_outs[i].tx_output, psbt_append_output(clone, output->script, amount_sat(output->amount));
idx);
/* Move output over */ /* Move output over */
clone->outputs[idx] = *out; clone->outputs[idx] = *out;
@@ -638,8 +645,8 @@ funding_transaction_established(struct multifundchannel_command *mfc)
for (size_t j = 0; j < mfc->psbt->num_outputs; j++) { for (size_t j = 0; j < mfc->psbt->num_outputs; j++) {
if (memeq(dest->funding_script, if (memeq(dest->funding_script,
tal_bytelen(dest->funding_script), tal_bytelen(dest->funding_script),
mfc->psbt->tx->outputs[j].script, mfc->psbt->outputs[j].script,
mfc->psbt->tx->outputs[j].script_len)) mfc->psbt->outputs[j].script_len))
dest->outnum = j; dest->outnum = j;
} }
if (dest->outnum == mfc->psbt->num_outputs) if (dest->outnum == mfc->psbt->num_outputs)

View File

@@ -216,7 +216,7 @@ static struct command_result *finish_txprepare(struct command *cmd,
utx = tal(NULL, struct unreleased_tx); utx = tal(NULL, struct unreleased_tx);
utx->is_upgrade = txp->is_upgrade; utx->is_upgrade = txp->is_upgrade;
utx->psbt = tal_steal(utx, txp->psbt); utx->psbt = tal_steal(utx, txp->psbt);
psbt_txid(utx, txp->psbt, &utx->txid, &utx->tx); psbt_txid(utx, utx->psbt, &utx->txid, &utx->tx);
/* If this is a withdraw, we sign and send immediately. */ /* If this is a withdraw, we sign and send immediately. */
if (txp->is_withdraw) { if (txp->is_withdraw) {
@@ -301,6 +301,11 @@ static struct command_result *psbt_created(struct command *cmd,
psbttok->end - psbttok->start, psbttok->end - psbttok->start,
buf + psbttok->start); buf + psbttok->start);
if (!psbt_set_version(txp->psbt, 2)) {
return command_fail(cmd, LIGHTNINGD,
"Unable to convert PSBT to version 2.");
}
if (!json_to_number(buf, json_get_member(buf, result, "feerate_per_kw"), if (!json_to_number(buf, json_get_member(buf, result, "feerate_per_kw"),
&txp->feerate)) &txp->feerate))
return command_fail(cmd, LIGHTNINGD, return command_fail(cmd, LIGHTNINGD,

View File

@@ -1,8 +1,7 @@
from decimal import Decimal
from fixtures import * # noqa: F401,F403 from fixtures import * # noqa: F401,F403
from fixtures import TEST_NETWORK from fixtures import TEST_NETWORK
from pyln.client import RpcError from pyln.client import RpcError
from utils import wait_for, sync_blockheight, COMPAT, VALGRIND, DEVELOPER, TIMEOUT, only_one, scid_to_int from utils import wait_for, sync_blockheight, COMPAT, VALGRIND, DEVELOPER, TIMEOUT, scid_to_int
import base64 import base64
import os import os
@@ -171,21 +170,16 @@ def test_scid_upgrade(node_factory, bitcoind):
def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind):
bitcoind.generate_block(12) bitcoind.generate_block(12)
prior_txs = ['02000000019CCCA2E59D863B00B5BD835BF7BA93CC257932D2C7CDBE51EFE2EE4A9D29DFCB01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620', '020000000122F9EBE38F54208545B681AD7F73A7AE3504A09C8201F502673D34E28424687C01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620'] # FIXME: Re-add dynamic checks once PSBTv2 support is in both Core/Elements, or get python support
# These PSBTs were manually checked for 0.001 BTC multisig witness utxos in a single input
upgraded_psbts = ['cHNidP8BAgQCAAAAAQMEmj7WIAEEAQEBBQECAQYBAwH7BAIAAAAAAQEroIYBAAAAAAAiACBbjNO5FM9nzdj6YnPJMDU902R2c0+9liECwt9TuQiAzSICAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XRjBDAiBgFZ+8xOkvxfBoC9QdAhBuX6zhpvKsqWw8QeN2gK1b4wIfQdSIq+vNMfnFZqLyv3Un4s7i2MzHUiTs2morB/t/SwEBAwQBAAAAAQVHUiECMkJm3oQDs6sVegnx94TVh69hgxyZjBUbzCG7dMKyMUshAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XUq4iBgIyQmbehAOzqxV6CfH3hNWHr2GDHJmMFRvMIbt0wrIxSwhK0xNpAAAAACIGAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XCBq8wdAAAAAAAQ4gnMyi5Z2GOwC1vYNb97qTzCV5MtLHzb5R7+LuSp0p38sBDwQBAAAAARAEnbDigAABAwhKAQAAAAAAAAEEIgAgvnk1p3ypq3CkuLGQaCVjd2f+08AIJKqQyYiYNYfWhIgAAQMI8IIBAAAAAAABBCIAIJ9GhN2yis3HOVm8GU0aJd+Qb2HtAw9S0WPm8eJH0yy7AA==', 'cHNidP8BAgQCAAAAAQMEmj7WIAEEAQEBBQECAQYBAwH7BAIAAAAAAQEroIYBAAAAAAAiACBbjNO5FM9nzdj6YnPJMDU902R2c0+9liECwt9TuQiAzSICAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XRzBEAiBWXvsSYMpD69abqr7X9XurE6B6GkhyI5JeGuKYByBukAIgUmk9q/g3PIS9HjTVJ4OmRoSZAMKLFdsowq15Sl9OAD8BAQMEAQAAAAEFR1IhAjJCZt6EA7OrFXoJ8feE1YevYYMcmYwVG8whu3TCsjFLIQLjvTgAmGbJ2o7EqpnMTqnGwN1G3xXGHvDOHycSkXFOV1KuIgYCMkJm3oQDs6sVegnx94TVh69hgxyZjBUbzCG7dMKyMUsIStMTaQAAAAAiBgLjvTgAmGbJ2o7EqpnMTqnGwN1G3xXGHvDOHycSkXFOVwgavMHQAAAAAAEOICL56+OPVCCFRbaBrX9zp641BKCcggH1Amc9NOKEJGh8AQ8EAQAAAAEQBJ2w4oAAAQMISgEAAAAAAAABBCIAIL55Nad8qatwpLixkGglY3dn/tPACCSqkMmImDWH1oSIAAEDCPCCAQAAAAAAAQQiACCfRoTdsorNxzlZvBlNGiXfkG9h7QMPUtFj5vHiR9MsuwA=']
l1 = node_factory.get_node(dbfile='upgrade_inflight.sqlite3.xz', l1 = node_factory.get_node(dbfile='upgrade_inflight.sqlite3.xz',
options={'database-upgrade': True}) options={'database-upgrade': True})
b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channel_funding_inflights ORDER BY channel_id, funding_feerate;')] b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channel_funding_inflights ORDER BY channel_id, funding_feerate;')]
for i in range(len(b64_last_txs)): for i in range(len(b64_last_txs)):
bpsbt = b64_last_txs[i] assert b64_last_txs[i] == upgraded_psbts[i]
psbt = bitcoind.rpc.decodepsbt(bpsbt)
tx = prior_txs[i]
assert psbt['tx']['txid'] == bitcoind.rpc.decoderawtransaction(tx)['txid']
funding_input = only_one(psbt['inputs'])
assert funding_input['witness_utxo']['amount'] == Decimal('0.001')
assert funding_input['witness_utxo']['scriptPubKey']['type'] == 'witness_v0_scripthash'
assert funding_input['witness_script']['type'] == 'multisig'
@unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db")
@@ -194,22 +188,16 @@ def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind):
def test_last_tx_psbt_upgrade(node_factory, bitcoind): def test_last_tx_psbt_upgrade(node_factory, bitcoind):
bitcoind.generate_block(12) bitcoind.generate_block(12)
prior_txs = ['02000000018DD699861B00061E50937A233DB584BF8ED4C0BF50B44C0411F71B031A06455000000000000EF7A9800350C300000000000022002073356CFF7E1588F14935EF138E142ABEFB5F7E3D51DE942758DCD5A179449B6250A90600000000002200202DF545EA882889846C52FC5E111AC07CE07E0C09418AC15743A6F6284C2A4FA720A1070000000000160014E89954FAC8F7A2DCE51E095D7BEB5271C3F7DA56EF81DC20', '02000000018A0AE4C63BCDF9D78B07EB4501BB23404FDDBC73973C592793F047BE1495074B010000000074D99980010A2D0F00000000002200203B8CB644781CBECA96BE8B2BF1827AFD908B3CFB5569AC74DAB9395E8DDA39E4C9555420', '020000000135DAB2996E57762E3EC158C0D57D39F43CA657E882D93FC24F5FEBAA8F36ED9A0100000000566D1D800350C30000000000002200205679A7D06E1BD276AA25F56E9E4DF7E07D9837EFB0C5F63604F10CD9F766A03ED4DD0600000000001600147E5B5C8F4FC1A9484E259F92CA4CBB7FA2814EA49A6C070000000000220020AB6226DEBFFEFF4A741C01367FA3C875172483CFB3E327D0F8C7AA4C51EDECAA27AA4720'] # FIXME: Re-add dynamic checks once PSBTv2 support is in both Core/Elements, or get python support
# These PSBTs were manually checked for 0.01 BTC multisig witness utxos in a single input
upgraded_psbts = ['cHNidP8BAgQCAAAAAQME74HcIAEEAQEBBQEDAQYBAwH7BAIAAAAAAQErQEIPAAAAAAAiACCiWhNhgwfpKsHIgLqGzpSdj8cCpITLFVpVRddsOobajiICAjJCZt6EA7OrFXoJ8feE1YevYYMcmYwVG8whu3TCsjFLRzBEAiBhqTjjdJx2TqTNUwYJgmjhH6p8FJnbnj/N/Jv0dEiQmwIgXG/ki8U0iN0YPbrhpl7goGhXUj/8+JRg0uKLJrkHLrsBAQMEAQAAAAEFR1IhAgZUBJOphZmWemHEUXLfSWgeOYpssIkKUG5092wtK+JCIQIyQmbehAOzqxV6CfH3hNWHr2GDHJmMFRvMIbt0wrIxS1KuIgYCBlQEk6mFmZZ6YcRRct9JaB45imywiQpQbnT3bC0r4kIIWA8TsgAAAAAiBgIyQmbehAOzqxV6CfH3hNWHr2GDHJmMFRvMIbt0wrIxSwhK0xNpAAAAAAEOII3WmYYbAAYeUJN6Iz21hL+O1MC/ULRMBBH3GwMaBkVQAQ8EAAAAAAEQBA73qYAAAQMIUMMAAAAAAAABBCIAIHM1bP9+FYjxSTXvE44UKr77X349Ud6UJ1jc1aF5RJtiAAEDCFCpBgAAAAAAAQQiACAt9UXqiCiJhGxS/F4RGsB84H4MCUGKwVdDpvYoTCpPpwABAwggoQcAAAAAAAEEFgAU6JlU+sj3otzlHglde+tSccP32lYA', 'cHNidP8BAgQCAAAAAQMEyVVUIAEEAQEBBQEBAQYBAwH7BAIAAAAAAQErQEIPAAAAAAAiACCc/dpuVjOUiLE7shRAGtPlr79BRDvRhJ8hBBZO3bJRByICAxP/QAbXElyp14Ex6p9hEOLadukdgNzFadkHQ0ihJIfuRzBEAiAQ/J3PtNddIXEyryGKmbLynVXAvdkXrx8G5/T1pVITngIgJC025b1L/xcPPl45Ji2ALELKkiAWsbbzX1Q7puxXmIcBAQMEAQAAAAEFR1IhAxP/QAbXElyp14Ex6p9hEOLadukdgNzFadkHQ0ihJIfuIQOI2tHiwIqqDuBYIsYi6cjqpiDUm7OrVyYYs3tDORxObVKuIgYDiNrR4sCKqg7gWCLGIunI6qYg1Juzq1cmGLN7QzkcTm0IAhKTyQAAAAAiBgMT/0AG1xJcqdeBMeqfYRDi2nbpHYDcxWnZB0NIoSSH7ghHnxq3AAAAAAEOIIoK5MY7zfnXiwfrRQG7I0BP3bxzlzxZJ5PwR74UlQdLAQ8EAQAAAAEQBHTZmYAAAQMICi0PAAAAAAABBCIAIDuMtkR4HL7Klr6LK/GCev2Qizz7VWmsdNq5OV6N2jnkAA==', 'cHNidP8BAgQCAAAAAQMEJ6pHIAEEAQEBBQEDAQYBAwH7BAIAAAAAAQErQEIPAAAAAAAiACBDLtwFmNIlFK0EyoFBTkL9Mby9xfFU9ESjJb90SmpQVSICAtYGPQImkbJJCrRU3uc6V8b/XTCDUrRh7OafPChPLCQSRzBEAiBysjZc3nD4W4nb/ZZwVo6y7g9xG1booVx2O3EamX/8HQIgYVfgTi/7A9g3deDEezVSG0i9w8PY+nCOZIzsI5QurTwBAQMEAQAAAAEFR1IhAtYGPQImkbJJCrRU3uc6V8b/XTCDUrRh7OafPChPLCQSIQL1LAIQ1bBdOKDAHzFr4nrQf62xABX0l6zPp4t8PNtctlKuIgYC9SwCENWwXTigwB8xa+J60H+tsQAV9Jesz6eLfDzbXLYIx88ENgAAAAAiBgLWBj0CJpGySQq0VN7nOlfG/10wg1K0YezmnzwoTywkEgj9r2whAAAAAAEOIDXaspluV3YuPsFYwNV9OfQ8plfogtk/wk9f66qPNu2aAQ8EAQAAAAEQBFZtHYAAAQMIUMMAAAAAAAABBCIAIFZ5p9BuG9J2qiX1bp5N9+B9mDfvsMX2NgTxDNn3ZqA+AAEDCNTdBgAAAAAAAQQWABR+W1yPT8GpSE4ln5LKTLt/ooFOpAABAwiabAcAAAAAAAEEIgAgq2Im3r/+/0p0HAE2f6PIdRckg8+z4yfQ+MeqTFHt7KoA']
l1 = node_factory.get_node(dbfile='last_tx_upgrade.sqlite3.xz', l1 = node_factory.get_node(dbfile='last_tx_upgrade.sqlite3.xz',
options={'database-upgrade': True}) options={'database-upgrade': True})
b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channels ORDER BY id;')] b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channels ORDER BY id;')]
for i in range(len(b64_last_txs)): for i in range(len(b64_last_txs)):
bpsbt = b64_last_txs[i] assert b64_last_txs[i] == upgraded_psbts[i]
psbt = bitcoind.rpc.decodepsbt(bpsbt)
tx = prior_txs[i]
assert psbt['tx']['txid'] == bitcoind.rpc.decoderawtransaction(tx)['txid']
funding_input = only_one(psbt['inputs'])
# Every opened channel was funded with the same amount: 1M sats
assert funding_input['witness_utxo']['amount'] == Decimal('0.01')
assert funding_input['witness_utxo']['scriptPubKey']['type'] == 'witness_v0_scripthash'
assert funding_input['witness_script']['type'] == 'multisig'
l1.stop() l1.stop()
# Test again, but this time with a database with a closed channel + forgotten peer # Test again, but this time with a database with a closed channel + forgotten peer
@@ -222,8 +210,9 @@ def test_last_tx_psbt_upgrade(node_factory, bitcoind):
options={'database-upgrade': True}) options={'database-upgrade': True})
last_txs = [x['last_tx'] for x in l2.db_query('SELECT last_tx FROM channels ORDER BY id;')] last_txs = [x['last_tx'] for x in l2.db_query('SELECT last_tx FROM channels ORDER BY id;')]
# The first tx should be psbt, the second should still be hex # The first tx should be psbt, the second should still be hex (Newer Core version required for better error message)
bitcoind.rpc.decodepsbt(base64.b64encode(last_txs[0]).decode('utf-8')) assert last_txs[0][:4] == b'psbt'
bitcoind.rpc.decoderawtransaction(last_txs[1].hex()) bitcoind.rpc.decoderawtransaction(last_txs[1].hex())

View File

@@ -461,6 +461,7 @@ def test_bech32_funding(node_factory, chainparams):
assert only_one(fundingtx['vin'])['txid'] == res['wallettxid'] assert only_one(fundingtx['vin'])['txid'] == res['wallettxid']
@unittest.skipIf(not TEST_NETWORK == 'regtest', 'no support for PSETv0')
def test_withdraw_misc(node_factory, bitcoind, chainparams): def test_withdraw_misc(node_factory, bitcoind, chainparams):
def dont_spend_outputs(n, txid): def dont_spend_outputs(n, txid):
"""Reserve both outputs (we assume there are two!) in case any our ours, so we don't spend change: wrecks accounting checks""" """Reserve both outputs (we assume there are two!) in case any our ours, so we don't spend change: wrecks accounting checks"""

View File

@@ -441,6 +441,7 @@ def test_txprepare(node_factory, bitcoind, chainparams):
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash' assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash'
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
def test_reserveinputs(node_factory, bitcoind, chainparams): def test_reserveinputs(node_factory, bitcoind, chainparams):
amount = 1000000 amount = 1000000
total_outs = 12 total_outs = 12
@@ -494,6 +495,7 @@ def test_reserveinputs(node_factory, bitcoind, chainparams):
assert not any('reserved_to_block' in o for o in l1.rpc.listfunds()['outputs']) assert not any('reserved_to_block' in o for o in l1.rpc.listfunds()['outputs'])
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
def test_fundpsbt(node_factory, bitcoind, chainparams): def test_fundpsbt(node_factory, bitcoind, chainparams):
amount = 1000000 amount = 1000000
total_outs = 4 total_outs = 4
@@ -577,6 +579,7 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
l1.rpc.fundpsbt(amount // 2, feerate, 0) l1.rpc.fundpsbt(amount // 2, feerate, 0)
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
def test_utxopsbt(node_factory, bitcoind, chainparams): def test_utxopsbt(node_factory, bitcoind, chainparams):
amount = 1000000 amount = 1000000
l1 = node_factory.get_node() l1 = node_factory.get_node()
@@ -691,6 +694,7 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
reservedok=True) reservedok=True)
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
def test_sign_external_psbt(node_factory, bitcoind, chainparams): def test_sign_external_psbt(node_factory, bitcoind, chainparams):
""" """
A PSBT w/ one of our inputs should be signable (we can fill A PSBT w/ one of our inputs should be signable (we can fill
@@ -719,6 +723,7 @@ def test_sign_external_psbt(node_factory, bitcoind, chainparams):
l1.rpc.signpsbt(psbt) l1.rpc.signpsbt(psbt)
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
def test_sign_and_send_psbt(node_factory, bitcoind, chainparams): def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
""" """
Tests for the sign + send psbt RPCs Tests for the sign + send psbt RPCs

View File

@@ -97,12 +97,21 @@ static struct command_result *json_reserveinputs(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
/* We only deal with V2 internally */
if (!psbt_set_version(psbt, 2)) {
return command_fail(cmd, LIGHTNINGD,
"Failed to set version for PSBT: %s",
type_to_string(tmpctx,
struct wally_psbt,
psbt));
}
current_height = get_block_height(cmd->ld->topology); current_height = get_block_height(cmd->ld->topology);
for (size_t i = 0; i < psbt->tx->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
struct utxo *utxo; struct utxo *utxo;
wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint);
utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint); utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint);
if (!utxo) if (!utxo)
continue; continue;
@@ -152,6 +161,14 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
/* We only deal with V2 internally */
if (!psbt_set_version(psbt, 2)) {
log_broken(cmd->ld->log,
"Unable to set version for PSBT: %s",
type_to_string(tmpctx, struct wally_psbt,
psbt));
}
/* We should also add the utxo info for these inputs! /* We should also add the utxo info for these inputs!
* (absolutely required for using this psbt in a dual-funded * (absolutely required for using this psbt in a dual-funded
* round) */ * round) */
@@ -159,7 +176,7 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
struct bitcoin_tx *utxo_tx; struct bitcoin_tx *utxo_tx;
struct bitcoin_txid txid; struct bitcoin_txid txid;
wally_tx_input_get_txid(&psbt->tx->inputs[i], &txid); wally_psbt_input_get_txid(&psbt->inputs[i], &txid);
utxo_tx = wallet_transaction_get(psbt, cmd->ld->wallet, utxo_tx = wallet_transaction_get(psbt, cmd->ld->wallet,
&txid); &txid);
if (utxo_tx) { if (utxo_tx) {
@@ -176,13 +193,13 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
response = json_stream_success(cmd); response = json_stream_success(cmd);
json_array_start(response, "reservations"); json_array_start(response, "reservations");
for (size_t i = 0; i < psbt->tx->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
struct utxo *utxo; struct utxo *utxo;
enum output_status oldstatus; enum output_status oldstatus;
u32 old_res; u32 old_res;
wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint);
utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint); utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint);
if (!utxo || utxo->status != OUTPUT_STATE_RESERVED) if (!utxo || utxo->status != OUTPUT_STATE_RESERVED)
continue; continue;
@@ -295,14 +312,10 @@ static struct wally_psbt *psbt_using_utxos(const tal_t *ctx,
psbt_input_set_wit_utxo(psbt, i, scriptPubkey, utxos[i]->amount); psbt_input_set_wit_utxo(psbt, i, scriptPubkey, utxos[i]->amount);
if (is_elements(chainparams)) { if (is_elements(chainparams)) {
struct amount_asset asset;
/* FIXME: persist asset tags */ /* FIXME: persist asset tags */
asset = amount_sat_to_asset(&utxos[i]->amount, amount_sat_to_asset(&utxos[i]->amount,
chainparams->fee_asset_tag); chainparams->fee_asset_tag);
/* FIXME: persist nonces */ /* FIXME: persist nonces */
psbt_elements_input_set_asset(psbt,
psbt->num_inputs - 1,
&asset);
} }
/* FIXME: as of 17 sept 2020, elementsd is *at most* at par /* FIXME: as of 17 sept 2020, elementsd is *at most* at par
@@ -358,7 +371,7 @@ static struct command_result *finish_psbt(struct command *cmd,
psbt = psbt_using_utxos(cmd, cmd->ld->wallet, utxos, psbt = psbt_using_utxos(cmd, cmd->ld->wallet, utxos,
*locktime, BITCOIN_TX_RBF_SEQUENCE); *locktime, BITCOIN_TX_RBF_SEQUENCE);
assert(psbt->version == 2);
/* Should we add a change output for the excess? */ /* Should we add a change output for the excess? */
if (excess_as_change) { if (excess_as_change) {
struct amount_sat change; struct amount_sat change;
@@ -401,7 +414,14 @@ fee_calc:
psbt_append_output(psbt, NULL, est_fee); psbt_append_output(psbt, NULL, est_fee);
/* Add additional weight of fee output */ /* Add additional weight of fee output */
weight += bitcoin_tx_output_weight(0); weight += bitcoin_tx_output_weight(0);
} else {
/* PSETv0 doesn't exist */
if (!psbt_set_version(psbt, 0)) {
return command_fail(cmd, LIGHTNINGD,
"Failed to set PSBT version number back to 0.");
}
} }
response = json_stream_success(cmd); response = json_stream_success(cmd);
json_add_psbt(response, "psbt", psbt); json_add_psbt(response, "psbt", psbt);
json_add_num(response, "feerate_per_kw", feerate_per_kw); json_add_num(response, "feerate_per_kw", feerate_per_kw);

View File

@@ -614,14 +614,14 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd,
struct utxo ***utxos) struct utxo ***utxos)
{ {
*utxos = tal_arr(cmd, struct utxo *, 0); *utxos = tal_arr(cmd, struct utxo *, 0);
for (size_t i = 0; i < psbt->tx->num_inputs; i++) { for (size_t i = 0; i < psbt->num_inputs; i++) {
struct utxo *utxo; struct utxo *utxo;
struct bitcoin_outpoint outpoint; struct bitcoin_outpoint outpoint;
if (only_inputs && !in_only_inputs(only_inputs, i)) if (only_inputs && !in_only_inputs(only_inputs, i))
continue; continue;
wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint);
utxo = wallet_utxo_get(*utxos, cmd->ld->wallet, &outpoint); utxo = wallet_utxo_get(*utxos, cmd->ld->wallet, &outpoint);
if (!utxo) { if (!utxo) {
if (only_inputs) if (only_inputs)
@@ -673,7 +673,6 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd,
static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt, static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt,
struct wallet *w) struct wallet *w)
{ {
assert(psbt->tx->num_outputs == psbt->num_outputs);
tal_wally_start(); tal_wally_start();
for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) { for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) {
u32 index; u32 index;
@@ -681,8 +680,8 @@ static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt,
const u8 *script; const u8 *script;
struct ext_key ext; struct ext_key ext;
script = wally_tx_output_get_script(tmpctx, script = wally_psbt_output_get_script(tmpctx,
&psbt->tx->outputs[outndx]); &psbt->outputs[outndx]);
if (!script) if (!script)
continue; continue;
@@ -735,6 +734,7 @@ static struct command_result *json_signpsbt(struct command *cmd,
struct wally_psbt *psbt, *signed_psbt; struct wally_psbt *psbt, *signed_psbt;
struct utxo **utxos; struct utxo **utxos;
u32 *input_nums; u32 *input_nums;
u32 psbt_version;
if (!param(cmd, buffer, params, if (!param(cmd, buffer, params,
p_req("psbt", param_psbt, &psbt), p_req("psbt", param_psbt, &psbt),
@@ -742,6 +742,15 @@ static struct command_result *json_signpsbt(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
/* We internally deal with v2 only but we want to return V2 if given */
psbt_version = psbt->version;
if (!psbt_set_version(psbt, 2)) {
return command_fail(cmd, LIGHTNINGD,
"Could not set PSBT version: %s",
type_to_string(tmpctx, struct wally_psbt,
psbt));
}
/* Sanity check! */ /* Sanity check! */
for (size_t i = 0; i < tal_count(input_nums); i++) { for (size_t i = 0; i < tal_count(input_nums); i++) {
if (input_nums[i] >= psbt->num_inputs) if (input_nums[i] >= psbt->num_inputs)
@@ -782,6 +791,13 @@ static struct command_result *json_signpsbt(struct command *cmd,
"HSM gave bad sign_withdrawal_reply %s", "HSM gave bad sign_withdrawal_reply %s",
tal_hex(tmpctx, msg)); tal_hex(tmpctx, msg));
if (!psbt_set_version(signed_psbt, psbt_version)) {
return command_fail(cmd, LIGHTNINGD,
"Signed PSBT unable to have version set: %s",
type_to_string(tmpctx, struct wally_psbt,
psbt));
}
response = json_stream_success(cmd); response = json_stream_success(cmd);
json_add_psbt(response, "signed_psbt", signed_psbt); json_add_psbt(response, "signed_psbt", signed_psbt);
return command_success(cmd, response); return command_success(cmd, response);
@@ -824,8 +840,8 @@ static void maybe_notify_new_external_send(struct lightningd *ld,
return; return;
/* If it's going to our wallet, ignore */ /* If it's going to our wallet, ignore */
script = wally_tx_output_get_script(tmpctx, script = wally_psbt_output_get_script(tmpctx,
&psbt->tx->outputs[outnum]); &psbt->outputs[outnum]);
if (wallet_can_spend(ld->wallet, script, &index, &is_p2sh)) if (wallet_can_spend(ld->wallet, script, &index, &is_p2sh))
return; return;
@@ -870,6 +886,11 @@ static void sendpsbt_done(struct bitcoind *bitcoind UNUSED,
return; return;
} }
/* Internal-only after, set to v2 */
if (!psbt_set_version(sending->psbt, 2)) {
abort(); // Send succeeded but later calls may fail
}
wallet_transaction_add(ld->wallet, sending->wtx, 0, 0); wallet_transaction_add(ld->wallet, sending->wtx, 0, 0);
/* Extract the change output and add it to the DB */ /* Extract the change output and add it to the DB */