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();
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;
}

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
* 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);

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 */
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(); }

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 */
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();

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 *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(); }

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 */
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(); }

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)
{
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);

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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)

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,
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);

View File

@ -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

@ -1 +1 @@
Subproject commit d839dbab4279e1d3d1ece4e52d4766f523b3f7ee
Subproject commit 23e6b626c8906bce2e3179409b938c9ef9bca463

View File

@ -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;

View File

@ -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,

View File

@ -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));

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)
{
/* 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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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())

View File

@ -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"""

View File

@ -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

View File

@ -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);

View File

@ -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 */