mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Merge ElementsProject/elements#1156: [backport] Backport fixes from master to elements-22.x for rc5
37076d7b9dBump version to -rc5 (Pablo Greco)5629cae32bfs: Make compatible with boost 1.78 (Andrew Chow)60b913e341Elements-qt: Correctly display the amount in the sender's wallet after using Send button (Andrea Bonel)872478b1bedocs: describe elements transaction serialization format (#1148) (James Dorfman)dd2d758bc6fixed minor issues found in review (Allen Piscitello)2da7d75ee9removing test that fails due to blinded issuances, which results in incorrect reissuance token ids (Allen Piscitello)420de43c1cremoving code to blind issuances. PSET should be modified to include an option to blind or unblind issuances, defaulting to unblind. (Allen Piscitello) Pull request description: Backport https://github.com/ElementsProject/elements/pull/1150 https://github.com/ElementsProject/elements/pull/1154 and https://github.com/ElementsProject/elements/pull/1148 from master. Backport https://github.com/bitcoin/bitcoin/pull/24104 from Bitcoin Core Bump to -rc5 ACKs for top commit: jamesdorfman: utACK37076d7b9d. delta1: utACK37076d7b9dTree-SHA512: 616322f94c17008cc7fd582203c22b33c73b922269ab33fd13b270f491eda9b30d4f18efa3f7887e247bef46b63c4810f4084e409bea98120702c426a83343a8
This commit is contained in:
commit
433a57a5bd
14 changed files with 673 additions and 111 deletions
|
|
@ -2,7 +2,7 @@ AC_PREREQ([2.69])
|
|||
define(_CLIENT_VERSION_MAJOR, 22)
|
||||
define(_CLIENT_VERSION_MINOR, 0)
|
||||
define(_CLIENT_VERSION_BUILD, 0)
|
||||
define(_CLIENT_VERSION_RC, 4)
|
||||
define(_CLIENT_VERSION_RC, 5)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||
define(_COPYRIGHT_YEAR, 2022)
|
||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||
|
|
|
|||
595
doc/elements-tx-format.md
Normal file
595
doc/elements-tx-format.md
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -386,99 +386,54 @@ BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map<uint32_t, st
|
|||
}
|
||||
|
||||
// Handle issuances
|
||||
if (input.m_issuance_value) {
|
||||
if (!input.m_issuance_value_commitment.IsCommitment() && input.m_issuance_rangeproof.size() == 0 && input.m_issuance_inflation_keys_rangeproof.size() == 0) {
|
||||
CAsset issuance_asset;
|
||||
CAsset reissuance_asset;
|
||||
if (input.m_issuance_value != std::nullopt || input.m_issuance_value_commitment.IsCommitment() || input.m_issuance_inflation_keys_amount != std::nullopt || input.m_issuance_inflation_keys_commitment.IsCommitment()) {
|
||||
CAsset issuance_asset;
|
||||
CAsset reissuance_asset;
|
||||
|
||||
uint256 entropy;
|
||||
if (!input.m_issuance_blinding_nonce.IsNull()) {
|
||||
// Reissuance, use assetEntropy as the asset entropy
|
||||
entropy = input.m_issuance_asset_entropy;
|
||||
} else {
|
||||
// New issuance, make new entropy
|
||||
GenerateAssetEntropy(entropy, input.GetOutPoint(), input.m_issuance_asset_entropy);
|
||||
}
|
||||
uint256 entropy;
|
||||
if (!input.m_issuance_blinding_nonce.IsNull()) {
|
||||
// Reissuance, use assetEntropy as the asset entropy
|
||||
entropy = input.m_issuance_asset_entropy;
|
||||
} else {
|
||||
// New issuance, make new entropy
|
||||
GenerateAssetEntropy(entropy, input.GetOutPoint(), input.m_issuance_asset_entropy);
|
||||
}
|
||||
|
||||
if (input.m_issuance_value != std::nullopt || input.m_issuance_value_commitment.IsCommitment()) {
|
||||
// Asset isn't blinded yet. Add it to the list of input assets
|
||||
CalculateAsset(issuance_asset, entropy);
|
||||
fixed_input_tags.emplace_back();
|
||||
memcpy(fixed_input_tags.back().data, issuance_asset.begin(), 32);
|
||||
ephemeral_input_tags.emplace_back();
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), issuance_asset.begin()) != 1) {
|
||||
return BlindingStatus::INVALID_ASSET;
|
||||
}
|
||||
unsigned int iss_to_blind = 1; // Always do the first issuance blinding iteration for the issuance value
|
||||
|
||||
bool blind_issuance = our_issuances_to_blind.count(i) > 0;
|
||||
|
||||
if (input.m_issuance_blinding_nonce.IsNull() && input.m_issuance_inflation_keys_amount) {
|
||||
// New issuance, do reissuance token things
|
||||
CalculateReissuanceToken(reissuance_asset, entropy, blind_issuance);
|
||||
// Add the reissuance_asset to the list of input assets
|
||||
fixed_input_tags.emplace_back();
|
||||
memcpy(fixed_input_tags.back().data, reissuance_asset.begin(), 32);
|
||||
ephemeral_input_tags.emplace_back();
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), reissuance_asset.begin()) != 1) {
|
||||
if (input.m_issuance_value_commitment.IsNull()) {
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), issuance_asset.begin()) != 1) {
|
||||
return BlindingStatus::INVALID_ASSET;
|
||||
}
|
||||
iss_to_blind++; // If we have a reissuance, do the second blinding iteration for the inflation keys
|
||||
}
|
||||
|
||||
if (blind_issuance) {
|
||||
for (unsigned int blind_i = 0; blind_i < iss_to_blind; ++blind_i) {
|
||||
// To blind an issuance, both the issuance value and the number of inflation keys need to be blinded
|
||||
// Since this process is basically the same for both, do it in a loop and switch based on the index
|
||||
bool blind_value = blind_i == 0; // True for blinding the value, false for blinding the inflation keys
|
||||
CAmount value = blind_value ? *input.m_issuance_value : *input.m_issuance_inflation_keys_amount;
|
||||
CAsset asset = blind_value ? issuance_asset : reissuance_asset;
|
||||
CKey blinding_privkey = blind_value ? our_issuances_to_blind.at(i).first : our_issuances_to_blind.at(i).second;
|
||||
|
||||
uint256 value_blinder;
|
||||
GetStrongRandBytes(value_blinder.begin(), value_blinder.size());
|
||||
|
||||
// Create unblinded generator. Throw away everything except asset_gen
|
||||
uint256 asset_blinder;
|
||||
CConfidentialAsset conf_asset;
|
||||
secp256k1_generator asset_gen;
|
||||
CreateAssetCommitment(conf_asset, asset_gen, asset, asset_blinder);
|
||||
input_asset_blinders.push_back(asset_blinder);
|
||||
|
||||
// Compute the scalar for this blinding and add to the input scalar
|
||||
if (!ComputeAndAddToScalarOffset(input_scalar, value, asset_blinder, value_blinder)) return BlindingStatus::SCALAR_UNABLE;
|
||||
|
||||
// Create value commitment
|
||||
secp256k1_pedersen_commitment value_commit;
|
||||
CConfidentialValue conf_value;
|
||||
CreateValueCommitment(conf_value, value_commit, value_blinder, asset_gen, value);
|
||||
|
||||
// Nonce is the blinding key
|
||||
uint256 nonce = uint256(std::vector<unsigned char>(blinding_privkey.begin(), blinding_privkey.end()));
|
||||
|
||||
// Generate rangeproof
|
||||
std::vector<unsigned char> rangeproof;
|
||||
bool rangeresult = CreateValueRangeProof(rangeproof, value_blinder, nonce, value, CScript(), value_commit, asset_gen, asset, asset_blinder);
|
||||
assert(rangeresult);
|
||||
|
||||
// Create explicit value rangeproofs
|
||||
std::vector<unsigned char> blind_value_proof;
|
||||
rangeresult = CreateBlindValueProof(blind_value_proof, value_blinder, value, value_commit, asset_gen);
|
||||
assert(rangeresult);
|
||||
|
||||
if (blind_value) {
|
||||
input.m_issuance_value_commitment = conf_value;
|
||||
input.m_issuance_rangeproof = rangeproof;
|
||||
input.m_blind_issuance_value_proof = blind_value_proof;
|
||||
} else {
|
||||
input.m_issuance_inflation_keys_commitment = conf_value;
|
||||
input.m_issuance_inflation_keys_rangeproof = rangeproof;
|
||||
input.m_blind_issuance_inflation_keys_proof = blind_value_proof;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
input_asset_blinders.emplace_back();
|
||||
memcpy(ephemeral_input_tags.back().data, input.m_issuance_value_commitment.vchCommitment.data(), 33);
|
||||
}
|
||||
input_asset_blinders.emplace_back();
|
||||
}
|
||||
|
||||
bool blind_issuance = input.m_issuance_value_commitment.IsCommitment();
|
||||
|
||||
if (input.m_issuance_blinding_nonce.IsNull() && (input.m_issuance_inflation_keys_amount != std::nullopt || input.m_issuance_inflation_keys_commitment.IsCommitment())) {
|
||||
// New issuance, do reissuance token things
|
||||
CalculateReissuanceToken(reissuance_asset, entropy, blind_issuance);
|
||||
// Add the reissuance_asset to the list of input assets
|
||||
fixed_input_tags.emplace_back();
|
||||
memcpy(fixed_input_tags.back().data, reissuance_asset.begin(), 32);
|
||||
ephemeral_input_tags.emplace_back();
|
||||
if (input.m_issuance_inflation_keys_commitment.IsNull()) {
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), reissuance_asset.begin()) != 1) {
|
||||
return BlindingStatus::INVALID_ASSET;
|
||||
}
|
||||
}
|
||||
else if(input.m_issuance_inflation_keys_commitment.IsCommitment()){
|
||||
memcpy(ephemeral_input_tags.back().data, input.m_issuance_inflation_keys_commitment.vchCommitment.data(), 33);
|
||||
}
|
||||
input_asset_blinders.emplace_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ struct PartiallySignedTransaction;
|
|||
struct WalletContext;
|
||||
struct bilingual_str;
|
||||
typedef uint8_t isminefilter;
|
||||
struct BlindDetails;
|
||||
|
||||
namespace interfaces {
|
||||
|
||||
|
|
@ -140,13 +141,14 @@ public:
|
|||
bool sign,
|
||||
int& change_pos,
|
||||
CAmount& fee,
|
||||
std::vector<CAmount>& out_amounts,
|
||||
BlindDetails* blind_details,
|
||||
bilingual_str& fail_reason) = 0;
|
||||
|
||||
//! Commit transaction.
|
||||
virtual void commitTransaction(CTransactionRef tx,
|
||||
WalletValueMap value_map,
|
||||
WalletOrderForm order_form) = 0;
|
||||
WalletOrderForm order_form,
|
||||
BlindDetails* blind_details) = 0;
|
||||
|
||||
//! Return whether transaction can be abandoned.
|
||||
virtual bool transactionCanBeAbandoned(const uint256& txid) = 0;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ CMutableTransaction PartiallySignedTransaction::GetUnsignedTx(bool force_unblind
|
|||
txin.assetIssuance.nAmount.SetNull();
|
||||
}
|
||||
if (input.m_issuance_inflation_keys_amount != std::nullopt && (input.m_issuance_inflation_keys_commitment.IsNull() || force_unblinded)) {
|
||||
txin.assetIssuance.nInflationKeys.SetToAmount(*input.m_issuance_value);
|
||||
txin.assetIssuance.nInflationKeys.SetToAmount(*input.m_issuance_inflation_keys_amount);
|
||||
}
|
||||
else if(!input.m_issuance_inflation_keys_commitment.IsNull()) {
|
||||
txin.assetIssuance.nInflationKeys = input.m_issuance_inflation_keys_commitment;
|
||||
|
|
|
|||
|
|
@ -281,11 +281,13 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
|
|||
|
||||
// prepare transaction for getting txFee earlier
|
||||
m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
|
||||
if (g_con_elementsmode)
|
||||
m_current_blind_details = std::make_unique<BlindDetails>();
|
||||
WalletModel::SendCoinsReturn prepareStatus;
|
||||
|
||||
updateCoinControlState();
|
||||
|
||||
prepareStatus = model->prepareTransaction(*m_current_transaction, *m_coin_control);
|
||||
prepareStatus = model->prepareTransaction(*m_current_transaction, m_current_blind_details.get(), *m_coin_control);
|
||||
|
||||
// process prepareStatus and on error generate message shown to user
|
||||
processSendCoinsReturn(prepareStatus,
|
||||
|
|
@ -403,6 +405,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
|
|||
QString question_string, informative_text, detailed_text;
|
||||
if (!PrepareSendText(question_string, informative_text, detailed_text)) return;
|
||||
assert(m_current_transaction);
|
||||
assert(!g_con_elementsmode || m_current_blind_details);
|
||||
|
||||
const QString confirmation = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
|
||||
const QString confirmButtonText = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Create Unsigned") : tr("Sign and send");
|
||||
|
|
@ -461,7 +464,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
|
|||
if (complete) {
|
||||
const CTransactionRef tx = MakeTransactionRef(mtx);
|
||||
m_current_transaction->setWtx(tx);
|
||||
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
|
||||
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction, m_current_blind_details.get());
|
||||
// process sendStatus and on error generate message shown to user
|
||||
processSendCoinsReturn(sendStatus);
|
||||
|
||||
|
|
@ -520,7 +523,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
|
|||
} // msgBox.exec()
|
||||
} else {
|
||||
// now send the prepared transaction
|
||||
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
|
||||
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction, m_current_blind_details.get());
|
||||
// process sendStatus and on error generate message shown to user
|
||||
processSendCoinsReturn(sendStatus);
|
||||
|
||||
|
|
@ -537,11 +540,13 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
|
|||
}
|
||||
fNewRecipientAllowed = true;
|
||||
m_current_transaction.reset();
|
||||
m_current_blind_details.reset();
|
||||
}
|
||||
|
||||
void SendCoinsDialog::clear()
|
||||
{
|
||||
m_current_transaction.reset();
|
||||
m_current_blind_details.reset();
|
||||
|
||||
// Clear coin control settings
|
||||
m_coin_control->UnSelectAll();
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ private:
|
|||
WalletModel *model;
|
||||
std::unique_ptr<CCoinControl> m_coin_control;
|
||||
std::unique_ptr<WalletModelTransaction> m_current_transaction;
|
||||
std::unique_ptr<BlindDetails> m_current_blind_details;
|
||||
bool fNewRecipientAllowed;
|
||||
bool fFeeMinimized;
|
||||
const PlatformStyle *platformStyle;
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ bool WalletModel::validateAddress(const QString &address)
|
|||
return IsValidDestinationString(address.toStdString());
|
||||
}
|
||||
|
||||
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
|
||||
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, BlindDetails *blind_details, const CCoinControl& coinControl)
|
||||
{
|
||||
CAmountMap total;
|
||||
bool fSubtractFeeFromAmount = false;
|
||||
|
|
@ -236,10 +236,13 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
|||
|
||||
auto& newTx = transaction.getWtx();
|
||||
std::vector<CAmount> out_amounts;
|
||||
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, out_amounts, error);
|
||||
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, blind_details, error);
|
||||
transaction.setTransactionFee(nFeeRequired);
|
||||
if (fSubtractFeeFromAmount && newTx) {
|
||||
assert(out_amounts.size() == newTx->vout.size());
|
||||
if(blind_details) {
|
||||
out_amounts = blind_details->o_amounts;
|
||||
assert(out_amounts.size() == newTx->vout.size());
|
||||
}
|
||||
transaction.reassignAmounts(out_amounts, nChangePosRet);
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +269,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
|||
return SendCoinsReturn(OK);
|
||||
}
|
||||
|
||||
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction)
|
||||
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction, BlindDetails *blind_details)
|
||||
{
|
||||
QByteArray transaction_array; /* store serialized transaction */
|
||||
|
||||
|
|
@ -279,7 +282,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
|||
}
|
||||
|
||||
auto& newTx = transaction.getWtx();
|
||||
wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm));
|
||||
wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), blind_details);
|
||||
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << *newTx;
|
||||
|
|
|
|||
|
|
@ -100,10 +100,10 @@ public:
|
|||
};
|
||||
|
||||
// prepare transaction for getting txfee before sending coins
|
||||
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl);
|
||||
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, BlindDetails *blind_details, const CCoinControl& coinControl);
|
||||
|
||||
// Send coins to a list of recipients
|
||||
SendCoinsReturn sendCoins(WalletModelTransaction &transaction);
|
||||
SendCoinsReturn sendCoins(WalletModelTransaction &transaction, BlindDetails *blind_details);
|
||||
|
||||
// Wallet encryption
|
||||
bool setWalletEncrypted(const SecureString& passphrase);
|
||||
|
|
|
|||
|
|
@ -248,26 +248,25 @@ public:
|
|||
bool sign,
|
||||
int& change_pos,
|
||||
CAmount& fee,
|
||||
std::vector<CAmount>& out_amounts,
|
||||
BlindDetails* blind_details,
|
||||
bilingual_str& fail_reason) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
CTransactionRef tx;
|
||||
FeeCalculation fee_calc_out;
|
||||
BlindDetails blind_details;
|
||||
if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos,
|
||||
fail_reason, coin_control, fee_calc_out, sign, gArgs.GetBoolArg("-blindedaddresses", g_con_elementsmode) ? &blind_details : nullptr)) {
|
||||
fail_reason, coin_control, fee_calc_out, sign, blind_details)) {
|
||||
return {};
|
||||
}
|
||||
out_amounts = blind_details.o_amounts;
|
||||
return tx;
|
||||
}
|
||||
void commitTransaction(CTransactionRef tx,
|
||||
WalletValueMap value_map,
|
||||
WalletOrderForm order_form) override
|
||||
WalletOrderForm order_form,
|
||||
BlindDetails* blind_details) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
|
||||
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form), blind_details);
|
||||
}
|
||||
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
|
||||
bool abandonTransaction(const uint256& txid) override
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ bool VerifyWallets(interfaces::Chain& chain)
|
|||
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
|
||||
boost::system::error_code error;
|
||||
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
|
||||
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
|
||||
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error).remove_trailing_separator();
|
||||
if (error || !fs::exists(wallet_dir)) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1921,8 +1921,8 @@ BlindingStatus CWallet::WalletBlindPSBT(PartiallySignedTransaction& psbtx) const
|
|||
our_input_data[i] = std::make_tuple(amount, asset, asset_blinder, value_blinder);
|
||||
}
|
||||
|
||||
// Blind issuances on our inputs
|
||||
if (input.m_issuance_value || input.m_issuance_inflation_keys_amount) {
|
||||
// Blind issuances on our inputs if at least one commitment was provided.
|
||||
if (input.m_issuance_value_commitment.IsCommitment() || input.m_issuance_inflation_keys_commitment.IsCommitment()) {
|
||||
CScript blinding_script(CScript() << OP_RETURN << std::vector<unsigned char>(input.prev_txid.begin(), input.prev_txid.end()) << *input.prev_out);
|
||||
our_issuances_to_blind[i] = std::make_pair(GetBlindingKey(&blinding_script), GetBlindingKey(&blinding_script));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ class SighashRangeproofTest(BitcoinTestFramework):
|
|||
"blind": True, # FIXME: if blind=False, `blindrawtranaction` fails. Should fix this in a future PR
|
||||
}]
|
||||
)[0]["hex"]
|
||||
|
||||
blinded_hex = self.nodes[1].blindrawtransaction(unsigned_hex)
|
||||
blinded_tx = tx_from_hex(blinded_hex)
|
||||
signed_hex = self.nodes[1].signrawtransactionwithwallet(blinded_hex)["hex"]
|
||||
|
|
@ -164,12 +165,13 @@ class SighashRangeproofTest(BitcoinTestFramework):
|
|||
assert test_accept["allowed"], "not accepted: {}".format(test_accept["reject-reason"])
|
||||
|
||||
# Try signing using the PSBT interface
|
||||
psbt_hex = self.nodes[0].converttopsbt(unsigned_hex)
|
||||
signed_psbt = self.nodes[1].walletprocesspsbt(psbt_hex, True, "ALL|RANGEPROOF")
|
||||
extracted_tx = self.nodes[0].finalizepsbt(signed_psbt["psbt"])
|
||||
assert extracted_tx["complete"]
|
||||
test_accept = self.nodes[0].testmempoolaccept([extracted_tx["hex"]])[0]
|
||||
assert test_accept["allowed"], "not accepted: {}".format(test_accept["reject-reason"])
|
||||
if not attach_issuance: # FIXME: We need to skip the issuance since the example assumes it was a blinded issuance, thus the reissuance token is incorrect.
|
||||
psbt_hex = self.nodes[0].converttopsbt(unsigned_hex)
|
||||
signed_psbt = self.nodes[1].walletprocesspsbt(psbt_hex, True, "ALL|RANGEPROOF")
|
||||
extracted_tx = self.nodes[0].finalizepsbt(signed_psbt["psbt"])
|
||||
assert extracted_tx["complete"]
|
||||
test_accept = self.nodes[0].testmempoolaccept([extracted_tx["hex"]])[0]
|
||||
assert test_accept["allowed"], "not accepted: {}".format(test_accept["reject-reason"])
|
||||
else:
|
||||
signed_tx.rehash()
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
|
||||
# should raise rpc error if wallet path can't be created
|
||||
err_code = -4 if self.options.descriptors else -1
|
||||
assert_raises_rpc_error(err_code, "boost::filesystem::create_directory:", self.nodes[0].createwallet, "w8/bad")
|
||||
assert_raises_rpc_error(err_code, "boost::filesystem::create_director", self.nodes[0].createwallet, "w8/bad")
|
||||
|
||||
# check that all requested wallets were created
|
||||
self.stop_node(0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue