Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ec764fd
partial bitcoin#22154: Add OutputType::BECH32M and related wallet sup…
kwvg Aug 17, 2025
9e23b11
merge bitcoin#25218: introduce generic 'Result' class and connect it …
kwvg Aug 17, 2025
50ca8cf
refactor: remove `CKey` overload for `Create{,AndProcess}Block()`
kwvg Aug 17, 2025
03939f2
partial bitcoin#24584: avoid mixing different `OutputTypes` during co…
kwvg Mar 11, 2022
56accfe
merge bitcoin#25721: Replace BResult with util::Result
kwvg Aug 17, 2025
bd897fa
merge bitcoin#25656: return util::Result from `GetReservedDestination…
kwvg Aug 16, 2025
240765e
merge bitcoin#25616: Return `util::Result` from WalletLoader methods
kwvg Aug 16, 2025
f15a1b9
merge bitcoin#26005: Fix error handling (copy_file failure in Restore…
kwvg Sep 4, 2022
0fca914
merge bitcoin#24855: Fix `setwalletflag` disabling of flags
kwvg Apr 14, 2022
c5e8bd6
merge bitcoin#18554: ensure wallet files are not reused across chains
kwvg Aug 17, 2025
c349dad
merge bitcoin#17204: Do not turn OP_1NEGATE in scriptSig into 0x0181 …
kwvg Apr 25, 2018
f883122
merge bitcoin#20562: Test that a fully signed tx given to signrawtx i…
kwvg Dec 3, 2020
4e0725e
merge bitcoin#21166: Introduce DeferredSignatureChecker and have Sign…
kwvg Aug 17, 2025
c6eabc1
merge bitcoin#25044: Use MiniWallet in rpc_rawtransaction.py
kwvg Aug 17, 2025
a118fe1
test: reduce `num_nodes` in `feature_nulldummy.py` to 1
kwvg Aug 17, 2025
c24c9ea
merge bitcoin#25364: remove wallet dependency from feature_nulldummy.py
kwvg Aug 17, 2025
f405790
merge bitcoin#25525: remove wallet dependency from mempool_updatefrom…
kwvg Jul 1, 2022
2a880d8
merge bitcoin#25512: remove wallet dependency and refactor rpc_signra…
kwvg Jun 30, 2022
d63ca8a
merge bitcoin#24678: Prevent wallet unload on GetWalletForJSONRPCRequest
kwvg Aug 17, 2025
c0f9225
merge bitcoin#26747: fix confusing error / GUI crash on cross-chain l…
kwvg Dec 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ BITCOIN_TESTS =\
test/random_tests.cpp \
test/ratecheck_tests.cpp \
test/rest_tests.cpp \
test/result_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
Expand Down Expand Up @@ -214,6 +215,7 @@ BITCOIN_TESTS += \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/wallet_transaction_tests.cpp \
wallet/test/coinselector_tests.cpp \
wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp
Expand Down
6 changes: 3 additions & 3 deletions src/bench/coin_selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ static void CoinSelection(benchmark::Bench& bench)
addCoin(3 * COIN, wallet, wtxs);

