mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
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:
parent
5eddf3cd73
commit
908f834d66
257
bitcoin/psbt.c
257
bitcoin/psbt.c
@ -24,36 +24,26 @@ static struct wally_psbt *init_psbt(const tal_t *ctx, size_t num_inputs, size_t
|
||||
|
||||
tal_wally_start();
|
||||
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
|
||||
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);
|
||||
/* 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_wally_end_onto(ctx, psbt, struct wally_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)
|
||||
{
|
||||
int wally_err;
|
||||
struct wally_tx *wtx;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -72,17 +62,18 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx)
|
||||
struct wally_psbt *psbt;
|
||||
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();
|
||||
/* Set directly: avoids psbt checks for non-NULL scripts/witnesses */
|
||||
wally_err = wally_tx_clone_alloc(wtx, 0, &psbt->tx);
|
||||
assert(wally_err == WALLY_OK);
|
||||
/* Inputs/outs are pre-allocated above, 'add' them as empty dummies */
|
||||
psbt->num_inputs = wtx->num_inputs;
|
||||
psbt->num_outputs = wtx->num_outputs;
|
||||
|
||||
/* locktime set in create_psbt for now */
|
||||
wally_psbt_set_tx_version(psbt, wtx->version);
|
||||
wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS);
|
||||
|
||||
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 */
|
||||
if (wtx->inputs[i].script) {
|
||||
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_len);
|
||||
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) {
|
||||
wally_err =
|
||||
wally_psbt_input_set_final_witness(&psbt->inputs[i],
|
||||
wtx->inputs[i].witness);
|
||||
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);
|
||||
return psbt;
|
||||
}
|
||||
@ -128,7 +114,7 @@ struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt,
|
||||
int wally_err;
|
||||
|
||||
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);
|
||||
tal_wally_end(psbt);
|
||||
return &psbt->inputs[insert_at];
|
||||
@ -168,7 +154,7 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt,
|
||||
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);
|
||||
wally_tx_input_free(tx_in);
|
||||
tal_wally_end(psbt);
|
||||
@ -204,7 +190,7 @@ struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt,
|
||||
int wally_err;
|
||||
|
||||
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);
|
||||
tal_wally_end(psbt);
|
||||
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_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);
|
||||
return out;
|
||||
}
|
||||
@ -264,7 +250,7 @@ void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in,
|
||||
pubkey_to_der(pk_der, pubkey);
|
||||
|
||||
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),
|
||||
fingerprint, sizeof(fingerprint),
|
||||
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();
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct amount_asset asset;
|
||||
size_t fee_output_idx = psbt->num_outputs;
|
||||
|
||||
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,
|
||||
* 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++) {
|
||||
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;
|
||||
}
|
||||
for (size_t i = 0; i < psbt->num_outputs; i++) {
|
||||
asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]);
|
||||
if (elements_wtx_output_is_fee(psbt->tx, i)) {
|
||||
struct amount_asset output_amount = wally_psbt_output_get_amount(&psbt->outputs[i]);
|
||||
if (elements_psbt_output_is_fee(psbt, i)) {
|
||||
if (fee_output_idx == psbt->num_outputs) {
|
||||
fee_output_idx = i;
|
||||
continue;
|
||||
@ -401,40 +386,47 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt)
|
||||
psbt_rm_output(psbt, i--);
|
||||
continue;
|
||||
}
|
||||
if (!amount_asset_is_main(&asset))
|
||||
if (!amount_asset_is_main(&output_amount))
|
||||
continue;
|
||||
|
||||
if (!amount_sat_sub(&total_in, total_in,
|
||||
amount_asset_to_sat(&asset)))
|
||||
if (!amount_sat_sub(&total_fee, total_fee,
|
||||
amount_asset_to_sat(&output_amount)))
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount_sat_eq(total_in, AMOUNT_SAT(0)))
|
||||
if (amount_sat_eq(total_fee, AMOUNT_SAT(0)))
|
||||
return;
|
||||
|
||||
/* We need to add a fee output */
|
||||
if (fee_output_idx == psbt->num_outputs) {
|
||||
psbt_append_output(psbt, NULL, total_in);
|
||||
psbt_append_output(psbt, NULL, total_fee);
|
||||
} else {
|
||||
u64 sats = total_in.satoshis; /* Raw: wally API */
|
||||
struct wally_tx_output *out = &psbt->tx->outputs[fee_output_idx];
|
||||
if (wally_tx_confidential_value_from_satoshi(
|
||||
sats, out->value, out->value_len) != WALLY_OK)
|
||||
return;
|
||||
int ret;
|
||||
u64 sats = total_fee.satoshis; /* Raw: wally API */
|
||||
struct wally_psbt_output *out = &psbt->outputs[fee_output_idx];
|
||||
ret = wally_psbt_output_set_amount(out, sats);
|
||||
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,
|
||||
const struct bitcoin_outpoint *outpoint)
|
||||
{
|
||||
for (size_t i = 0; i < psbt->num_inputs; i++) {
|
||||
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)
|
||||
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))
|
||||
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));
|
||||
val = amount_asset_to_sat(&amt_asset);
|
||||
} 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;
|
||||
val = amount_sat(prev_tx->outputs[idx].satoshi);
|
||||
} else
|
||||
@ -466,7 +458,7 @@ struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
|
||||
{
|
||||
struct amount_asset asset;
|
||||
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));
|
||||
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>
|
||||
*/
|
||||
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(&key, 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++) {
|
||||
struct wally_psbt_input *input = &psbt->inputs[i];
|
||||
struct wally_tx_witness_stack *stack;
|
||||
const struct wally_map_item *iws;
|
||||
|
||||
if (!is_anchor_witness_script(input->witness_script,
|
||||
input->witness_script_len))
|
||||
iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05);
|
||||
if (!iws || !is_anchor_witness_script(iws->value,
|
||||
iws->value_len))
|
||||
continue;
|
||||
|
||||
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_len);
|
||||
wally_tx_witness_stack_add(stack,
|
||||
input->witness_script,
|
||||
input->witness_script_len);
|
||||
iws->value,
|
||||
iws->value_len);
|
||||
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;
|
||||
|
||||
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);
|
||||
else
|
||||
wtx = NULL;
|
||||
@ -679,7 +673,7 @@ struct wally_psbt *psbt_from_b64(const tal_t *ctx,
|
||||
char *str = tal_strndup(tmpctx, b64, b64len);
|
||||
|
||||
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);
|
||||
else
|
||||
psbt = NULL;
|
||||
@ -713,7 +707,9 @@ const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt,
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
else
|
||||
psbt = NULL;
|
||||
@ -780,38 +776,23 @@ struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx,
|
||||
return psbt;
|
||||
}
|
||||
|
||||
/* This only works on a non-final psbt because we're ALL SEGWIT! */
|
||||
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 *tx;
|
||||
int wally_err;
|
||||
assert(psbt->version == 2);
|
||||
|
||||
/* You can *almost* take txid of global tx. But @niftynei thought
|
||||
* about this far more than me and pointed out that P2SH
|
||||
* inputs would not be represented, so here we go. */
|
||||
/* We rely on wally extractor to fill out all txid-related fields including scriptSigs */
|
||||
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)
|
||||
*wtx = tx;
|
||||
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++) {
|
||||
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)
|
||||
|| elements_wtx_output_is_fee(psbt->tx, i))
|
||||
|| elements_psbt_output_is_fee(psbt, i))
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
* as the global_tx
|
||||
* as the locktime/inputs/output psbt fields
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @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,
|
||||
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,
|
||||
const char *b64,
|
||||
size_t b64len);
|
||||
|
@ -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 */
|
||||
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
|
||||
{ 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 */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }
|
||||
|
@ -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 */
|
||||
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
|
||||
{ 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 */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ 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 */
|
||||
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);
|
||||
|
||||
common_shutdown();
|
||||
|
@ -81,10 +81,6 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt UNNEEDED,
|
||||
const u8 *input_wscript UNNEEDED,
|
||||
const u8 *redeemscript UNNEEDED)
|
||||
{ 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 */
|
||||
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(); }
|
||||
|
@ -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 */
|
||||
void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED)
|
||||
{ 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 */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }
|
||||
|
61
bitcoin/tx.c
61
bitcoin/tx.c
@ -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)
|
||||
{
|
||||
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,
|
||||
@ -191,6 +220,7 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx,
|
||||
{
|
||||
int wally_err;
|
||||
int input_num = tx->wtx->num_inputs;
|
||||
struct wally_tx_input *tx_input;
|
||||
|
||||
psbt_append_input(tx->psbt, outpoint,
|
||||
sequence, scriptSig,
|
||||
@ -205,9 +235,11 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx,
|
||||
scriptPubkey, amount);
|
||||
|
||||
tal_wally_start();
|
||||
tx_input = wally_tx_input_from_outpoint_sequence(outpoint, sequence);
|
||||
wally_err = wally_tx_add_input(tx->wtx,
|
||||
&tx->psbt->tx->inputs[input_num]);
|
||||
tx_input);
|
||||
assert(wally_err == WALLY_OK);
|
||||
wally_tx_input_free(tx_input);
|
||||
|
||||
/* scriptsig isn't actually stored in psbt input, so add that now */
|
||||
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);
|
||||
|
||||
if (is_elements(chainparams)) {
|
||||
struct amount_asset asset;
|
||||
/* FIXME: persist asset tags */
|
||||
asset = amount_sat_to_asset(&amount,
|
||||
amount_sat_to_asset(&amount,
|
||||
chainparams->fee_asset_tag);
|
||||
/* FIXME: persist nonces */
|
||||
psbt_elements_input_set_asset(tx->psbt, input_num, &asset);
|
||||
}
|
||||
return input_num;
|
||||
}
|
||||
@ -258,10 +288,6 @@ void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum,
|
||||
assert(ret == WALLY_OK);
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
struct wally_psbt_output *out;
|
||||
const struct wally_map_item *output_witness_script;
|
||||
|
||||
assert(outnum < tx->psbt->num_outputs);
|
||||
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 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,
|
||||
@ -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)
|
||||
{
|
||||
size_t locktime;
|
||||
wally_psbt_get_locktime(psbt, &locktime);
|
||||
struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams,
|
||||
psbt->tx->num_inputs,
|
||||
psbt->tx->num_outputs,
|
||||
psbt->tx->locktime);
|
||||
psbt->num_inputs,
|
||||
psbt->num_outputs,
|
||||
locktime);
|
||||
wally_tx_free(tx->wtx);
|
||||
|
||||
psbt_finalize(psbt);
|
||||
tx->wtx = psbt_final_tx(tx, psbt);
|
||||
if (!tx->wtx) {
|
||||
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;
|
||||
}
|
||||
tal_wally_end_onto(tx, tx->wtx, struct wally_tx);
|
||||
if (!tx->wtx)
|
||||
return tal_free(tx);
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <wally_psbt.h>
|
||||
|
||||
static void swap_wally_outputs(struct wally_tx_output *outputs,
|
||||
struct wally_tx_output *psbt_global_outs,
|
||||
struct wally_psbt_output *psbt_outs,
|
||||
const void **map, u32 *cltvs,
|
||||
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[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];
|
||||
psbt_outs[i1] = psbt_outs[i2];
|
||||
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_wally_outputs(tx->wtx->outputs,
|
||||
tx->psbt->tx->outputs,
|
||||
tx->psbt->outputs,
|
||||
map, cltvs, i, best_pos);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ void psbt_finalize_input(const tal_t *ctx,
|
||||
struct wally_psbt_input *in,
|
||||
const struct witness_element **elements)
|
||||
{
|
||||
const struct wally_map_item *redeem_script;
|
||||
psbt_input_set_final_witness_stack(ctx, in, elements);
|
||||
|
||||
/* 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
|
||||
* scriptsig check -- if there's a redeemscript field still around we
|
||||
* 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,
|
||||
in->redeem_script,
|
||||
in->redeem_script_len, 0);
|
||||
in->final_scriptsig =
|
||||
redeem_script->value,
|
||||
redeem_script->value_len, 0);
|
||||
u8 *final_scriptsig =
|
||||
bitcoin_scriptsig_redeem(NULL,
|
||||
take(redeemscript));
|
||||
in->final_scriptsig_len =
|
||||
tal_bytelen(in->final_scriptsig);
|
||||
|
||||
in->redeem_script = tal_free(in->redeem_script);
|
||||
in->redeem_script_len = 0;
|
||||
wally_psbt_input_set_final_scriptsig(in, final_scriptsig, tal_bytelen(final_scriptsig));
|
||||
wally_psbt_input_set_redeem_script(in, tal_arr(NULL, u8, 0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *ma
|
||||
u32 path[1];
|
||||
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),
|
||||
fingerprint, sizeof(fingerprint),
|
||||
path, 1) != WALLY_OK)
|
||||
|
@ -58,17 +58,11 @@ static int compare_outputs_at(const struct output_set *a,
|
||||
}
|
||||
|
||||
static const u8 *linearize_input(const tal_t *ctx,
|
||||
const struct wally_psbt_input *in,
|
||||
const struct wally_tx_input *tx_in)
|
||||
const struct wally_psbt_input *in)
|
||||
{
|
||||
struct wally_psbt *psbt = create_psbt(NULL, 1, 0, 0);
|
||||
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->num_inputs++;
|
||||
|
||||
@ -77,11 +71,10 @@ static const u8 *linearize_input(const tal_t *ctx,
|
||||
wally_map_sort(&psbt->inputs[0].unknowns, 0);
|
||||
|
||||
/* signatures, keypaths, etc - we dont care if they change */
|
||||
psbt->inputs[0].final_witness = NULL;
|
||||
psbt->inputs[0].final_scriptsig_len = 0;
|
||||
psbt->inputs[0].witness_script = NULL;
|
||||
psbt->inputs[0].witness_script_len = 0;
|
||||
psbt->inputs[0].redeem_script_len = 0;
|
||||
wally_psbt_input_set_final_witness(&psbt->inputs[0], NULL);
|
||||
wally_psbt_input_set_final_scriptsig(&psbt->inputs[0], NULL, 0);
|
||||
wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0);
|
||||
wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0);
|
||||
psbt->inputs[0].keypaths.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,
|
||||
const struct wally_psbt_output *out,
|
||||
const struct wally_tx_output *tx_out)
|
||||
const struct wally_psbt_output *out)
|
||||
{
|
||||
struct wally_psbt *psbt = create_psbt(NULL, 1, 1, 0);
|
||||
size_t byte_len;
|
||||
struct bitcoin_outpoint outpoint;
|
||||
|
||||
/* Add a 'fake' input so this will linearize the tx */
|
||||
memset(&outpoint, 0, sizeof(outpoint));
|
||||
/* Add a 'fake' non-zero input so libwally will agree to linearize the tx */
|
||||
memset(&outpoint, 1, sizeof(outpoint));
|
||||
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->num_outputs++;
|
||||
/* 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 */
|
||||
psbt->outputs[0].keypaths.num_items = 0;
|
||||
/* And you can add scripts, no problem */
|
||||
psbt->outputs[0].witness_script_len = 0;
|
||||
psbt->outputs[0].redeem_script_len = 0;
|
||||
wally_psbt_output_set_witness_script(&psbt->outputs[0], NULL, 0);
|
||||
wally_psbt_output_set_redeem_script(&psbt->outputs[0], NULL, 0);
|
||||
|
||||
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)
|
||||
{
|
||||
const u8 *a_in = linearize_input(tmpctx,
|
||||
&a->inputs[a_index],
|
||||
&a->tx->inputs[a_index]);
|
||||
&a->inputs[a_index]);
|
||||
const u8 *b_in = linearize_input(tmpctx,
|
||||
&b->inputs[b_index],
|
||||
&b->tx->inputs[b_index]);
|
||||
&b->inputs[b_index]);
|
||||
|
||||
return memeq(a_in, tal_bytelen(a_in),
|
||||
b_in, tal_bytelen(b_in));
|
||||
@ -151,11 +136,9 @@ static bool output_identical(const struct wally_psbt *a,
|
||||
size_t b_index)
|
||||
{
|
||||
const u8 *a_out = linearize_output(tmpctx,
|
||||
&a->outputs[a_index],
|
||||
&a->tx->outputs[a_index]);
|
||||
&a->outputs[a_index]);
|
||||
const u8 *b_out = linearize_output(tmpctx,
|
||||
&b->outputs[b_index],
|
||||
&b->tx->outputs[b_index]);
|
||||
&b->outputs[b_index]);
|
||||
return memeq(a_out, tal_bytelen(a_out),
|
||||
b_out, tal_bytelen(b_out));
|
||||
}
|
||||
@ -168,7 +151,6 @@ static void sort_inputs(struct wally_psbt *psbt)
|
||||
psbt->num_inputs);
|
||||
|
||||
for (size_t i = 0; i < tal_count(set); i++) {
|
||||
set[i].tx_input = psbt->tx->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 */
|
||||
for (size_t i = 0; i < tal_count(set); i++) {
|
||||
psbt->inputs[i] = set[i].input;
|
||||
psbt->tx->inputs[i] = set[i].tx_input;
|
||||
}
|
||||
|
||||
tal_free(set);
|
||||
@ -191,7 +172,6 @@ static void sort_outputs(struct wally_psbt *psbt)
|
||||
struct output_set,
|
||||
psbt->num_outputs);
|
||||
for (size_t i = 0; i < tal_count(set); i++) {
|
||||
set[i].tx_output = psbt->tx->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 */
|
||||
for (size_t i = 0; i < tal_count(set); i++) {
|
||||
psbt->outputs[i] = set[i].output;
|
||||
psbt->tx->outputs[i] = set[i].tx_output;
|
||||
}
|
||||
|
||||
tal_free(set);
|
||||
@ -217,7 +196,6 @@ void psbt_sort_by_serial_id(struct wally_psbt *psbt)
|
||||
do { \
|
||||
struct type##_set a; \
|
||||
a.type = from->type##s[index]; \
|
||||
a.tx_##type = from->tx->type##s[index]; \
|
||||
a.idx = index; \
|
||||
tal_arr_expand(&add_to, a); \
|
||||
} while (0)
|
||||
@ -398,6 +376,7 @@ bool psbt_has_required_fields(struct wally_psbt *psbt)
|
||||
{
|
||||
u64 serial_id;
|
||||
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];
|
||||
|
||||
if (!psbt_get_serial_id(&input->unknowns, &serial_id))
|
||||
@ -408,13 +387,13 @@ bool psbt_has_required_fields(struct wally_psbt *psbt)
|
||||
return false;
|
||||
|
||||
/* 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 =
|
||||
wally_tx_output_get_script(tmpctx,
|
||||
&input->utxo->outputs[psbt->tx->inputs[i].index]);
|
||||
if (is_p2sh(outscript, NULL) && input->redeem_script_len == 0)
|
||||
&input->utxo->outputs[psbt->inputs[i].index]);
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
struct wally_psbt *new)
|
||||
{
|
||||
assert(orig->version == 2 && new->version == 2);
|
||||
|
||||
struct psbt_changeset *cs;
|
||||
bool ok;
|
||||
cs = psbt_get_changeset(NULL, orig, new);
|
||||
|
@ -15,14 +15,12 @@ struct wally_psbt_output;
|
||||
struct wally_map;
|
||||
|
||||
struct input_set {
|
||||
struct wally_tx_input tx_input;
|
||||
struct wally_psbt_input input;
|
||||
/* index on PSBT of this input */
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
struct output_set {
|
||||
struct wally_tx_output tx_output;
|
||||
struct wally_psbt_output output;
|
||||
/* index on PSBT of this output */
|
||||
size_t idx;
|
||||
|
File diff suppressed because one or more lines are too long
2
external/libwally-core
vendored
2
external/libwally-core
vendored
@ -1 +1 @@
|
||||
Subproject commit d839dbab4279e1d3d1ece4e52d4766f523b3f7ee
|
||||
Subproject commit 23e6b626c8906bce2e3179409b938c9ef9bca463
|
@ -466,7 +466,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt)
|
||||
struct privkey privkey;
|
||||
struct pubkey pubkey;
|
||||
|
||||
if (!wally_tx_input_spends(&psbt->tx->inputs[j],
|
||||
if (!wally_psbt_input_spends(&psbt->inputs[j],
|
||||
&utxo->outpoint))
|
||||
continue;
|
||||
|
||||
|
@ -2180,11 +2180,11 @@ static void handle_validate_rbf(struct subd *dualopend,
|
||||
list_for_each(&channel->inflights, inflight, list) {
|
||||
/* Remove every non-matching input from set */
|
||||
for (size_t i = 0; i < candidate_psbt->num_inputs; i++) {
|
||||
struct wally_tx_input *input =
|
||||
&candidate_psbt->tx->inputs[i];
|
||||
const struct wally_psbt_input *input =
|
||||
&candidate_psbt->inputs[i];
|
||||
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,
|
||||
&outpoint))
|
||||
@ -2793,6 +2793,11 @@ static struct command_result *json_openchannel_init(struct command *cmd,
|
||||
NULL))
|
||||
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 ! */
|
||||
if (!amount_sat_zero(*request_amt) && !rates)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
|
@ -1009,10 +1009,15 @@ static struct command_result *json_fundchannel_complete(struct command *cmd,
|
||||
|
||||
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. */
|
||||
for (size_t i = 0; i < funding_psbt->tx->num_outputs; i++) {
|
||||
if (memeq(funding_psbt->tx->outputs[i].script,
|
||||
funding_psbt->tx->outputs[i].script_len,
|
||||
for (size_t i = 0; i < funding_psbt->num_outputs; i++) {
|
||||
if (memeq(funding_psbt->outputs[i].script,
|
||||
funding_psbt->outputs[i].script_len,
|
||||
fc->funding_scriptpubkey,
|
||||
tal_bytelen(fc->funding_scriptpubkey))) {
|
||||
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. */
|
||||
if (!chainparams->is_elements
|
||||
&& !amount_sat_eq(amount_sat(funding_psbt->tx->outputs
|
||||
[*funding_txout_num].satoshi),
|
||||
&& !amount_sat_eq(amount_sat(funding_psbt->outputs
|
||||
[*funding_txout_num].amount),
|
||||
fc->funding_sats))
|
||||
return command_fail(cmd, FUNDING_PSBT_INVALID,
|
||||
"Output to open channel is %"PRIu64"sat,"
|
||||
" should be %s",
|
||||
funding_psbt->tx->outputs
|
||||
[*funding_txout_num].satoshi,
|
||||
funding_psbt->outputs
|
||||
[*funding_txout_num].amount,
|
||||
type_to_string(tmpctx, struct amount_sat,
|
||||
&fc->funding_sats));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
/* 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,
|
||||
&channel->funding.txid, funding_depth_cb);
|
||||
watch_txo(channel, ld->topology, channel,
|
||||
|
@ -250,8 +250,8 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx,
|
||||
in->input.utxo);
|
||||
|
||||
msg = towire_tx_add_input(ctx, cid, serial_id,
|
||||
prevtx, in->tx_input.index,
|
||||
in->tx_input.sequence);
|
||||
prevtx, in->input.index,
|
||||
in->input.sequence);
|
||||
|
||||
tal_arr_remove(&set->added_ins, 0);
|
||||
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))
|
||||
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);
|
||||
const u8 *script = wally_tx_output_get_script(ctx,
|
||||
&out->tx_output);
|
||||
const u8 *script = wally_psbt_output_get_script(ctx,
|
||||
&out->output);
|
||||
|
||||
|
||||
msg = towire_tx_add_output(ctx, cid, serial_id,
|
||||
sats.satoshis, /* Raw: wire interface */
|
||||
@ -596,12 +597,20 @@ static size_t psbt_input_weight(struct wally_psbt *psbt,
|
||||
size_t in)
|
||||
{
|
||||
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 */
|
||||
weight = (32 + 4 + 4) * 4;
|
||||
weight +=
|
||||
(psbt->inputs[in].redeem_script_len +
|
||||
(varint_t) varint_size(psbt->inputs[in].redeem_script_len)) * 4;
|
||||
if (redeem_script) {
|
||||
weight +=
|
||||
(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;
|
||||
}
|
||||
@ -609,15 +618,15 @@ static size_t psbt_input_weight(struct wally_psbt *psbt,
|
||||
static size_t psbt_output_weight(struct wally_psbt *psbt,
|
||||
size_t outnum)
|
||||
{
|
||||
return (8 + psbt->tx->outputs[outnum].script_len +
|
||||
varint_size(psbt->tx->outputs[outnum].script_len)) * 4;
|
||||
return (8 + psbt->outputs[outnum].script_len +
|
||||
varint_size(psbt->outputs[outnum].script_len)) * 4;
|
||||
}
|
||||
|
||||
static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u32 *funding_txout)
|
||||
{
|
||||
for (size_t i = 0; i < psbt->num_outputs; i++) {
|
||||
if (memeq(wscript, tal_bytelen(wscript), psbt->tx->outputs[i].script,
|
||||
psbt->tx->outputs[i].script_len)) {
|
||||
if (memeq(wscript, tal_bytelen(wscript), psbt->outputs[i].script,
|
||||
psbt->outputs[i].script_len)) {
|
||||
*funding_txout = i;
|
||||
return true;
|
||||
}
|
||||
@ -2382,9 +2391,17 @@ static void accepter_start(struct state *state, const u8 *oc2_msg)
|
||||
if (!tx_state->psbt)
|
||||
tx_state->psbt = create_psbt(tx_state, 0, 0,
|
||||
tx_state->tx_locktime);
|
||||
else
|
||||
else {
|
||||
/* 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:
|
||||
*
|
||||
@ -2914,6 +2931,7 @@ static void opener_start(struct state *state, u8 *msg)
|
||||
struct lease_rates *expected_rates;
|
||||
struct tx_state *tx_state = state->tx_state;
|
||||
struct amount_sat *requested_lease;
|
||||
size_t locktime;
|
||||
|
||||
if (!fromwire_dualopend_opener_init(state, msg,
|
||||
&tx_state->psbt,
|
||||
@ -2930,8 +2948,8 @@ static void opener_start(struct state *state, u8 *msg)
|
||||
master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg);
|
||||
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
char *rbf_ctx = notleak_with_children(tal(state, char));
|
||||
size_t locktime;
|
||||
|
||||
/* We need a new tx_state! */
|
||||
tx_state = new_tx_state(rbf_ctx);
|
||||
@ -3490,8 +3509,8 @@ static void rbf_local_start(struct state *state, u8 *msg)
|
||||
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 */
|
||||
init_rbf_tlvs->funding_output_contribution
|
||||
= tal(init_rbf_tlvs, u64);
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <bitcoin/feerate.h>
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/json_out/json_out.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
@ -212,14 +213,14 @@ remember_channel_utxos(struct command *cmd,
|
||||
signed_psbt);
|
||||
|
||||
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;
|
||||
|
||||
/* Don't save peer's UTXOS */
|
||||
if (!psbt_input_is_ours(&signed_psbt->inputs[i]))
|
||||
continue;
|
||||
|
||||
wally_tx_input_get_outpoint(&signed_psbt->tx->inputs[i],
|
||||
wally_psbt_input_get_outpoint(&signed_psbt->inputs[i],
|
||||
&outpoint);
|
||||
towire_bitcoin_outpoint(&utxos_bin, &outpoint);
|
||||
}
|
||||
|
@ -572,6 +572,14 @@ after_signpsbt(struct command *cmd,
|
||||
json_tok_full_len(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))
|
||||
plugin_err(mfc->cmd->plugin,
|
||||
"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 v2_dest_count = dest_count(mfc, OPEN_CHANNEL);
|
||||
size_t i, deck_i;
|
||||
u32 psbt_version = mfc->psbt->version;
|
||||
|
||||
plugin_log(mfc->cmd->plugin, LOG_DBG,
|
||||
"mfc %"PRIu64": Creating funding tx.",
|
||||
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. */
|
||||
deck = tal_arr(tmpctx, struct multifundchannel_destination *,
|
||||
v1_dest_count + mfc->change_needed);
|
||||
@ -929,6 +947,14 @@ perform_funding_tx_finalize(struct multifundchannel_command *mfc)
|
||||
mfc->txid),
|
||||
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. */
|
||||
return perform_fundchannel_complete(mfc);
|
||||
}
|
||||
@ -1343,6 +1369,9 @@ after_fundpsbt(struct command *cmd,
|
||||
if (!mfc->psbt)
|
||||
goto fail;
|
||||
|
||||
if (!psbt_set_version(mfc->psbt, 2))
|
||||
goto fail;
|
||||
|
||||
field = json_get_member(buf, result, "feerate_per_kw");
|
||||
if (!field || !json_to_u32(buf, field, &mfc->feerate_per_kw))
|
||||
goto fail;
|
||||
|
@ -421,6 +421,8 @@ mw_after_fundpsbt(struct command *cmd,
|
||||
field->end - field->start) : NULL;
|
||||
ok = ok && mw->psbt;
|
||||
|
||||
ok = ok && psbt_set_version(mw->psbt, 2);
|
||||
|
||||
field = ok ? json_get_member(buf, result, "feerate_per_kw") : NULL;
|
||||
ok = ok && field;
|
||||
ok = ok && json_to_number(buf, field, &feerate_per_kw);
|
||||
|
@ -112,9 +112,16 @@ static bool update_parent_psbt(const tal_t *ctx,
|
||||
if (s_idx != -1)
|
||||
goto fail;
|
||||
|
||||
psbt_add_input(clone,
|
||||
&changes->added_ins[i].tx_input,
|
||||
idx);
|
||||
const struct wally_psbt_input *input = &changes->added_ins[i].input;
|
||||
struct bitcoin_outpoint outpoint;
|
||||
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 */
|
||||
clone->inputs[idx] = *in;
|
||||
|
||||
@ -172,9 +179,9 @@ static bool update_parent_psbt(const tal_t *ctx,
|
||||
if (s_idx != -1)
|
||||
goto fail;
|
||||
|
||||
psbt_add_output(clone,
|
||||
&changes->added_outs[i].tx_output,
|
||||
idx);
|
||||
const struct wally_psbt_output *output = &changes->added_outs[i].output;
|
||||
psbt_append_output(clone, output->script, amount_sat(output->amount));
|
||||
|
||||
/* Move output over */
|
||||
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++) {
|
||||
if (memeq(dest->funding_script,
|
||||
tal_bytelen(dest->funding_script),
|
||||
mfc->psbt->tx->outputs[j].script,
|
||||
mfc->psbt->tx->outputs[j].script_len))
|
||||
mfc->psbt->outputs[j].script,
|
||||
mfc->psbt->outputs[j].script_len))
|
||||
dest->outnum = j;
|
||||
}
|
||||
if (dest->outnum == mfc->psbt->num_outputs)
|
||||
|
@ -216,7 +216,7 @@ static struct command_result *finish_txprepare(struct command *cmd,
|
||||
utx = tal(NULL, struct unreleased_tx);
|
||||
utx->is_upgrade = txp->is_upgrade;
|
||||
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 (txp->is_withdraw) {
|
||||
@ -301,6 +301,11 @@ static struct command_result *psbt_created(struct command *cmd,
|
||||
psbttok->end - 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"),
|
||||
&txp->feerate))
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
|
@ -1,8 +1,7 @@
|
||||
from decimal import Decimal
|
||||
from fixtures import * # noqa: F401,F403
|
||||
from fixtures import TEST_NETWORK
|
||||
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 os
|
||||
@ -171,21 +170,16 @@ def test_scid_upgrade(node_factory, bitcoind):
|
||||
def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind):
|
||||
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',
|
||||
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;')]
|
||||
for i in range(len(b64_last_txs)):
|
||||
bpsbt = b64_last_txs[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'
|
||||
assert b64_last_txs[i] == upgraded_psbts[i]
|
||||
|
||||
|
||||
@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):
|
||||
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',
|
||||
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;')]
|
||||
for i in range(len(b64_last_txs)):
|
||||
bpsbt = b64_last_txs[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'
|
||||
assert b64_last_txs[i] == upgraded_psbts[i]
|
||||
|
||||
l1.stop()
|
||||
# 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})
|
||||
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
|
||||
bitcoind.rpc.decodepsbt(base64.b64encode(last_txs[0]).decode('utf-8'))
|
||||
# The first tx should be psbt, the second should still be hex (Newer Core version required for better error message)
|
||||
assert last_txs[0][:4] == b'psbt'
|
||||
|
||||
bitcoind.rpc.decoderawtransaction(last_txs[1].hex())
|
||||
|
||||
|
||||
|
@ -461,6 +461,7 @@ def test_bech32_funding(node_factory, chainparams):
|
||||
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 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"""
|
||||
|
@ -441,6 +441,7 @@ def test_txprepare(node_factory, bitcoind, chainparams):
|
||||
assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
|
||||
def test_reserveinputs(node_factory, bitcoind, chainparams):
|
||||
amount = 1000000
|
||||
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'])
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
|
||||
def test_fundpsbt(node_factory, bitcoind, chainparams):
|
||||
amount = 1000000
|
||||
total_outs = 4
|
||||
@ -577,6 +579,7 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
|
||||
l1.rpc.fundpsbt(amount // 2, feerate, 0)
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
|
||||
def test_utxopsbt(node_factory, bitcoind, chainparams):
|
||||
amount = 1000000
|
||||
l1 = node_factory.get_node()
|
||||
@ -691,6 +694,7 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
|
||||
reservedok=True)
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
|
||||
def test_sign_external_psbt(node_factory, bitcoind, chainparams):
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '')
|
||||
def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
||||
"""
|
||||
Tests for the sign + send psbt RPCs
|
||||
|
@ -97,12 +97,21 @@ static struct command_result *json_reserveinputs(struct command *cmd,
|
||||
NULL))
|
||||
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);
|
||||
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 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);
|
||||
if (!utxo)
|
||||
continue;
|
||||
@ -152,6 +161,14 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
|
||||
NULL))
|
||||
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!
|
||||
* (absolutely required for using this psbt in a dual-funded
|
||||
* round) */
|
||||
@ -159,7 +176,7 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
|
||||
struct bitcoin_tx *utxo_tx;
|
||||
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,
|
||||
&txid);
|
||||
if (utxo_tx) {
|
||||
@ -176,13 +193,13 @@ static struct command_result *json_unreserveinputs(struct command *cmd,
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
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 utxo *utxo;
|
||||
enum output_status oldstatus;
|
||||
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);
|
||||
if (!utxo || utxo->status != OUTPUT_STATE_RESERVED)
|
||||
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);
|
||||
if (is_elements(chainparams)) {
|
||||
struct amount_asset asset;
|
||||
/* FIXME: persist asset tags */
|
||||
asset = amount_sat_to_asset(&utxos[i]->amount,
|
||||
amount_sat_to_asset(&utxos[i]->amount,
|
||||
chainparams->fee_asset_tag);
|
||||
/* 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
|
||||
@ -358,7 +371,7 @@ static struct command_result *finish_psbt(struct command *cmd,
|
||||
|
||||
psbt = psbt_using_utxos(cmd, cmd->ld->wallet, utxos,
|
||||
*locktime, BITCOIN_TX_RBF_SEQUENCE);
|
||||
|
||||
assert(psbt->version == 2);
|
||||
/* Should we add a change output for the excess? */
|
||||
if (excess_as_change) {
|
||||
struct amount_sat change;
|
||||
@ -401,7 +414,14 @@ fee_calc:
|
||||
psbt_append_output(psbt, NULL, est_fee);
|
||||
/* Add additional weight of fee output */
|
||||
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);
|
||||
json_add_psbt(response, "psbt", psbt);
|
||||
json_add_num(response, "feerate_per_kw", feerate_per_kw);
|
||||
|
@ -614,14 +614,14 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd,
|
||||
struct utxo ***utxos)
|
||||
{
|
||||
*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 bitcoin_outpoint outpoint;
|
||||
|
||||
if (only_inputs && !in_only_inputs(only_inputs, i))
|
||||
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);
|
||||
if (!utxo) {
|
||||
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,
|
||||
struct wallet *w)
|
||||
{
|
||||
assert(psbt->tx->num_outputs == psbt->num_outputs);
|
||||
tal_wally_start();
|
||||
for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) {
|
||||
u32 index;
|
||||
@ -681,8 +680,8 @@ static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt,
|
||||
const u8 *script;
|
||||
struct ext_key ext;
|
||||
|
||||
script = wally_tx_output_get_script(tmpctx,
|
||||
&psbt->tx->outputs[outndx]);
|
||||
script = wally_psbt_output_get_script(tmpctx,
|
||||
&psbt->outputs[outndx]);
|
||||
if (!script)
|
||||
continue;
|
||||
|
||||
@ -735,6 +734,7 @@ static struct command_result *json_signpsbt(struct command *cmd,
|
||||
struct wally_psbt *psbt, *signed_psbt;
|
||||
struct utxo **utxos;
|
||||
u32 *input_nums;
|
||||
u32 psbt_version;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("psbt", param_psbt, &psbt),
|
||||
@ -742,6 +742,15 @@ static struct command_result *json_signpsbt(struct command *cmd,
|
||||
NULL))
|
||||
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! */
|
||||
for (size_t i = 0; i < tal_count(input_nums); i++) {
|
||||
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",
|
||||
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);
|
||||
json_add_psbt(response, "signed_psbt", signed_psbt);
|
||||
return command_success(cmd, response);
|
||||
@ -824,8 +840,8 @@ static void maybe_notify_new_external_send(struct lightningd *ld,
|
||||
return;
|
||||
|
||||
/* If it's going to our wallet, ignore */
|
||||
script = wally_tx_output_get_script(tmpctx,
|
||||
&psbt->tx->outputs[outnum]);
|
||||
script = wally_psbt_output_get_script(tmpctx,
|
||||
&psbt->outputs[outnum]);
|
||||
if (wallet_can_spend(ld->wallet, script, &index, &is_p2sh))
|
||||
return;
|
||||
|
||||
@ -870,6 +886,11 @@ static void sendpsbt_done(struct bitcoind *bitcoind UNUSED,
|
||||
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);
|
||||
|
||||
/* Extract the change output and add it to the DB */
|
||||
|
Loading…
Reference in New Issue
Block a user