mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
merge bitcoin#10973: separate wallet from node
This commit is contained in:
parent
71b90dad97
commit
438c93bd9a
@ -226,6 +226,7 @@ BITCOIN_CORE_H = \
|
|||||||
netbase.h \
|
netbase.h \
|
||||||
netfulfilledman.h \
|
netfulfilledman.h \
|
||||||
netmessagemaker.h \
|
netmessagemaker.h \
|
||||||
|
node/coin.h \
|
||||||
node/coinstats.h \
|
node/coinstats.h \
|
||||||
node/transaction.h \
|
node/transaction.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
@ -386,6 +387,7 @@ libdash_server_a_SOURCES = \
|
|||||||
net.cpp \
|
net.cpp \
|
||||||
netfulfilledman.cpp \
|
netfulfilledman.cpp \
|
||||||
net_processing.cpp \
|
net_processing.cpp \
|
||||||
|
node/coin.cpp \
|
||||||
node/coinstats.cpp \
|
node/coinstats.cpp \
|
||||||
node/transaction.cpp \
|
node/transaction.cpp \
|
||||||
noui.cpp \
|
noui.cpp \
|
||||||
|
@ -22,12 +22,7 @@ struct WalletTestingSetup {
|
|||||||
|
|
||||||
void handleNotifications()
|
void handleNotifications()
|
||||||
{
|
{
|
||||||
RegisterValidationInterface(&m_wallet);
|
m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
|
||||||
}
|
|
||||||
|
|
||||||
~WalletTestingSetup()
|
|
||||||
{
|
|
||||||
UnregisterValidationInterface(&m_wallet);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,21 +7,28 @@
|
|||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <coinjoin/coinjoin.h>
|
#include <coinjoin/coinjoin.h>
|
||||||
|
#include <interfaces/handler.h>
|
||||||
#include <interfaces/wallet.h>
|
#include <interfaces/wallet.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#include <node/coin.h>
|
||||||
#include <policy/fees.h>
|
#include <policy/fees.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <protocol.h>
|
#include <protocol.h>
|
||||||
|
#include <rpc/protocol.h>
|
||||||
|
#include <rpc/server.h>
|
||||||
|
#include <shutdown.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <threadsafety.h>
|
#include <threadsafety.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
#include <univalue.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
#include <validationinterface.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -175,6 +182,94 @@ class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
|
|||||||
using UniqueLock::UniqueLock;
|
using UniqueLock::UniqueLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NotificationsHandlerImpl : public Handler, CValidationInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
|
||||||
|
: m_chain(chain), m_notifications(¬ifications)
|
||||||
|
{
|
||||||
|
RegisterValidationInterface(this);
|
||||||
|
}
|
||||||
|
~NotificationsHandlerImpl() override { disconnect(); }
|
||||||
|
void disconnect() override
|
||||||
|
{
|
||||||
|
if (m_notifications) {
|
||||||
|
m_notifications = nullptr;
|
||||||
|
UnregisterValidationInterface(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override
|
||||||
|
{
|
||||||
|
m_notifications->TransactionAddedToMempool(tx, nAcceptTime);
|
||||||
|
}
|
||||||
|
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override
|
||||||
|
{
|
||||||
|
m_notifications->TransactionRemovedFromMempool(tx, reason);
|
||||||
|
}
|
||||||
|
void BlockConnected(const std::shared_ptr<const CBlock>& block,
|
||||||
|
const CBlockIndex* index,
|
||||||
|
const std::vector<CTransactionRef>& tx_conflicted) override
|
||||||
|
{
|
||||||
|
m_notifications->BlockConnected(*block, tx_conflicted);
|
||||||
|
}
|
||||||
|
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindexDisconnected) override
|
||||||
|
{
|
||||||
|
m_notifications->BlockDisconnected(*block);
|
||||||
|
}
|
||||||
|
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
|
||||||
|
void ResendWalletTransactions(int64_t best_block_time, CConnman*) override
|
||||||
|
{
|
||||||
|
// `cs_main` is always held when this method is called, so it is safe to
|
||||||
|
// call `assumeLocked`. This is awkward, and the `assumeLocked` method
|
||||||
|
// should be able to be removed entirely if `ResendWalletTransactions`
|
||||||
|
// is replaced by a wallet timer as suggested in
|
||||||
|
// https://github.com/bitcoin/bitcoin/issues/15619
|
||||||
|
auto locked_chain = m_chain.assumeLocked();
|
||||||
|
m_notifications->ResendWalletTransactions(*locked_chain, best_block_time);
|
||||||
|
}
|
||||||
|
Chain& m_chain;
|
||||||
|
Chain::Notifications* m_notifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RpcHandlerImpl : public Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
|
||||||
|
{
|
||||||
|
m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
|
||||||
|
if (!m_wrapped_command) return false;
|
||||||
|
try {
|
||||||
|
return m_wrapped_command->actor(request, result, last_handler);
|
||||||
|
} catch (const UniValue& e) {
|
||||||
|
// If this is not the last handler and a wallet not found
|
||||||
|
// exception was thrown, return false so the next handler can
|
||||||
|
// try to handle the request. Otherwise, reraise the exception.
|
||||||
|
if (!last_handler) {
|
||||||
|
const UniValue& code = e["code"];
|
||||||
|
if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
::tableRPC.appendCommand(m_command.name, &m_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect() override final
|
||||||
|
{
|
||||||
|
if (m_wrapped_command) {
|
||||||
|
m_wrapped_command = nullptr;
|
||||||
|
::tableRPC.removeCommand(m_command.name, &m_command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RpcHandlerImpl() override { disconnect(); }
|
||||||
|
|
||||||
|
CRPCCommand m_command;
|
||||||
|
const CRPCCommand* m_wrapped_command;
|
||||||
|
};
|
||||||
|
|
||||||
class ChainImpl : public Chain
|
class ChainImpl : public Chain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -208,6 +303,7 @@ public:
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
|
||||||
double guessVerificationProgress(const uint256& block_hash) override
|
double guessVerificationProgress(const uint256& block_hash) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@ -254,17 +350,33 @@ public:
|
|||||||
{
|
{
|
||||||
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
|
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
|
||||||
}
|
}
|
||||||
|
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
|
||||||
|
CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
|
||||||
|
CFeeRate relayDustFee() override { return ::dustRelayFee; }
|
||||||
CAmount maxTxFee() override { return ::maxTxFee; }
|
CAmount maxTxFee() override { return ::maxTxFee; }
|
||||||
bool getPruneMode() override { return ::fPruneMode; }
|
bool getPruneMode() override { return ::fPruneMode; }
|
||||||
bool p2pEnabled() override { return g_connman != nullptr; }
|
bool p2pEnabled() override { return g_connman != nullptr; }
|
||||||
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
|
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
|
||||||
|
bool shutdownRequested() override { return ShutdownRequested(); }
|
||||||
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
|
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
|
||||||
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
||||||
void initWarning(const std::string& message) override { InitWarning(message); }
|
void initWarning(const std::string& message) override { InitWarning(message); }
|
||||||
void initError(const std::string& message) override { InitError(message); }
|
void initError(const std::string& message) override { InitError(message); }
|
||||||
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
|
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
|
||||||
|
void showProgress(const std::string& title, int progress, bool resume_possible) override
|
||||||
|
{
|
||||||
|
::uiInterface.ShowProgress(title, progress, resume_possible);
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
|
||||||
|
{
|
||||||
|
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
||||||
|
}
|
||||||
|
void waitForNotifications() override { SyncWithValidationInterfaceQueue(); }
|
||||||
|
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
|
||||||
|
{
|
||||||
|
return MakeUnique<RpcHandlerImpl>(command);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
|
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
|
||||||
|
@ -15,18 +15,28 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class CBlock;
|
class CBlock;
|
||||||
|
class CRPCCommand;
|
||||||
class CScheduler;
|
class CScheduler;
|
||||||
class CValidationState;
|
class CValidationState;
|
||||||
class CFeeRate;
|
class CFeeRate;
|
||||||
|
class CBlockIndex;
|
||||||
|
class Coin;
|
||||||
class uint256;
|
class uint256;
|
||||||
struct CBlockLocator;
|
struct CBlockLocator;
|
||||||
struct FeeCalculation;
|
struct FeeCalculation;
|
||||||
|
enum class MemPoolRemovalReason;
|
||||||
|
|
||||||
|
namespace llmq {
|
||||||
|
class CChainLockSig;
|
||||||
|
class CInstantSendLock;
|
||||||
|
} // namespace llmq
|
||||||
|
|
||||||
typedef std::shared_ptr<const CTransaction> CTransactionRef;
|
typedef std::shared_ptr<const CTransaction> CTransactionRef;
|
||||||
|
|
||||||
namespace interfaces {
|
namespace interfaces {
|
||||||
|
|
||||||
class Wallet;
|
class Wallet;
|
||||||
|
class Handler;
|
||||||
|
|
||||||
//! Interface for giving wallet processes access to blockchain state.
|
//! Interface for giving wallet processes access to blockchain state.
|
||||||
class Chain
|
class Chain
|
||||||
@ -140,6 +150,11 @@ public:
|
|||||||
int64_t* time = nullptr,
|
int64_t* time = nullptr,
|
||||||
int64_t* max_time = nullptr) = 0;
|
int64_t* max_time = nullptr) = 0;
|
||||||
|
|
||||||
|
//! Look up unspent output information. Returns coins in the mempool and in
|
||||||
|
//! the current chain UTXO set. Iterates through all the keys in the map and
|
||||||
|
//! populates the values.
|
||||||
|
virtual void findCoins(std::map<COutPoint, Coin>& coins) = 0;
|
||||||
|
|
||||||
//! Estimate fraction of total transactions verified if blocks up to
|
//! Estimate fraction of total transactions verified if blocks up to
|
||||||
//! the specified block hash are verified.
|
//! the specified block hash are verified.
|
||||||
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
|
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
|
||||||
@ -165,6 +180,15 @@ public:
|
|||||||
//! Pool min fee.
|
//! Pool min fee.
|
||||||
virtual CFeeRate mempoolMinFee() = 0;
|
virtual CFeeRate mempoolMinFee() = 0;
|
||||||
|
|
||||||
|
//! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
|
||||||
|
virtual CFeeRate relayMinFee() = 0;
|
||||||
|
|
||||||
|
//! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
|
||||||
|
virtual CFeeRate relayIncrementalFee() = 0;
|
||||||
|
|
||||||
|
//! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
|
||||||
|
virtual CFeeRate relayDustFee() = 0;
|
||||||
|
|
||||||
//! Get node max tx fee setting (-maxtxfee).
|
//! Get node max tx fee setting (-maxtxfee).
|
||||||
//! This could be replaced by a per-wallet max fee, as proposed at
|
//! This could be replaced by a per-wallet max fee, as proposed at
|
||||||
//! https://github.com/bitcoin/bitcoin/issues/15355
|
//! https://github.com/bitcoin/bitcoin/issues/15355
|
||||||
@ -177,9 +201,12 @@ public:
|
|||||||
//! Check if p2p enabled.
|
//! Check if p2p enabled.
|
||||||
virtual bool p2pEnabled() = 0;
|
virtual bool p2pEnabled() = 0;
|
||||||
|
|
||||||
// Check if in IBD.
|
//! Check if in IBD.
|
||||||
virtual bool isInitialBlockDownload() = 0;
|
virtual bool isInitialBlockDownload() = 0;
|
||||||
|
|
||||||
|
//! Check if shutdown requested.
|
||||||
|
virtual bool shutdownRequested() = 0;
|
||||||
|
|
||||||
//! Get adjusted time.
|
//! Get adjusted time.
|
||||||
virtual int64_t getAdjustedTime() = 0;
|
virtual int64_t getAdjustedTime() = 0;
|
||||||
|
|
||||||
@ -194,6 +221,34 @@ public:
|
|||||||
|
|
||||||
//! Send wallet load notification to the GUI.
|
//! Send wallet load notification to the GUI.
|
||||||
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;
|
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;
|
||||||
|
|
||||||
|
//! Send progress indicator.
|
||||||
|
virtual void showProgress(const std::string& title, int progress, bool resume_possible) = 0;
|
||||||
|
|
||||||
|
//! Chain notifications.
|
||||||
|
class Notifications
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Notifications() {}
|
||||||
|
virtual void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) {}
|
||||||
|
virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) {}
|
||||||
|
virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted) {}
|
||||||
|
virtual void BlockDisconnected(const CBlock& block) {}
|
||||||
|
virtual void ChainStateFlushed(const CBlockLocator& locator) {}
|
||||||
|
virtual void ResendWalletTransactions(Lock& locked_chain, int64_t best_block_time) {}
|
||||||
|
virtual void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) {}
|
||||||
|
virtual void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Register handler for notifications.
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
|
||||||
|
|
||||||
|
//! Wait for pending notifications to be handled.
|
||||||
|
virtual void waitForNotifications() = 0;
|
||||||
|
|
||||||
|
//! Register handler for RPC. Command is not copied, so reference
|
||||||
|
//! needs to remain valid until Handler is disconnected.
|
||||||
|
virtual std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Interface to let node manage chain clients (wallets, or maybe tools for
|
//! Interface to let node manage chain clients (wallets, or maybe tools for
|
||||||
|
@ -110,12 +110,8 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
|
|||||||
//! Construct wallet tx status struct.
|
//! Construct wallet tx status struct.
|
||||||
WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
|
WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
|
||||||
{
|
{
|
||||||
LockAnnotation lock(::cs_main); // Temporary, for mapBlockIndex below. Removed in upcoming commit.
|
|
||||||
|
|
||||||
WalletTxStatus result;
|
WalletTxStatus result;
|
||||||
auto mi = ::BlockIndex().find(wtx.hashBlock);
|
result.block_height = locked_chain.getBlockHeight(wtx.hashBlock).get_value_or(std::numeric_limits<int>::max());
|
||||||
CBlockIndex* block = mi != ::BlockIndex().end() ? mi->second : nullptr;
|
|
||||||
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
|
|
||||||
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
|
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
|
||||||
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
|
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
|
||||||
result.time_received = wtx.nTimeReceived;
|
result.time_received = wtx.nTimeReceived;
|
||||||
@ -604,7 +600,7 @@ public:
|
|||||||
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
|
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
|
void registerRpcs() override { return RegisterWalletRPCCommands(m_chain, m_rpc_handlers); }
|
||||||
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
|
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
|
||||||
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
|
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
|
||||||
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
|
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
|
||||||
@ -614,6 +610,7 @@ public:
|
|||||||
|
|
||||||
Chain& m_chain;
|
Chain& m_chain;
|
||||||
std::vector<std::string> m_wallet_filenames;
|
std::vector<std::string> m_wallet_filenames;
|
||||||
|
std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
21
src/node/coin.cpp
Normal file
21
src/node/coin.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2019 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <node/coin.h>
|
||||||
|
|
||||||
|
#include <txmempool.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
|
void FindCoins(std::map<COutPoint, Coin>& coins)
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, ::mempool.cs);
|
||||||
|
CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip();
|
||||||
|
CCoinsViewMemPool mempool_view(&chain_view, ::mempool);
|
||||||
|
for (auto& coin : coins) {
|
||||||
|
if (!mempool_view.GetCoin(coin.first, coin.second)) {
|
||||||
|
// Either the coin is not in the CCoinsViewCache or is spent. Clear it.
|
||||||
|
coin.second.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/node/coin.h
Normal file
22
src/node/coin.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2019 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_NODE_COIN_H
|
||||||
|
#define BITCOIN_NODE_COIN_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class COutPoint;
|
||||||
|
class Coin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up unspent output information. Returns coins in the mempool and in the
|
||||||
|
* current chain UTXO set. Iterates through all the keys in the map and
|
||||||
|
* populates the values.
|
||||||
|
*
|
||||||
|
* @param[in,out] coins map to fill
|
||||||
|
*/
|
||||||
|
void FindCoins(std::map<COutPoint, Coin>& coins);
|
||||||
|
|
||||||
|
#endif // BITCOIN_NODE_COIN_H
|
@ -29,7 +29,7 @@ std::unique_ptr<interfaces::PendingWalletTx>& WalletModelTransaction::getWtx()
|
|||||||
|
|
||||||
unsigned int WalletModelTransaction::getTransactionSize()
|
unsigned int WalletModelTransaction::getTransactionSize()
|
||||||
{
|
{
|
||||||
return wtx != nullptr ? ::GetSerializeSize(wtx->get(), SER_NETWORK, PROTOCOL_VERSION) : 0;
|
return wtx ? ::GetSerializeSize(wtx->get(), SER_NETWORK, PROTOCOL_VERSION) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount WalletModelTransaction::getTransactionFee() const
|
CAmount WalletModelTransaction::getTransactionFee() const
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <core_io.h>
|
#include <core_io.h>
|
||||||
#include <index/txindex.h>
|
#include <index/txindex.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <interfaces/chain.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <keystore.h>
|
#include <keystore.h>
|
||||||
#include <merkleblock.h>
|
#include <merkleblock.h>
|
||||||
@ -768,23 +769,20 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
|
|||||||
return EncodeHexTx(CTransaction(mergedTx));
|
return EncodeHexTx(CTransaction(mergedTx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237):
|
||||||
|
// This function is called from both wallet and node rpcs
|
||||||
|
// (signrawtransactionwithwallet and signrawtransactionwithkey). It should be
|
||||||
|
// moved to a util file so wallet code doesn't need to link against node code.
|
||||||
|
// Also the dependency on interfaces::Chain should be removed, so
|
||||||
|
// signrawtransactionwithkey doesn't need access to a Chain instance.
|
||||||
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
|
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
|
||||||
{
|
{
|
||||||
// Fetch previous transactions (inputs):
|
// Fetch previous transactions (inputs):
|
||||||
CCoinsView viewDummy;
|
std::map<COutPoint, Coin> coins;
|
||||||
CCoinsViewCache view(&viewDummy);
|
for (const CTxIn& txin : mtx.vin) {
|
||||||
{
|
coins[txin.prevout]; // Create empty map entry keyed by prevout.
|
||||||
LOCK2(cs_main, mempool.cs);
|
|
||||||
CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip();
|
|
||||||
CCoinsViewMemPool viewMempool(&viewChain, mempool);
|
|
||||||
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
|
||||||
|
|
||||||
for (const CTxIn& txin : mtx.vin) {
|
|
||||||
view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
|
|
||||||
}
|
|
||||||
|
|
||||||
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
|
||||||
}
|
}
|
||||||
|
chain.findCoins(coins);
|
||||||
|
|
||||||
// Add previous txouts given in the RPC call:
|
// Add previous txouts given in the RPC call:
|
||||||
if (!prevTxsUnival.isNull()) {
|
if (!prevTxsUnival.isNull()) {
|
||||||
@ -816,10 +814,10 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
|||||||
CScript scriptPubKey(pkData.begin(), pkData.end());
|
CScript scriptPubKey(pkData.begin(), pkData.end());
|
||||||
|
|
||||||
{
|
{
|
||||||
const Coin& coin = view.AccessCoin(out);
|
auto coin = coins.find(out);
|
||||||
if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
|
if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
|
||||||
std::string err("Previous output scriptPubKey mismatch:\n");
|
std::string err("Previous output scriptPubKey mismatch:\n");
|
||||||
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
|
err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
|
||||||
ScriptToAsmStr(scriptPubKey);
|
ScriptToAsmStr(scriptPubKey);
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
||||||
}
|
}
|
||||||
@ -830,7 +828,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
|||||||
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
|
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
|
||||||
}
|
}
|
||||||
newcoin.nHeight = 1;
|
newcoin.nHeight = 1;
|
||||||
view.AddCoin(out, std::move(newcoin), true);
|
coins[out] = std::move(newcoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
|
// if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
|
||||||
@ -862,15 +860,15 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
|||||||
// Sign what we can:
|
// Sign what we can:
|
||||||
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
|
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
|
||||||
CTxIn& txin = mtx.vin[i];
|
CTxIn& txin = mtx.vin[i];
|
||||||
const Coin& coin = view.AccessCoin(txin.prevout);
|
auto coin = coins.find(txin.prevout);
|
||||||
if (coin.IsSpent()) {
|
if (coin == coins.end() || coin->second.IsSpent()) {
|
||||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const CScript& prevPubKey = coin.out.scriptPubKey;
|
const CScript& prevPubKey = coin->second.out.scriptPubKey;
|
||||||
const CAmount& amount = coin.out.nValue;
|
const CAmount& amount = coin->second.out.nValue;
|
||||||
|
|
||||||
SignatureData sigdata = DataFromTransaction(mtx, i, coin.out);
|
SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
|
||||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||||
if (!fHashSingle || (i < mtx.vout.size())) {
|
if (!fHashSingle || (i < mtx.vout.size())) {
|
||||||
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
|
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
|
||||||
|
@ -33,6 +33,7 @@ static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server starte
|
|||||||
static RPCTimerInterface* timerInterface = nullptr;
|
static RPCTimerInterface* timerInterface = nullptr;
|
||||||
/* Map of name to timer. */
|
/* Map of name to timer. */
|
||||||
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
|
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
|
||||||
|
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions);
|
||||||
|
|
||||||
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
|
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
|
||||||
static const std::string defaultPlatformUser = "platform-user";
|
static const std::string defaultPlatformUser = "platform-user";
|
||||||
@ -201,11 +202,11 @@ std::string CRPCTable::help(const std::string& strCommand, const std::string& st
|
|||||||
{
|
{
|
||||||
std::string strRet;
|
std::string strRet;
|
||||||
std::string category;
|
std::string category;
|
||||||
std::set<rpcfn_type> setDone;
|
std::set<intptr_t> setDone;
|
||||||
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
|
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
|
||||||
|
|
||||||
for (const auto& entry : mapCommands)
|
for (const auto& entry : mapCommands)
|
||||||
vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
|
vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
|
||||||
sort(vCommands.begin(), vCommands.end());
|
sort(vCommands.begin(), vCommands.end());
|
||||||
|
|
||||||
JSONRPCRequest jreq(helpreq);
|
JSONRPCRequest jreq(helpreq);
|
||||||
@ -225,9 +226,9 @@ std::string CRPCTable::help(const std::string& strCommand, const std::string& st
|
|||||||
jreq.params.setArray();
|
jreq.params.setArray();
|
||||||
jreq.params.push_back(strSubCommand);
|
jreq.params.push_back(strSubCommand);
|
||||||
}
|
}
|
||||||
rpcfn_type pfn = pcmd->actor;
|
UniValue unused_result;
|
||||||
if (setDone.insert(pfn).second)
|
if (setDone.insert(pcmd->unique_id).second)
|
||||||
(*pfn)(jreq);
|
pcmd->actor(jreq, unused_result, true /* last_handler */);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
@ -356,32 +357,32 @@ CRPCTable::CRPCTable()
|
|||||||
const CRPCCommand *pcmd;
|
const CRPCCommand *pcmd;
|
||||||
|
|
||||||
pcmd = &vRPCCommands[vcidx];
|
pcmd = &vRPCCommands[vcidx];
|
||||||
mapCommands[pcmd->name] = pcmd;
|
mapCommands[pcmd->name].push_back(pcmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRPCCommand *CRPCTable::operator[](const std::string &name) const
|
|
||||||
{
|
|
||||||
std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
|
|
||||||
if (it == mapCommands.end())
|
|
||||||
return nullptr;
|
|
||||||
return (*it).second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
|
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
|
||||||
{
|
{
|
||||||
if (IsRPCRunning())
|
if (IsRPCRunning())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// don't allow overwriting for now
|
mapCommands[name].push_back(pcmd);
|
||||||
std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
|
|
||||||
if (it != mapCommands.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
mapCommands[name] = pcmd;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
|
||||||
|
{
|
||||||
|
auto it = mapCommands.find(name);
|
||||||
|
if (it != mapCommands.end()) {
|
||||||
|
auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
|
||||||
|
if (it->second.end() != new_end) {
|
||||||
|
it->second.erase(new_end, it->second.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void StartRPC()
|
void StartRPC()
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::RPC, "Starting RPC\n");
|
LogPrint(BCLog::RPC, "Starting RPC\n");
|
||||||
@ -564,10 +565,20 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find method
|
// Find method
|
||||||
const CRPCCommand *pcmd = tableRPC[request.strMethod];
|
auto it = mapCommands.find(request.strMethod);
|
||||||
if (!pcmd)
|
if (it != mapCommands.end()) {
|
||||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
UniValue result;
|
||||||
|
for (const auto& command : it->second) {
|
||||||
|
if (ExecuteCommand(*command, request, result, &command == &it->second.back(), mapPlatformRestrictions)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions)
|
||||||
|
{
|
||||||
// Before executing the RPC Command, filter commands from platform rpc user
|
// Before executing the RPC Command, filter commands from platform rpc user
|
||||||
if (fMasternodeMode && request.authUser == gArgs.GetArg("-platform-user", defaultPlatformUser)) {
|
if (fMasternodeMode && request.authUser == gArgs.GetArg("-platform-user", defaultPlatformUser)) {
|
||||||
// replace this with structured binding in c++20
|
// replace this with structured binding in c++20
|
||||||
@ -633,9 +644,9 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
|||||||
{
|
{
|
||||||
// Execute, convert arguments to array if necessary
|
// Execute, convert arguments to array if necessary
|
||||||
if (request.params.isObject()) {
|
if (request.params.isObject()) {
|
||||||
return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
|
return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
|
||||||
} else {
|
} else {
|
||||||
return pcmd->actor(request);
|
return command.actor(request, result, last_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
@ -129,10 +129,31 @@ typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
|
|||||||
class CRPCCommand
|
class CRPCCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
//! RPC method handler reading request and assigning result. Should return
|
||||||
|
//! true if request is fully handled, false if it should be passed on to
|
||||||
|
//! subsequent handlers.
|
||||||
|
using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
|
||||||
|
|
||||||
|
//! Constructor taking Actor callback supporting multiple handlers.
|
||||||
|
CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
|
||||||
|
: category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
|
||||||
|
unique_id(unique_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Simplified constructor taking plain rpcfn_type function pointer.
|
||||||
|
CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
|
||||||
|
: CRPCCommand(category, name,
|
||||||
|
[fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; },
|
||||||
|
{args.begin(), args.end()}, intptr_t(fn))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string category;
|
std::string category;
|
||||||
std::string name;
|
std::string name;
|
||||||
rpcfn_type actor;
|
Actor actor;
|
||||||
std::vector<std::string> argNames;
|
std::vector<std::string> argNames;
|
||||||
|
intptr_t unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,11 +162,10 @@ public:
|
|||||||
class CRPCTable
|
class CRPCTable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::map<std::string, const CRPCCommand*> mapCommands;
|
std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
|
||||||
std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions;
|
std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions;
|
||||||
public:
|
public:
|
||||||
CRPCTable();
|
CRPCTable();
|
||||||
const CRPCCommand* operator[](const std::string& name) const;
|
|
||||||
std::string help(const std::string& name, const std::string& strSubCommand, const JSONRPCRequest& helpreq) const;
|
std::string help(const std::string& name, const std::string& strSubCommand, const JSONRPCRequest& helpreq) const;
|
||||||
|
|
||||||
void InitPlatformRestrictions();
|
void InitPlatformRestrictions();
|
||||||
@ -169,9 +189,7 @@ public:
|
|||||||
*
|
*
|
||||||
* Returns false if RPC server is already running (dump concurrency protection).
|
* Returns false if RPC server is already running (dump concurrency protection).
|
||||||
*
|
*
|
||||||
* Commands cannot be overwritten (returns false).
|
* Commands with different method names but the same unique_id will
|
||||||
*
|
|
||||||
* Commands with different method names but the same callback function will
|
|
||||||
* be considered aliases, and only the first registered method name will
|
* be considered aliases, and only the first registered method name will
|
||||||
* show up in the help text command listing. Aliased commands do not have
|
* show up in the help text command listing. Aliased commands do not have
|
||||||
* to have the same behavior. Server and client code can distinguish
|
* to have the same behavior. Server and client code can distinguish
|
||||||
@ -179,6 +197,7 @@ public:
|
|||||||
* register different names, types, and numbers of parameters.
|
* register different names, types, and numbers of parameters.
|
||||||
*/
|
*/
|
||||||
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
|
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
|
||||||
|
bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsDeprecatedRPCEnabled(const std::string& method);
|
bool IsDeprecatedRPCEnabled(const std::string& method);
|
||||||
|
@ -31,10 +31,9 @@ UniValue CallRPC(std::string args)
|
|||||||
request.strMethod = strMethod;
|
request.strMethod = strMethod;
|
||||||
request.params = RPCConvertValues(strMethod, vArgs);
|
request.params = RPCConvertValues(strMethod, vArgs);
|
||||||
request.fHelp = false;
|
request.fHelp = false;
|
||||||
BOOST_CHECK(tableRPC[strMethod]);
|
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
|
||||||
rpcfn_type method = tableRPC[strMethod]->actor;
|
|
||||||
try {
|
try {
|
||||||
UniValue result = (*method)(request);
|
UniValue result = tableRPC.execute(request);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (const UniValue& objError) {
|
catch (const UniValue& objError) {
|
||||||
|
@ -21,8 +21,9 @@ CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinC
|
|||||||
{
|
{
|
||||||
CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
|
CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
|
||||||
// Always obey the maximum
|
// Always obey the maximum
|
||||||
if (fee_needed > maxTxFee) {
|
const CAmount max_tx_fee = wallet.chain().maxTxFee();
|
||||||
fee_needed = maxTxFee;
|
if (fee_needed > max_tx_fee) {
|
||||||
|
fee_needed = max_tx_fee;
|
||||||
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
|
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
|
||||||
}
|
}
|
||||||
return fee_needed;
|
return fee_needed;
|
||||||
@ -30,7 +31,7 @@ CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinC
|
|||||||
|
|
||||||
CFeeRate GetRequiredFeeRate(const CWallet& wallet)
|
CFeeRate GetRequiredFeeRate(const CWallet& wallet)
|
||||||
{
|
{
|
||||||
return std::max(wallet.m_min_fee, ::minRelayTxFee);
|
return std::max(wallet.m_min_fee, wallet.chain().relayMinFee());
|
||||||
}
|
}
|
||||||
|
|
||||||
CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc)
|
CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc)
|
||||||
@ -92,6 +93,6 @@ CFeeRate GetDiscardRate(const CWallet& wallet)
|
|||||||
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
|
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
|
||||||
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
|
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
|
||||||
// Discard rate must be at least dustRelayFee
|
// Discard rate must be at least dustRelayFee
|
||||||
discard_rate = std::max(discard_rate, ::dustRelayFee);
|
discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
|
||||||
return discard_rate;
|
return discard_rate;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
|
|||||||
|
|
||||||
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
|
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
|
||||||
|
|
||||||
uiInterface.InitMessage(_("Verifying wallet(s)..."));
|
chain.initMessage(_("Verifying wallet(s)..."));
|
||||||
|
|
||||||
// Parameter interaction code should have thrown an error if -salvagewallet
|
// Parameter interaction code should have thrown an error if -salvagewallet
|
||||||
// was enabled with more than wallet file, so the wallet_files size check
|
// was enabled with more than wallet file, so the wallet_files size check
|
||||||
|
@ -561,11 +561,11 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
// Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
|
// Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
|
||||||
// we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
|
// we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
|
||||||
uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
|
pwallet->chain().showProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
|
||||||
std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
|
std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
|
||||||
std::vector<std::pair<CScript, int64_t>> scripts;
|
std::vector<std::pair<CScript, int64_t>> scripts;
|
||||||
while (file.good()) {
|
while (file.good()) {
|
||||||
uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
|
pwallet->chain().showProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
|
||||||
std::string line;
|
std::string line;
|
||||||
std::getline(file, line);
|
std::getline(file, line);
|
||||||
if (line.empty() || line[0] == '#')
|
if (line.empty() || line[0] == '#')
|
||||||
@ -603,13 +603,13 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||||||
file.close();
|
file.close();
|
||||||
// We now know whether we are importing private keys, so we can error if private keys are disabled
|
// We now know whether we are importing private keys, so we can error if private keys are disabled
|
||||||
if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||||
uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
|
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
|
||||||
}
|
}
|
||||||
double total = (double)(keys.size() + scripts.size());
|
double total = (double)(keys.size() + scripts.size());
|
||||||
double progress = 0;
|
double progress = 0;
|
||||||
for (const auto& key_tuple : keys) {
|
for (const auto& key_tuple : keys) {
|
||||||
uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
||||||
const CKey& key = std::get<0>(key_tuple);
|
const CKey& key = std::get<0>(key_tuple);
|
||||||
int64_t time = std::get<1>(key_tuple);
|
int64_t time = std::get<1>(key_tuple);
|
||||||
bool has_label = std::get<2>(key_tuple);
|
bool has_label = std::get<2>(key_tuple);
|
||||||
@ -634,7 +634,7 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||||||
progress++;
|
progress++;
|
||||||
}
|
}
|
||||||
for (const auto& script_pair : scripts) {
|
for (const auto& script_pair : scripts) {
|
||||||
uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
||||||
const CScript& script = script_pair.first;
|
const CScript& script = script_pair.first;
|
||||||
int64_t time = script_pair.second;
|
int64_t time = script_pair.second;
|
||||||
CScriptID id(script);
|
CScriptID id(script);
|
||||||
@ -653,10 +653,10 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
progress++;
|
progress++;
|
||||||
}
|
}
|
||||||
uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
|
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||||
pwallet->UpdateTimeFirstKey(nTimeBegin);
|
pwallet->UpdateTimeFirstKey(nTimeBegin);
|
||||||
}
|
}
|
||||||
uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
|
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||||
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
|
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
|
||||||
pwallet->MarkDirty();
|
pwallet->MarkDirty();
|
||||||
|
|
||||||
|
@ -2447,8 +2447,8 @@ static UniValue settxfee(const JSONRPCRequest& request)
|
|||||||
CFeeRate tx_fee_rate(nAmount, 1000);
|
CFeeRate tx_fee_rate(nAmount, 1000);
|
||||||
if (tx_fee_rate == 0) {
|
if (tx_fee_rate == 0) {
|
||||||
// automatic selection
|
// automatic selection
|
||||||
} else if (tx_fee_rate < ::minRelayTxFee) {
|
} else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", ::minRelayTxFee.ToString()));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
|
||||||
} else if (tx_fee_rate < pwallet->m_min_fee) {
|
} else if (tx_fee_rate < pwallet->m_min_fee) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
|
||||||
}
|
}
|
||||||
@ -4271,8 +4271,8 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterWalletRPCCommands(CRPCTable &t)
|
void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers)
|
||||||
{
|
{
|
||||||
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
||||||
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
|
handlers.emplace_back(chain.handleRpc(commands[vcidx]));
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#ifndef BITCOIN_WALLET_RPCWALLET_H
|
#ifndef BITCOIN_WALLET_RPCWALLET_H
|
||||||
#define BITCOIN_WALLET_RPCWALLET_H
|
#define BITCOIN_WALLET_RPCWALLET_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CRPCTable;
|
class CRPCTable;
|
||||||
class CWallet;
|
class CWallet;
|
||||||
@ -14,7 +16,12 @@ class UniValue;
|
|||||||
struct PartiallySignedTransaction;
|
struct PartiallySignedTransaction;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
|
|
||||||
void RegisterWalletRPCCommands(CRPCTable &t);
|
namespace interfaces {
|
||||||
|
class Chain;
|
||||||
|
class Handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Figures out what wallet, if any, to use for a JSONRPCRequest.
|
* Figures out what wallet, if any, to use for a JSONRPCRequest.
|
||||||
|
@ -13,12 +13,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
|
|||||||
{
|
{
|
||||||
bool fFirstRun;
|
bool fFirstRun;
|
||||||
m_wallet.LoadWallet(fFirstRun);
|
m_wallet.LoadWallet(fFirstRun);
|
||||||
RegisterValidationInterface(&m_wallet);
|
m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
|
||||||
|
|
||||||
RegisterWalletRPCCommands(tableRPC);
|
m_chain_client->registerRpcs();
|
||||||
}
|
|
||||||
|
|
||||||
WalletTestingSetup::~WalletTestingSetup()
|
|
||||||
{
|
|
||||||
UnregisterValidationInterface(&m_wallet);
|
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
struct WalletTestingSetup: public TestingSetup {
|
struct WalletTestingSetup: public TestingSetup {
|
||||||
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
|
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
|
||||||
~WalletTestingSetup();
|
|
||||||
|
|
||||||
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
|
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
|
||||||
|
std::unique_ptr<interfaces::ChainClient> m_chain_client = interfaces::MakeWalletClient(*m_chain, {});
|
||||||
CWallet m_wallet;
|
CWallet m_wallet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ static void ReleaseWallet(CWallet* wallet)
|
|||||||
wallet->WalletLogPrintf("Releasing wallet\n");
|
wallet->WalletLogPrintf("Releasing wallet\n");
|
||||||
wallet->BlockUntilSyncedToCurrentChain();
|
wallet->BlockUntilSyncedToCurrentChain();
|
||||||
wallet->Flush();
|
wallet->Flush();
|
||||||
UnregisterValidationInterface(wallet);
|
wallet->m_chain_notifications_handler.reset();
|
||||||
delete wallet;
|
delete wallet;
|
||||||
// Wallet is now released, notify UnloadWallet, if any.
|
// Wallet is now released, notify UnloadWallet, if any.
|
||||||
{
|
{
|
||||||
@ -1427,7 +1427,8 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
|
void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) {
|
||||||
|
const uint256& block_hash = block.GetHash();
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
// TODO: Temporarily ensure that mempool removals are notified before
|
// TODO: Temporarily ensure that mempool removals are notified before
|
||||||
@ -1443,24 +1444,24 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
|
|||||||
// UNKNOWN because it's a manual removal, not using mempool logic
|
// UNKNOWN because it's a manual removal, not using mempool logic
|
||||||
TransactionRemovedFromMempool(ptx, MemPoolRemovalReason::UNKNOWN);
|
TransactionRemovedFromMempool(ptx, MemPoolRemovalReason::UNKNOWN);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < pblock->vtx.size(); i++) {
|
for (size_t i = 0; i < block.vtx.size(); i++) {
|
||||||
SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
|
SyncTransaction(block.vtx[i], block_hash, i);
|
||||||
// UNKNOWN because it's a manual removal, not using mempool logic
|
// UNKNOWN because it's a manual removal, not using mempool logic
|
||||||
TransactionRemovedFromMempool(pblock->vtx[i], MemPoolRemovalReason::UNKNOWN);
|
TransactionRemovedFromMempool(block.vtx[i], MemPoolRemovalReason::UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_block_processed = pindex->GetBlockHash();
|
m_last_block_processed = block_hash;
|
||||||
|
|
||||||
// reset cache to make sure no longer immature coins are included
|
// reset cache to make sure no longer immature coins are included
|
||||||
fAnonymizableTallyCached = false;
|
fAnonymizableTallyCached = false;
|
||||||
fAnonymizableTallyCachedNonDenom = false;
|
fAnonymizableTallyCachedNonDenom = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) {
|
void CWallet::BlockDisconnected(const CBlock& block) {
|
||||||
auto locked_chain = chain().lock();
|
auto locked_chain = chain().lock();
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
for (const CTransactionRef& ptx : pblock->vtx) {
|
for (const CTransactionRef& ptx : block.vtx) {
|
||||||
// NOTE: do NOT pass pindex here
|
// NOTE: do NOT pass pindex here
|
||||||
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
|
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
|
||||||
}
|
}
|
||||||
@ -1492,7 +1493,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
|
|||||||
// ...otherwise put a callback in the validation interface queue and wait
|
// ...otherwise put a callback in the validation interface queue and wait
|
||||||
// for the queue to drain enough to execute it (indicating we are caught up
|
// for the queue to drain enough to execute it (indicating we are caught up
|
||||||
// at least with the time we entered this function).
|
// at least with the time we entered this function).
|
||||||
SyncWithValidationInterfaceQueue();
|
chain().waitForNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2177,7 +2178,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
|
progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
|
||||||
}
|
}
|
||||||
double progress_current = progress_begin;
|
double progress_current = progress_begin;
|
||||||
while (block_height && !fAbortRescan && !ShutdownRequested()) {
|
while (block_height && !fAbortRescan && !chain().shutdownRequested()) {
|
||||||
m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
|
m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
|
||||||
if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
|
if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
|
||||||
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
|
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
|
||||||
@ -2240,7 +2241,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
if (block_height && fAbortRescan) {
|
if (block_height && fAbortRescan) {
|
||||||
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
|
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
|
||||||
result.status = ScanResult::USER_ABORT;
|
result.status = ScanResult::USER_ABORT;
|
||||||
} else if (block_height && ShutdownRequested()) {
|
} else if (block_height && chain().shutdownRequested()) {
|
||||||
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
|
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
|
||||||
result.status = ScanResult::USER_ABORT;
|
result.status = ScanResult::USER_ABORT;
|
||||||
}
|
}
|
||||||
@ -2615,7 +2616,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(interfaces::Chain::
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
|
void CWallet::ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime)
|
||||||
{
|
{
|
||||||
// Do this infrequently and randomly to avoid giving away
|
// Do this infrequently and randomly to avoid giving away
|
||||||
// that these are our transactions.
|
// that these are our transactions.
|
||||||
@ -2633,8 +2634,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman
|
|||||||
|
|
||||||
// Rebroadcast unconfirmed txes older than 5 minutes before the last
|
// Rebroadcast unconfirmed txes older than 5 minutes before the last
|
||||||
// block was found:
|
// block was found:
|
||||||
auto locked_chain = chain().assumeLocked(); // Temporary. Removed in upcoming lock cleanup
|
std::vector<uint256> relayed = ResendWalletTransactionsBefore(locked_chain, nBestBlockTime-5*60);
|
||||||
std::vector<uint256> relayed = ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime-5*60);
|
|
||||||
if (!relayed.empty())
|
if (!relayed.empty())
|
||||||
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
|
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
|
||||||
}
|
}
|
||||||
@ -2829,7 +2829,6 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
|
|||||||
|
|
||||||
void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
|
void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
vCoins.clear();
|
vCoins.clear();
|
||||||
@ -2924,7 +2923,6 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
|
|||||||
|
|
||||||
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Chain::Lock& locked_chain) const
|
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Chain::Lock& locked_chain) const
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
std::map<CTxDestination, std::vector<COutput>> result;
|
std::map<CTxDestination, std::vector<COutput>> result;
|
||||||
@ -3265,13 +3263,13 @@ bool CWallet::SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::ve
|
|||||||
return nValueTotal > 0;
|
return nValueTotal > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
|
static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
|
||||||
{
|
{
|
||||||
if (::ChainstateActive().IsInitialBlockDownload()) {
|
if (chain.isInitialBlockDownload()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
|
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
|
||||||
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
|
if (locked_chain.getBlockTime(*locked_chain.getHeight()) < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -3281,7 +3279,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
|
|||||||
* Return a height-based locktime for new transactions (uses the height of the
|
* Return a height-based locktime for new transactions (uses the height of the
|
||||||
* current chain tip unless we are not synced with the current chain
|
* current chain tip unless we are not synced with the current chain
|
||||||
*/
|
*/
|
||||||
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
|
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
|
||||||
{
|
{
|
||||||
uint32_t locktime;
|
uint32_t locktime;
|
||||||
// Discourage fee sniping.
|
// Discourage fee sniping.
|
||||||
@ -3304,7 +3302,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
|
|||||||
// enough, that fee sniping isn't a problem yet, but by implementing a fix
|
// enough, that fee sniping isn't a problem yet, but by implementing a fix
|
||||||
// now we ensure code won't be written that makes assumptions about
|
// now we ensure code won't be written that makes assumptions about
|
||||||
// nLockTime that preclude a fix later.
|
// nLockTime that preclude a fix later.
|
||||||
if (IsCurrentForAntiFeeSniping(locked_chain)) {
|
if (IsCurrentForAntiFeeSniping(chain, locked_chain)) {
|
||||||
locktime = locked_chain.getHeight().value_or(-1);
|
locktime = locked_chain.getHeight().value_or(-1);
|
||||||
|
|
||||||
// Secondly occasionally randomly pick a nLockTime even further back, so
|
// Secondly occasionally randomly pick a nLockTime even further back, so
|
||||||
@ -3540,7 +3538,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
|||||||
}
|
}
|
||||||
|
|
||||||
CMutableTransaction txNew;
|
CMutableTransaction txNew;
|
||||||
txNew.nLockTime = GetLocktimeForNewTransaction(locked_chain);
|
txNew.nLockTime = GetLocktimeForNewTransaction(chain(), locked_chain);
|
||||||
|
|
||||||
FeeCalculation feeCalc;
|
FeeCalculation feeCalc;
|
||||||
CFeeRate discard_rate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(*this);
|
CFeeRate discard_rate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(*this);
|
||||||
@ -3630,7 +3628,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsDust(txout, ::dustRelayFee))
|
if (IsDust(txout, chain().relayDustFee()))
|
||||||
{
|
{
|
||||||
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
|
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
|
||||||
{
|
{
|
||||||
@ -5101,9 +5099,9 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||||||
_("This is the transaction fee you will pay if you send a transaction."));
|
_("This is the transaction fee you will pay if you send a transaction."));
|
||||||
}
|
}
|
||||||
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
|
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
|
||||||
if (walletInstance->m_pay_tx_fee < ::minRelayTxFee) {
|
if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
|
||||||
chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
|
chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
|
||||||
gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
|
gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5206,8 +5204,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||||||
|
|
||||||
chain.loadWallet(interfaces::MakeWallet(walletInstance));
|
chain.loadWallet(interfaces::MakeWallet(walletInstance));
|
||||||
|
|
||||||
// Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
|
// Register with the validation interface. It's ok to do this after rescan since we're still holding locked_chain.
|
||||||
RegisterValidationInterface(walletInstance.get());
|
walletInstance->m_chain_notifications_handler = chain.handleNotifications(*walletInstance);
|
||||||
|
|
||||||
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
|
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
|
||||||
|
|
||||||
@ -5463,8 +5461,6 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
|
|||||||
if (hashUnset())
|
if (hashUnset())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
AssertLockHeld(cs_main);
|
|
||||||
|
|
||||||
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
|
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <amount.h>
|
#include <amount.h>
|
||||||
#include <interfaces/chain.h>
|
#include <interfaces/chain.h>
|
||||||
|
#include <interfaces/handler.h>
|
||||||
#include <policy/feerate.h>
|
#include <policy/feerate.h>
|
||||||
#include <saltedhasher.h>
|
#include <saltedhasher.h>
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
@ -507,7 +508,7 @@ public:
|
|||||||
CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
|
CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
|
||||||
CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
|
CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
|
||||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet)". The
|
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
|
||||||
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
|
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
|
||||||
// having to resolve the issue of member access into incomplete type CWallet.
|
// having to resolve the issue of member access into incomplete type CWallet.
|
||||||
CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
|
CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
|
||||||
@ -656,7 +657,7 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
|
|||||||
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
|
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
|
||||||
* and provides the ability to create new transactions.
|
* and provides the ability to create new transactions.
|
||||||
*/
|
*/
|
||||||
class CWallet final : public CCryptoKeyStore, public CValidationInterface
|
class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> fAbortRescan{false};
|
std::atomic<bool> fAbortRescan{false};
|
||||||
@ -850,6 +851,9 @@ public:
|
|||||||
|
|
||||||
std::map<CKeyID, CHDPubKey> mapHdPubKeys; //<! memory map of HD extended pubkeys
|
std::map<CKeyID, CHDPubKey> mapHdPubKeys; //<! memory map of HD extended pubkeys
|
||||||
|
|
||||||
|
/** Registered interfaces::Chain::Notifications handler. */
|
||||||
|
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
|
||||||
|
|
||||||
/** Interface for accessing chain state. */
|
/** Interface for accessing chain state. */
|
||||||
interfaces::Chain& chain() const { return m_chain; }
|
interfaces::Chain& chain() const { return m_chain; }
|
||||||
|
|
||||||
@ -991,8 +995,8 @@ public:
|
|||||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
||||||
void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override;
|
void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override;
|
||||||
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
|
void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) override;
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) override;
|
void BlockDisconnected(const CBlock& block) override;
|
||||||
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
||||||
|
|
||||||
struct ScanResult {
|
struct ScanResult {
|
||||||
@ -1013,7 +1017,7 @@ public:
|
|||||||
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
|
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
|
||||||
void TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) override;
|
void TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) override;
|
||||||
void ReacceptWalletTransactions();
|
void ReacceptWalletTransactions();
|
||||||
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime) override;
|
||||||
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
|
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
|
||||||
std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime);
|
std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime);
|
||||||
struct Balance {
|
struct Balance {
|
||||||
@ -1292,6 +1296,8 @@ public:
|
|||||||
|
|
||||||
/** Implement lookup of key origin information through wallet key metadata. */
|
/** Implement lookup of key origin information through wallet key metadata. */
|
||||||
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
||||||
|
|
||||||
|
friend struct WalletTestingSetup;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A key allocated from the key pool. */
|
/** A key allocated from the key pool. */
|
||||||
|
Loading…
Reference in New Issue
Block a user