// Create coins
std::vector<COutput> coins;
wallet::CoinsResult available_coins;
for (const auto& wtx : wtxs) {
const auto txout = wtx->tx->vout.at(0);
coins.emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
available_coins.legacy.emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
}
const CoinEligibilityFilter filter_standard(1, 6, 0);
FastRandomContext rand{};
Expand All @@ -73,7 +73,7 @@ static void CoinSelection(benchmark::Bench& bench)
/*avoid_partial=*/ false,
};
bench.run([&] {
auto result = AttemptSelection(wallet, 1003 * COIN, filter_standard, coins, coin_selection_params);
auto result = AttemptSelection(wallet, 1003 * COIN, filter_standard, available_coins, coin_selection_params, /*allow_mixed_output_types=*/true);
assert(result);
assert(result->GetSelectedValue() == 1003 * COIN);
assert(result->GetInputSet().size() == 2);
Expand Down
6 changes: 1 addition & 5 deletions src/bench/wallet_loading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,8 @@ static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)

static void AddTx(CWallet& wallet)
{
bilingual_str error;
CTxDestination dest;
wallet.GetNewDestination("", dest, error);

CMutableTransaction mtx;
mtx.vout.push_back({COIN, GetScriptForDestination(dest)});
mtx.vout.push_back({COIN, GetScriptForDestination(*Assert(wallet.GetNewDestination("")))});
mtx.vin.push_back(CTxIn());

wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{});
Expand Down
9 changes: 4 additions & 5 deletions src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
AssertLockHeld(m_wallet->cs_wallet);

CCoinControl coin_control(CoinType::ONLY_COINJOIN_COLLATERAL);
std::vector<COutput> vCoins{AvailableCoinsListUnspent(*m_wallet, &coin_control).coins};
std::vector<COutput> vCoins{AvailableCoinsListUnspent(*m_wallet, &coin_control).all()};
if (vCoins.empty()) {
strReason = strprintf("%s requires a collateral transaction and could not locate an acceptable input!", gCoinJoinName);
return false;
Expand All @@ -1575,11 +1575,10 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
if (txout.nValue >= CoinJoin::GetCollateralAmount() * 2) {
// make our change address
CScript scriptChange;
CTxDestination dest;
ReserveDestination reserveDest(m_wallet.get());
bool success = reserveDest.GetReservedDestination(dest, true);
assert(success); // should never fail, as we just unlocked
scriptChange = GetScriptForDestination(dest);
auto dest_opt = reserveDest.GetReservedDestination(true);
assert(dest_opt); // should never fail, as we just unlocked
scriptChange = GetScriptForDestination(*dest_opt);
reserveDest.KeepDestination();
// return change
txCollateral.vout.emplace_back(txout.nValue - CoinJoin::GetCollateralAmount(), scriptChange);
Expand Down
21 changes: 12 additions & 9 deletions src/coinjoin/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ inline unsigned int GetSizeOfCompactSizeDiff(uint64_t nSizePrev, uint64_t nSizeN
CKeyHolder::CKeyHolder(CWallet* pwallet) :
reserveDestination(pwallet)
{
reserveDestination.GetReservedDestination(dest, false);
auto dest_opt = reserveDestination.GetReservedDestination(false);
assert(dest_opt);
dest = *dest_opt;
}
Comment on lines +32 to 35
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Assert should be replaced with proper error handling

The constructor now uses GetReservedDestination(false) which returns a util::Result. While asserting the result exists works, this could fail in production if the wallet cannot provide addresses (e.g., keypool exhausted). Consider proper error handling instead of assertions.

Consider propagating the error instead of asserting:

-    auto dest_opt = reserveDestination.GetReservedDestination(false);
-    assert(dest_opt);
-    dest = *dest_opt;
+    auto dest_result = reserveDestination.GetReservedDestination(false);
+    if (!dest_result) {
+        throw std::runtime_error(strprintf("CKeyHolder: %s", util::ErrorString(dest_result).original));
+    }
+    dest = *dest_result;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto dest_opt = reserveDestination.GetReservedDestination(false);
assert(dest_opt);
dest = *dest_opt;
}
auto dest_result = reserveDestination.GetReservedDestination(false);
if (!dest_result) {
throw std::runtime_error(strprintf("CKeyHolder: %s", util::ErrorString(dest_result).original));
}
dest = *dest_result;
}
🤖 Prompt for AI Agents
In src/coinjoin/util.cpp around lines 32–35, replace the assert on the result of
GetReservedDestination(false) with proper error handling: check whether dest_opt
contains a value, and if it does, assign dest = *dest_opt; if it does not,
propagate the failure instead of asserting — for example, throw an appropriate
exception (e.g., std::runtime_error) or convert and return a util::Result error
containing dest_opt's error text so callers can handle keypool exhaustion or
other failures gracefully.


void CKeyHolder::KeepKey()
Expand Down Expand Up @@ -99,10 +101,10 @@ CTransactionBuilderOutput::CTransactionBuilderOutput(CTransactionBuilder* pTxBui
nAmount(nAmountIn)
{
assert(pTxBuilder);
CTxDestination txdest;
LOCK(wallet.cs_wallet);
dest.GetReservedDestination(txdest, false);
script = ::GetScriptForDestination(txdest);
auto dest_opt = dest.GetReservedDestination(false);
assert(dest_opt);
script = ::GetScriptForDestination(*dest_opt);
}
Comment on lines +105 to 108
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Another assertion that should handle errors gracefully

Similar to the CKeyHolder constructor, this assertion could fail if the wallet cannot provide addresses. The code should handle this error case properly.

Consider proper error handling:

-    auto dest_opt = dest.GetReservedDestination(false);
-    assert(dest_opt);
-    script = ::GetScriptForDestination(*dest_opt);
+    auto dest_result = dest.GetReservedDestination(false);
+    if (!dest_result) {
+        throw std::runtime_error(strprintf("CTransactionBuilderOutput: %s", util::ErrorString(dest_result).original));
+    }
+    script = ::GetScriptForDestination(*dest_result);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto dest_opt = dest.GetReservedDestination(false);
assert(dest_opt);
script = ::GetScriptForDestination(*dest_opt);
}
auto dest_result = dest.GetReservedDestination(false);
if (!dest_result) {
throw std::runtime_error(strprintf(
"CTransactionBuilderOutput: %s", util::ErrorString(dest_result).original));
}
script = ::GetScriptForDestination(*dest_result);
}
🤖 Prompt for AI Agents
In src/coinjoin/util.cpp around lines 105 to 108, replace the bare assert on
dest_opt with proper runtime error handling like the CKeyHolder constructor:
check if dest_opt is set, and if not, log an error with context (including any
relevant wallet/address info) and return an appropriate failure (e.g., return
false/empty optional or throw a descriptive exception depending on surrounding
function semantics) instead of asserting; only call
::GetScriptForDestination(*dest_opt) when dest_opt is valid so the failure is
handled gracefully.


bool CTransactionBuilderOutput::UpdateAmount(const CAmount nNewAmount)
Expand Down Expand Up @@ -280,12 +282,13 @@ bool CTransactionBuilder::Commit(bilingual_str& strResult)
CTransactionRef tx;
{
LOCK2(m_wallet.cs_wallet, ::cs_main);
FeeCalculation fee_calc_out;
if (auto txr = wallet::CreateTransaction(m_wallet, vecSend, nChangePosRet, strResult, coinControl, fee_calc_out)) {
tx = txr->tx;
nFeeRet = txr->fee;
nChangePosRet = txr->change_pos;
auto ret = wallet::CreateTransaction(m_wallet, vecSend, nChangePosRet, coinControl);
if (ret) {
tx = ret->tx;
nFeeRet = ret->fee;
nChangePosRet = ret->change_pos;
} else {
strResult = util::ErrorString(ret);
return false;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/dummywallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
"-flushwallet",
"-privdb",
"-walletrejectlongchains",
"-unsafesqlitesync"
"-walletcrosschain",
"-unsafesqlitesync",
});
}

Expand Down
49 changes: 24 additions & 25 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class Wallet
virtual std::string getWalletName() = 0;

// Get a new address.
virtual bool getNewDestination(const std::string label, CTxDestination& dest) = 0;
virtual util::Result<CTxDestination> getNewDestination(const std::string& label) = 0;

//! Get public key.
virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0;
Expand Down Expand Up @@ -167,12 +167,11 @@ class Wallet
virtual std::vector<COutPoint> listProTxCoins() = 0;

//! Create transaction.
virtual CTransactionRef createTransaction(const std::vector<wallet::CRecipient>& recipients,
virtual util::Result<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
const wallet::CCoinControl& coin_control,
bool sign,
int& change_pos,
CAmount& fee,
bilingual_str& fail_reason) = 0;
CAmount& fee) = 0;

