Skip to content

Commit

Permalink
merge bitcoin#10973: separate wallet from node
Browse files Browse the repository at this point in the history
  • Loading branch information
kwvg committed Oct 31, 2021
1 parent fd42242 commit ab6f8fe
Show file tree
Hide file tree
Showing 21 changed files with 366 additions and 128 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ BITCOIN_CORE_H = \
netbase.h \
netfulfilledman.h \
netmessagemaker.h \
node/coin.h \
node/coinstats.h \
node/transaction.h \
noui.h \
Expand Down Expand Up @@ -385,6 +386,7 @@ libdash_server_a_SOURCES = \
net.cpp \
netfulfilledman.cpp \
net_processing.cpp \
node/coin.cpp \
node/coinstats.cpp \
node/transaction.cpp \
noui.cpp \
Expand Down
7 changes: 1 addition & 6 deletions src/bench/wallet_balance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@ struct WalletTestingSetup {

void handleNotifications()
{
RegisterValidationInterface(&m_wallet);
}

~WalletTestingSetup()
{
UnregisterValidationInterface(&m_wallet);
m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
}
};

Expand Down
114 changes: 113 additions & 1 deletion src/interfaces/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,28 @@

#include <chain.h>
#include <chainparams.h>
#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <net.h>
#include <node/coin.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <protocol.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <shutdown.h>
#include <sync.h>
#include <threadsafety.h>
#include <timedata.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <uint256.h>
#include <univalue.h>
#include <util/system.h>
#include <validation.h>
#include <validationinterface.h>

#include <memory>
#include <utility>
Expand Down Expand Up @@ -160,6 +167,94 @@ class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
using UniqueLock::UniqueLock;
};

class NotificationsHandlerImpl : public Handler, CValidationInterface
{
public:
explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
: m_chain(chain), m_notifications(&notifications)
{
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
{
public:
Expand Down Expand Up @@ -193,6 +288,7 @@ class ChainImpl : public Chain
}
return true;
}
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
Expand Down Expand Up @@ -239,17 +335,33 @@ class ChainImpl : public Chain
auto it_mp = ::mempool.mapTx.find(txid);
return it_mp != ::mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1;
}
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
CFeeRate relayDustFee() override { return ::dustRelayFee; }
CAmount maxTxFee() override { return ::maxTxFee; }
bool getPruneMode() override { return ::fPruneMode; }
bool p2pEnabled() override { return g_connman != nullptr; }
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); }
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

std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
Expand Down
57 changes: 56 additions & 1 deletion src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,28 @@
#include <vector>

class CBlock;
class CRPCCommand;
class CScheduler;
class CValidationState;
class CFeeRate;
class CBlockIndex;
class Coin;
class uint256;
struct CBlockLocator;
struct FeeCalculation;
enum class MemPoolRemovalReason;

namespace llmq {
class CChainLockSig;
class CInstantSendLock;
} // namespace llmq

typedef std::shared_ptr<const CTransaction> CTransactionRef;

namespace interfaces {

class Wallet;
class Handler;

//! Interface for giving wallet processes access to blockchain state.
class Chain
Expand Down Expand Up @@ -140,6 +150,11 @@ class Chain
int64_t* time = nullptr,
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
//! the specified block hash are verified.
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
Expand All @@ -165,6 +180,15 @@ class Chain
//! Pool min fee.
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).
//! This could be replaced by a per-wallet max fee, as proposed at
//! https://github.com/bitcoin/bitcoin/issues/15355
Expand All @@ -177,9 +201,12 @@ class Chain
//! Check if p2p enabled.
virtual bool p2pEnabled() = 0;

// Check if in IBD.
//! Check if in IBD.
virtual bool isInitialBlockDownload() = 0;

//! Check if shutdown requested.
virtual bool shutdownRequested() = 0;

//! Get adjusted time.
virtual int64_t getAdjustedTime() = 0;

Expand All @@ -194,6 +221,34 @@ class Chain

//! Send wallet load notification to the GUI.
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
Expand Down
7 changes: 3 additions & 4 deletions src/interfaces/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,10 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
//! Construct wallet tx status struct.
WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
{
LockAnnotation lock(::cs_main); // Temporary, for mapBlockIndex below. Removed in upcoming commit.

WalletTxStatus result;
auto mi = ::BlockIndex().find(wtx.hashBlock);
CBlockIndex* block = mi != ::BlockIndex().end() ? mi->second : nullptr;
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
result.block_height = locked_chain.getBlockHeight(wtx.hashBlock).get_value_or(std::numeric_limits<int>::max());
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
result.time_received = wtx.nTimeReceived;
Expand Down Expand Up @@ -604,7 +602,7 @@ class WalletClientImpl : public ChainClient
: 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 load() override { return LoadWallets(m_chain, m_wallet_filenames); }
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
Expand All @@ -614,6 +612,7 @@ class WalletClientImpl : public ChainClient

Chain& m_chain;
std::vector<std::string> m_wallet_filenames;
std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
};

} // namespace
Expand Down
21 changes: 21 additions & 0 deletions src/node/coin.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions src/node/coin.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/qt/walletmodeltransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ std::unique_ptr<interfaces::PendingWalletTx>& WalletModelTransaction::getWtx()

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
Expand Down

0 comments on commit ab6f8fe

Please sign in to comment.