diff --git a/bitcoin/chainparams.h b/bitcoin/chainparams.h index 40a6ea8fa..eade2344b 100644 --- a/bitcoin/chainparams.h +++ b/bitcoin/chainparams.h @@ -9,6 +9,8 @@ #include #include +#define ELEMENTS_ASSET_LEN 33 + struct chainparams { const char *network_name; const char *bip173_name; diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 7e59a940d..62e3f3522 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -267,6 +267,16 @@ bool psbt_input_set_partial_sig(struct wally_psbt *psbt, size_t in, sizeof(sig->s.data)) == WALLY_OK; } +static void psbt_input_set_witness_utxo(struct wally_psbt *psbt, size_t in, + struct wally_tx_output *txout) +{ + int wally_err; + assert(psbt->num_inputs > in); + wally_err = wally_psbt_input_set_witness_utxo(&psbt->inputs[in], + txout); + assert(wally_err == WALLY_OK); +} + void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, const u8 *scriptPubkey, struct amount_sat amt) { @@ -274,7 +284,6 @@ void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, int wally_err; u8 *scriptpk; - assert(psbt->num_inputs > in); if (scriptPubkey) { assert(is_p2wsh(scriptPubkey, NULL) || is_p2wpkh(scriptPubkey, NULL) || is_p2sh(scriptPubkey, NULL)); @@ -293,10 +302,34 @@ void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, tal_bytelen(scriptpk), &prev_out); assert(wally_err == WALLY_OK); - wally_err = wally_psbt_input_set_witness_utxo(&psbt->inputs[in], - prev_out); + psbt_input_set_witness_utxo(psbt, in, prev_out); +} + +static void psbt_input_set_elements_prev_utxo(struct wally_psbt *psbt, + size_t in, + const u8 *scriptPubkey, + struct amount_asset *asset, + const u8 *nonce) +{ + struct wally_tx_output *prev_out; + int wally_err; + + u8 *prefixed_value = amount_asset_extract_value(psbt, asset); + + wally_err = + wally_tx_elements_output_init_alloc(scriptPubkey, + tal_bytelen(scriptPubkey), + asset->asset, + sizeof(asset->asset), + prefixed_value, + tal_bytelen(prefixed_value), + nonce, + tal_bytelen(nonce), + NULL, 0, + NULL, 0, + &prev_out); assert(wally_err == WALLY_OK); - tal_steal(psbt, psbt->inputs[in].witness_utxo); + psbt_input_set_witness_utxo(psbt, in, prev_out); } void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in, @@ -316,6 +349,76 @@ void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in, psbt_input_set_prev_utxo(psbt, in, scriptPubkey, amt); } +static void +psbt_input_set_elements_prev_utxo_wscript(struct wally_psbt *psbt, + size_t in, + const u8 *wscript, + struct amount_asset *asset, + const u8 *nonce) +{ + int wally_err; + const u8 *scriptPubkey; + + if (wscript) { + scriptPubkey = scriptpubkey_p2wsh(psbt, wscript); + wally_err = wally_psbt_input_set_witness_script( + &psbt->inputs[in], + cast_const(u8 *, wscript), + tal_bytelen(wscript)); + assert(wally_err == WALLY_OK); + } else + scriptPubkey = NULL; + + psbt_input_set_elements_prev_utxo(psbt, in, scriptPubkey, + asset, nonce); +} + +void psbt_elements_input_init_witness(struct wally_psbt *psbt, size_t in, + const u8 *witscript, + struct amount_asset *asset, + const u8 *nonce) +{ + psbt_input_set_elements_prev_utxo_wscript( + psbt, in, witscript, + asset, nonce); + + if (asset->value > 0) + wally_psbt_elements_input_set_value(&psbt->inputs[in], + asset->value); + + /* PSET expects an asset tag without the prefix */ + if (wally_psbt_elements_input_set_asset(&psbt->inputs[in], + asset->asset + 1, + ELEMENTS_ASSET_LEN - 1) != WALLY_OK) + abort(); +} + +void psbt_elements_input_init(struct wally_psbt *psbt, size_t in, + const u8 *scriptPubkey, + struct amount_asset *asset, + const u8 *nonce) +{ + psbt_input_set_elements_prev_utxo(psbt, in, + scriptPubkey, + asset, nonce); + + if (asset->value > 0) { + if (wally_psbt_elements_input_set_value( + &psbt->inputs[in], + asset->value) != WALLY_OK) + abort(); + + } + + /* PSET expects an asset tag without the prefix */ + /* FIXME: Verify that we're sending unblinded asset tag */ + if (wally_psbt_elements_input_set_asset( + &psbt->inputs[in], + asset->asset + 1, + ELEMENTS_ASSET_LEN - 1) != WALLY_OK) + abort(); +} + bool psbt_input_set_redeemscript(struct wally_psbt *psbt, size_t in, const u8 *redeemscript) { @@ -333,7 +436,10 @@ struct amount_sat psbt_input_get_amount(struct wally_psbt *psbt, struct amount_sat val; assert(in < psbt->num_inputs); if (psbt->inputs[in].witness_utxo) { - val.satoshis = psbt->inputs[in].witness_utxo->satoshi; /* Raw: type conversion */ + struct amount_asset amt_asset = + wally_tx_output_get_amount(psbt->inputs[in].witness_utxo); + assert(amount_asset_is_main(&amt_asset)); + val = amount_asset_to_sat(&amt_asset); } else if (psbt->inputs[in].non_witness_utxo) { int idx = psbt->tx->inputs[in].index; struct wally_tx *prev_tx = psbt->inputs[in].non_witness_utxo; diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 1282e41a2..c47f185b1 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -10,6 +10,7 @@ struct wally_tx_output; struct wally_psbt; struct wally_psbt_input; struct wally_tx; +struct amount_asset; struct amount_sat; struct bitcoin_signature; struct pubkey; @@ -55,10 +56,21 @@ WARN_UNUSED_RESULT bool psbt_input_set_partial_sig(struct wally_psbt *psbt, size const struct pubkey *pubkey, const struct bitcoin_signature *sig); -void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, - const u8 *wscript, struct amount_sat amt); +void psbt_input_set_prev_utxo(struct wally_psbt *psbt, + size_t in, + const u8 *wscript, + struct amount_sat amt); void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in, - const u8 *wscript, struct amount_sat amt); + const u8 *wscript, + struct amount_sat amt); +void psbt_elements_input_init(struct wally_psbt *psbt, size_t in, + const u8 *scriptPubkey, + struct amount_asset *asset, + const u8 *nonce); +void psbt_elements_input_init_witness(struct wally_psbt *psbt, size_t in, + const u8 *witscript, + struct amount_asset *asset, + const u8 *nonce); bool psbt_input_set_redeemscript(struct wally_psbt *psbt, size_t in, const u8 *redeemscript); struct amount_sat psbt_input_get_amount(struct wally_psbt *psbt, diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 375a4a203..7265ff6d5 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -207,18 +207,51 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid, if (input_wscript) { /* Add the prev output's data into the PSBT struct */ - psbt_input_set_prev_utxo_wscript(tx->psbt, i, input_wscript, amount); + if (is_elements(chainparams)) { + struct amount_asset asset; + /*FIXME: persist asset tags */ + asset = amount_sat_to_asset( + &amount, + chainparams->fee_asset_tag); + psbt_elements_input_init_witness(tx->psbt, i, + input_wscript, + &asset, NULL); + } else + psbt_input_set_prev_utxo_wscript(tx->psbt, i, + input_wscript, + amount); } else if (scriptPubkey) { - if (is_p2wsh(scriptPubkey, NULL) || is_p2wpkh(scriptPubkey, NULL) || - /* FIXME: assert that p2sh inputs are witness/are accompanied by a redeemscript+witnessscript */ + if (is_p2wsh(scriptPubkey, NULL) || + is_p2wpkh(scriptPubkey, NULL) || + /* FIXME: assert that p2sh inputs are + * witness/are accompanied by a + * redeemscript+witnessscript */ is_p2sh(scriptPubkey, NULL)) { - /* the only way to get here currently with a p2sh script is via a p2sh-p2wpkh script + /* the only way to get here currently with + * a p2sh script is via a p2sh-p2wpkh script * that we've created ...*/ - /* Relevant section from bip-0174, emphasis mine: - * ** Value: The entire transaction output in network serialization which the current input spends from. - * This should only be present for inputs which spend segwit outputs, _including P2SH embedded ones._ + /* BIP0174: + * ** Value: The entire transaction output in + * network serialization which the + * current input spends from. + * This should only be present for + * inputs which spend segwit outputs, + * including P2SH embedded ones. */ - psbt_input_set_prev_utxo(tx->psbt, i, scriptPubkey, amount); + if (is_elements(chainparams)) { + struct amount_asset asset; + /*FIXME: persist asset tags */ + asset = amount_sat_to_asset( + &amount, + chainparams->fee_asset_tag); + /* FIXME: persist nonces */ + psbt_elements_input_init(tx->psbt, i, + scriptPubkey, + &asset, NULL); + } else + psbt_input_set_prev_utxo(tx->psbt, i, + scriptPubkey, + amount); } } @@ -722,10 +755,9 @@ wally_tx_output_get_amount(const struct wally_tx_output *output) if (chainparams->is_elements) { assert(output->asset_len == sizeof(amount.asset)); memcpy(&amount.asset, output->asset, sizeof(amount.asset)); - - /* We currently only support explicit value asset tags, others - * are confidential, so don't even try to assign a value to - * it. */ + /* We currently only support explicit value + * asset tags, others are confidential, so + * don't even try to assign a value to it. */ if (output->asset[0] == 0x01) { memcpy(&raw, output->value + 1, sizeof(raw)); amount.value = be64_to_cpu(raw); diff --git a/wallet/db.c b/wallet/db.c index c97d2e08b..5ef666b0e 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1165,9 +1165,18 @@ void migrate_last_tx_to_psbt(struct lightningd *ld, struct db *db) funding_wscript = bitcoin_redeem_2of2(stmt, &local_funding_pubkey, &remote_funding_pubkey); - psbt_input_set_prev_utxo_wscript(last_tx->psbt, - 0, funding_wscript, - funding_sat); + if (is_elements(chainparams)) { + /*FIXME: persist asset tags */ + struct amount_asset asset; + asset = amount_sat_to_asset(&funding_sat, + chainparams->fee_asset_tag); + psbt_elements_input_init_witness(last_tx->psbt, + 0, funding_wscript, + &asset, NULL); + } else + psbt_input_set_prev_utxo_wscript(last_tx->psbt, + 0, funding_wscript, + funding_sat); if (!db_column_signature(stmt, 5, &last_sig.s)) abort();