//! Commit transaction.
virtual void commitTransaction(CTransactionRef tx,
Expand Down Expand Up @@ -348,35 +347,35 @@ class Wallet
class WalletLoader : public ChainClient
{
public:
//! Register non-core wallet RPCs
virtual void registerOtherRpcs(const Span<const CRPCCommand>& commands) = 0;
//! Register non-core wallet RPCs
virtual void registerOtherRpcs(const Span<const CRPCCommand>& commands) = 0;

//! Create new wallet.
virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
//! Create new wallet.
virtual util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) = 0;

//! Load existing wallet.
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
//! Load existing wallet.
virtual util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) = 0;

//! Return default wallet directory.
virtual std::string getWalletDir() = 0;
//! Return default wallet directory.
virtual std::string getWalletDir() = 0;

//! Restore backup wallet
virtual BResult<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
//! Restore backup wallet
virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;

//! Return available wallets in wallet directory.
virtual std::vector<std::string> listWalletDir() = 0;
//! Return available wallets in wallet directory.
virtual std::vector<std::string> listWalletDir() = 0;

//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;

//! Register handler for load wallet messages. This callback is triggered by
//! createWallet and loadWallet above, and also triggered when wallets are
//! loaded at startup or by RPC.
using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
//! Register handler for load wallet messages. This callback is triggered by
//! createWallet and loadWallet above, and also triggered when wallets are
//! loaded at startup or by RPC.
using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;

//! Return pointer to internal context, useful for testing.
virtual wallet::WalletContext* context() { return nullptr; }
//! Return pointer to internal context, useful for testing.
virtual wallet::WalletContext* context() { return nullptr; }
};
Comment on lines +350 to 379
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

WalletLoader methods migrated to util::Result — good, but verify call sites are updated

The create/load/restore methods now return util::Result and drop the error out-param. This ripples through GUI/RPC. Please verify there are no remaining callers expecting the old signatures.

Run this script to catch old-style usages (extra args/out-params):


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for old getNewDestination usages (with extra out-params)..."
rg -nP --type=cpp -C2 '\b(getNewDestination|GetNewDestination)\s*\(\s*[^,()]+\s*,\s*[^)]' || true

echo
echo "Searching for old createTransaction usages (fail_reason out-param or boolean return)..."
# Look for calls passing a bilingual_str or expecting bool
rg -nP --type=cpp -C3 '\bcreateTransaction\s*\(' || true
rg -nP --type=cpp -C2 'bilingual_str\s+\w+\s*;.*\bcreateTransaction\s*\(' || true

echo
echo "Searching for WalletLoader old create/load/restore signatures..."
rg -nP --type=cpp -C2 '\.createWallet\s*\([^)]{60,}\)' || true
rg -nP --type=cpp -C2 '\.loadWallet\s*\([^)]{60,}\)' || true
rg -nP --type=cpp -C2 '\.restoreWallet\s*\([^)]{60,}\)' || true

Length of output: 2428


Fix outdated createTransaction usage in Qt WalletModel

We confirmed there are no remaining old-style calls to getNewDestination or to the migrated createWallet/loadWallet/restoreWallet APIs. However, the Qt UI still invokes the legacy createTransaction signature with both change_pos and fee out-params. Please update it to the new util::Result<CTransactionRef> API (which no longer takes a fee out-param) and handle the returned Result.

• src/qt/walletmodel.cpp:257
replace

const auto& res = m_wallet->createTransaction(
    vecSend, coinControl, !wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);

with a call matching the interface’s new signature (e.g. passing only vecSend, coinControl, sign, nChangePosRet), then unpack res to obtain both the transaction and fee.

🤖 Prompt for AI Agents
In src/qt/walletmodel.cpp around line 257, the code still calls the legacy
createTransaction that returned both change_pos and fee via out-params; update
the call to the new signature that returns util::Result<CTransactionRef> (pass
vecSend, coinControl, sign flag, and nChangePosRet only), capture the
util::Result, check for and handle errors before proceeding, and then unpack the
successful Result to obtain the CTransactionRef and the fee value and replace
uses of the old nFeeRequired out-param with the fee extracted from the Result.


//! Information about one wallet address.
Expand Down
14 changes: 6 additions & 8 deletions src/qt/addresstablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,23 +366,21 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
else if(type == Receive)
{
// Generate a new address to associate with given label
CTxDestination dest;
if(!walletModel->wallet().getNewDestination(strLabel, dest))
{
auto op_dest = walletModel->wallet().getNewDestination(strLabel);
if (!op_dest) {
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
if(!ctx.isValid())
{
if (!ctx.isValid()) {
// Unlock wallet failed or was cancelled
editStatus = WALLET_UNLOCK_FAILURE;
return QString();
}
if(!walletModel->wallet().getNewDestination(strLabel, dest))
{
op_dest = walletModel->wallet().getNewDestination(strLabel);
if (!op_dest) {
editStatus = KEY_GENERATION_FAILURE;
return QString();
}
}
strAddress = EncodeDestination(dest);
strAddress = EncodeDestination(*op_dest);
}
else
{
Expand Down
23 changes: 17 additions & 6 deletions src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,13 @@ void CreateWalletActivity::createWallet()
}

QTimer::singleShot(500ms, worker(), [this, name, flags] {
std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
auto wallet{node().walletLoader().createWallet(name, m_passphrase, flags, m_warning_message)};

if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
if (wallet) {
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
} else {
m_error_message = util::ErrorString(wallet);
}

QTimer::singleShot(500ms, this, &CreateWalletActivity::finish);
});
Expand Down Expand Up @@ -330,9 +334,13 @@ void OpenWalletActivity::open(const std::string& path)
tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));

QTimer::singleShot(0, worker(), [this, path] {
std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().loadWallet(path, m_error_message, m_warning_message);
auto wallet{node().walletLoader().loadWallet(path, m_warning_message)};

if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
if (wallet) {
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
} else {
m_error_message = util::ErrorString(wallet);
}

QTimer::singleShot(0, this, &OpenWalletActivity::finish);
});
Expand Down Expand Up @@ -375,8 +383,11 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)};

m_error_message = wallet ? bilingual_str{} : wallet.GetError();
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(wallet.ReleaseObj());
if (wallet) {
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
} else {
m_error_message = util::ErrorString(wallet);
}

QTimer::singleShot(0, this, &RestoreWalletActivity::finish);
});
Expand Down
6 changes: 3 additions & 3 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
}

CAmount nFeeRequired = 0;
bilingual_str error;
int nChangePosRet = -1;

auto& newTx = transaction.getWtx();
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired);
newTx = res ? *res : nullptr;
transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet);
Expand All @@ -266,7 +266,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
Q_EMIT message(tr("Send Coins"), QString::fromStdString(error.translated),
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
Expand Down
13 changes: 5 additions & 8 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ static void FundSpecialTx(CWallet& wallet, CMutableTransaction& tx, const Specia
coinControl.destChange = fundDest;
coinControl.fRequireAllInputs = false;

for (const auto& out : AvailableCoinsListUnspent(wallet).coins) {
for (const auto& out : AvailableCoinsListUnspent(wallet).all()) {
CTxDestination txDest;
if (ExtractDestination(out.txout.scriptPubKey, txDest) && txDest == fundDest) {
coinControl.Select(out.outpoint);
Expand All @@ -281,15 +281,12 @@ static void FundSpecialTx(CWallet& wallet, CMutableTransaction& tx, const Specia
throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("No funds at specified address %s", EncodeDestination(fundDest)));
}

bilingual_str strFailReason;
FeeCalculation fee_calc_out;
auto txr = CreateTransaction(wallet, vecSend, RANDOM_CHANGE_POSITION, strFailReason, coinControl, fee_calc_out,
true, tx.vExtraPayload.size());
if (!txr) {
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason.original);
auto res = CreateTransaction(wallet, vecSend, RANDOM_CHANGE_POSITION, coinControl, /*sign=*/true, tx.vExtraPayload.size());
if (!res) {
throw JSONRPCError(RPC_INTERNAL_ERROR, util::ErrorString(res).original);
}
CTransactionRef newTx = txr->tx;

const CTransactionRef& newTx = res->tx;
tx.vin = newTx->vin;
tx.vout = newTx->vout;

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ static RPCHelpMan masternode_outputs()
CCoinControl coin_control(CoinType::ONLY_MASTERNODE_COLLATERAL);

UniValue outputsArr(UniValue::VARR);
for (const auto& out : WITH_LOCK(wallet->cs_wallet, return AvailableCoinsListUnspent(*wallet, &coin_control).coins)) {
for (const auto& out : WITH_LOCK(wallet->cs_wallet, return AvailableCoinsListUnspent(*wallet, &coin_control).all())) {
outputsArr.push_back(out.outpoint.ToStringShort());
}

Expand Down
22 changes: 22 additions & 0 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,28 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;

class DeferringSignatureChecker : public BaseSignatureChecker
{
protected:
BaseSignatureChecker& m_checker;

public:
DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}

bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
{
return m_checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion);
}
bool CheckLockTime(const CScriptNum& nLockTime) const override
{
return m_checker.CheckLockTime(nLockTime);
}
bool CheckSequence(const CScriptNum& nSequence) const override
{
return m_checker.CheckSequence(nSequence);
}
};

bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);

Expand Down
Loading
Loading