mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Merge f4b603cff6 into merged_master (Bitcoin PR #17993)
This commit is contained in:
commit
bfa1cef745
11 changed files with 71 additions and 40 deletions
|
|
@ -187,6 +187,11 @@ public:
|
|||
LOCK(::cs_main);
|
||||
return ::ChainActive().Height();
|
||||
}
|
||||
uint256 getBestBlockHash() override
|
||||
{
|
||||
const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
|
||||
return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
|
||||
}
|
||||
int64_t getLastBlockTime() override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
|
|
@ -310,7 +315,7 @@ public:
|
|||
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
|
||||
{
|
||||
return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
|
||||
fn(sync_state, block->nHeight, block->GetBlockTime(),
|
||||
fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
|
||||
GuessVerificationProgress(block, Params().GetConsensus().nPowTargetSpacing));
|
||||
}));
|
||||
}
|
||||
|
|
@ -318,7 +323,7 @@ public:
|
|||
{
|
||||
return MakeHandler(
|
||||
::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
|
||||
fn(sync_state, block->nHeight, block->GetBlockTime(),
|
||||
fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
|
||||
/* verification progress is unused when a header was received */ 0);
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ struct bilingual_str;
|
|||
namespace interfaces {
|
||||
class Handler;
|
||||
class Wallet;
|
||||
struct BlockTip;
|
||||
|
||||
//! Top-level interface for a bitcoin node (bitcoind process).
|
||||
class Node
|
||||
|
|
@ -149,6 +150,9 @@ public:
|
|||
//! Get num blocks.
|
||||
virtual int getNumBlocks() = 0;
|
||||
|
||||
//! Get best block hash.
|
||||
virtual uint256 getBestBlockHash() = 0;
|
||||
|
||||
//! Get last block time.
|
||||
virtual int64_t getLastBlockTime() = 0;
|
||||
|
||||
|
|
@ -250,12 +254,12 @@ public:
|
|||
|
||||
//! Register handler for block tip messages.
|
||||
using NotifyBlockTipFn =
|
||||
std::function<void(SynchronizationState, int height, int64_t block_time, double verification_progress)>;
|
||||
std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
|
||||
virtual std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) = 0;
|
||||
|
||||
//! Register handler for header tip messages.
|
||||
using NotifyHeaderTipFn =
|
||||
std::function<void(SynchronizationState, int height, int64_t block_time, double verification_progress)>;
|
||||
std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
|
||||
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
|
||||
|
||||
//! Return pointer to internal chain interface, useful for testing.
|
||||
|
|
@ -265,6 +269,13 @@ public:
|
|||
//! Return implementation of Node interface.
|
||||
std::unique_ptr<Node> MakeNode();
|
||||
|
||||
//! Block tip (could be a header or not, depends on the subscribed signal).
|
||||
struct BlockTip {
|
||||
int block_height;
|
||||
int64_t block_time;
|
||||
uint256 block_hash;
|
||||
};
|
||||
|
||||
} // namespace interfaces
|
||||
|
||||
#endif // BITCOIN_INTERFACES_NODE_H
|
||||
|
|
|
|||
|
|
@ -366,13 +366,13 @@ public:
|
|||
}
|
||||
return result;
|
||||
}
|
||||
bool tryGetBalances(WalletBalances& balances, int& num_blocks) override
|
||||
bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override
|
||||
{
|
||||
TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
|
||||
if (!locked_wallet) {
|
||||
return false;
|
||||
}
|
||||
num_blocks = m_wallet->GetLastBlockHeight();
|
||||
block_hash = m_wallet->GetLastBlockHash();
|
||||
balances = getBalances();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ public:
|
|||
virtual WalletBalances getBalances() = 0;
|
||||
|
||||
//! Get balances if possible without blocking.
|
||||
virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;
|
||||
virtual bool tryGetBalances(WalletBalances& balances, uint256& block_hash) = 0;
|
||||
|
||||
//! Get balance.
|
||||
virtual CAmountMap getBalance() = 0;
|
||||
|
|
|
|||
|
|
@ -114,6 +114,15 @@ int ClientModel::getNumBlocks() const
|
|||
return m_cached_num_blocks;
|
||||
}
|
||||
|
||||
uint256 ClientModel::getBestBlockHash()
|
||||
{
|
||||
LOCK(m_cached_tip_mutex);
|
||||
if (m_cached_tip_blocks.IsNull()) {
|
||||
m_cached_tip_blocks = m_node.getBestBlockHash();
|
||||
}
|
||||
return m_cached_tip_blocks;
|
||||
}
|
||||
|
||||
void ClientModel::updateNumConnections(int numConnections)
|
||||
{
|
||||
Q_EMIT numConnectionsChanged(numConnections);
|
||||
|
|
@ -235,14 +244,15 @@ static void BannedListChanged(ClientModel *clientmodel)
|
|||
assert(invoked);
|
||||
}
|
||||
|
||||
static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_state, int height, int64_t blockTime, double verificationProgress, bool fHeader)
|
||||
static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_state, interfaces::BlockTip tip, double verificationProgress, bool fHeader)
|
||||
{
|
||||
if (fHeader) {
|
||||
// cache best headers time and height to reduce future cs_main locks
|
||||
clientmodel->cachedBestHeaderHeight = height;
|
||||
clientmodel->cachedBestHeaderTime = blockTime;
|
||||
clientmodel->cachedBestHeaderHeight = tip.block_height;
|
||||
clientmodel->cachedBestHeaderTime = tip.block_time;
|
||||
} else {
|
||||
clientmodel->m_cached_num_blocks = height;
|
||||
clientmodel->m_cached_num_blocks = tip.block_height;
|
||||
WITH_LOCK(clientmodel->m_cached_tip_mutex, clientmodel->m_cached_tip_blocks = tip.block_hash;);
|
||||
}
|
||||
|
||||
// Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
|
||||
|
|
@ -254,8 +264,8 @@ static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_
|
|||
}
|
||||
|
||||
bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
|
||||
Q_ARG(int, height),
|
||||
Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
|
||||
Q_ARG(int, tip.block_height),
|
||||
Q_ARG(QDateTime, QDateTime::fromTime_t(tip.block_time)),
|
||||
Q_ARG(double, verificationProgress),
|
||||
Q_ARG(bool, fHeader),
|
||||
Q_ARG(SynchronizationState, sync_state));
|
||||
|
|
@ -271,8 +281,8 @@ void ClientModel::subscribeToCoreSignals()
|
|||
m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(std::bind(NotifyNetworkActiveChanged, this, std::placeholders::_1));
|
||||
m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(std::bind(NotifyAlertChanged, this));
|
||||
m_handler_banned_list_changed = m_node.handleBannedListChanged(std::bind(BannedListChanged, this));
|
||||
m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, false));
|
||||
m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, true));
|
||||
m_handler_notify_block_tip = m_node.handleNotifyBlockTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, false));
|
||||
m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, true));
|
||||
}
|
||||
|
||||
void ClientModel::unsubscribeFromCoreSignals()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <sync.h>
|
||||
#include <uint256.h>
|
||||
|
||||
class BanTableModel;
|
||||
class CBlockIndex;
|
||||
|
|
@ -57,6 +59,7 @@ public:
|
|||
//! Return number of connections, default is in- and outbound (total)
|
||||
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
|
||||
int getNumBlocks() const;
|
||||
uint256 getBestBlockHash();
|
||||
int getHeaderTipHeight() const;
|
||||
int64_t getHeaderTipTime() const;
|
||||
|
||||
|
|
@ -74,11 +77,14 @@ public:
|
|||
|
||||
bool getProxyInfo(std::string& ip_port) const;
|
||||
|
||||
// caches for the best header, number of blocks
|
||||
// caches for the best header: hash, number of blocks and block time
|
||||
mutable std::atomic<int> cachedBestHeaderHeight;
|
||||
mutable std::atomic<int64_t> cachedBestHeaderTime;
|
||||
mutable std::atomic<int> m_cached_num_blocks{-1};
|
||||
|
||||
Mutex m_cached_tip_mutex;
|
||||
uint256 m_cached_tip_blocks GUARDED_BY(m_cached_tip_mutex){};
|
||||
|
||||
private:
|
||||
interfaces::Node& m_node;
|
||||
std::unique_ptr<interfaces::Handler> m_handler_show_progress;
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
|
|||
return parts;
|
||||
}
|
||||
|
||||
void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time)
|
||||
void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time)
|
||||
{
|
||||
// Determine transaction status
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int
|
|||
typesort);
|
||||
status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
|
||||
status.depth = wtx.depth_in_main_chain;
|
||||
status.cur_num_blocks = numBlocks;
|
||||
status.m_cur_block_hash = block_hash;
|
||||
|
||||
const bool up_to_date = ((int64_t)QDateTime::currentMSecsSinceEpoch() / 1000 - block_time < MAX_BLOCK_TIME_GAP);
|
||||
if (up_to_date && !wtx.is_final) {
|
||||
|
|
@ -296,9 +296,9 @@ void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int
|
|||
status.needsUpdate = false;
|
||||
}
|
||||
|
||||
bool TransactionRecord::statusUpdateNeeded(int numBlocks) const
|
||||
bool TransactionRecord::statusUpdateNeeded(const uint256& block_hash) const
|
||||
{
|
||||
return status.cur_num_blocks != numBlocks || status.needsUpdate;
|
||||
return status.m_cur_block_hash != block_hash || status.needsUpdate;
|
||||
}
|
||||
|
||||
QString TransactionRecord::getTxHash() const
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@ struct WalletTxStatus;
|
|||
class TransactionStatus
|
||||
{
|
||||
public:
|
||||
TransactionStatus():
|
||||
countsForBalance(false), sortKey(""),
|
||||
matures_in(0), status(Unconfirmed), depth(0), open_for(0), cur_num_blocks(-1)
|
||||
TransactionStatus() : countsForBalance(false), sortKey(""),
|
||||
matures_in(0), status(Unconfirmed), depth(0), open_for(0)
|
||||
{ }
|
||||
|
||||
enum Status {
|
||||
|
|
@ -62,8 +61,8 @@ public:
|
|||
finalization */
|
||||
/**@}*/
|
||||
|
||||
/** Current number of blocks (to know whether cached status is still valid) */
|
||||
int cur_num_blocks;
|
||||
/** Current block hash (to know whether cached status is still valid) */
|
||||
uint256 m_cur_block_hash{};
|
||||
|
||||
bool needsUpdate;
|
||||
};
|
||||
|
|
@ -142,11 +141,11 @@ public:
|
|||
|
||||
/** Update status from core wallet tx.
|
||||
*/
|
||||
void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time);
|
||||
void updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time);
|
||||
|
||||
/** Return whether a status update is needed.
|
||||
*/
|
||||
bool statusUpdateNeeded(int numBlocks) const;
|
||||
bool statusUpdateNeeded(const uint256& block_hash) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_QT_TRANSACTIONRECORD_H
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ public:
|
|||
return cachedWallet.size();
|
||||
}
|
||||
|
||||
TransactionRecord *index(interfaces::Wallet& wallet, const int cur_num_blocks, const int idx)
|
||||
TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
|
||||
{
|
||||
if(idx >= 0 && idx < cachedWallet.size())
|
||||
{
|
||||
|
|
@ -195,8 +195,8 @@ public:
|
|||
interfaces::WalletTxStatus wtx;
|
||||
int numBlocks;
|
||||
int64_t block_time;
|
||||
if (rec->statusUpdateNeeded(cur_num_blocks) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
|
||||
rec->updateStatus(wtx, numBlocks, block_time);
|
||||
if (rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
|
||||
rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
|
@ -669,7 +669,7 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
|
|||
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
TransactionRecord *data = priv->index(walletModel->wallet(), walletModel->getNumBlocks(), row);
|
||||
TransactionRecord* data = priv->index(walletModel->wallet(), walletModel->clientModel().getBestBlockHash(), row);
|
||||
if(data)
|
||||
{
|
||||
return createIndex(row, column, data);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel
|
|||
transactionTableModel(nullptr),
|
||||
recentRequestsTableModel(nullptr),
|
||||
cachedEncryptionStatus(Unencrypted),
|
||||
cachedNumBlocks(0),
|
||||
timer(new QTimer(this))
|
||||
{
|
||||
fHaveWatchOnly = m_wallet->haveWatchOnly();
|
||||
|
|
@ -107,24 +106,23 @@ void WalletModel::pollBalanceChanged()
|
|||
{
|
||||
// Avoid recomputing wallet balances unless a TransactionChanged or
|
||||
// BlockTip notification was received.
|
||||
if (!fForceCheckBalanceChanged && cachedNumBlocks == m_client_model->getNumBlocks()) return;
|
||||
if (!fForceCheckBalanceChanged && m_cached_last_update_tip == m_client_model->getBestBlockHash()) return;
|
||||
|
||||
// Try to get balances and return early if locks can't be acquired. This
|
||||
// avoids the GUI from getting stuck on periodical polls if the core is
|
||||
// holding the locks for a longer time - for example, during a wallet
|
||||
// rescan.
|
||||
interfaces::WalletBalances new_balances;
|
||||
int numBlocks = -1;
|
||||
if (!m_wallet->tryGetBalances(new_balances, numBlocks)) {
|
||||
uint256 block_hash;
|
||||
if (!m_wallet->tryGetBalances(new_balances, block_hash)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(fForceCheckBalanceChanged || numBlocks != cachedNumBlocks)
|
||||
{
|
||||
if (fForceCheckBalanceChanged || block_hash != m_cached_last_update_tip) {
|
||||
fForceCheckBalanceChanged = false;
|
||||
|
||||
// Balance and number of transactions might have changed
|
||||
cachedNumBlocks = numBlocks;
|
||||
m_cached_last_update_tip = block_hash;
|
||||
|
||||
checkBalanceChanged(new_balances);
|
||||
if(transactionTableModel)
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ public:
|
|||
|
||||
interfaces::Node& node() const { return m_node; }
|
||||
interfaces::Wallet& wallet() const { return *m_wallet; }
|
||||
ClientModel& clientModel() const { return *m_client_model; }
|
||||
void setClientModel(ClientModel* client_model);
|
||||
int getNumBlocks() const { return cachedNumBlocks; }
|
||||
|
||||
QString getWalletName() const;
|
||||
QString getDisplayName() const;
|
||||
|
|
@ -183,9 +183,11 @@ private:
|
|||
interfaces::WalletBalances m_cached_balances;
|
||||
std::set<CAsset> cached_asset_types;
|
||||
EncryptionStatus cachedEncryptionStatus;
|
||||
int cachedNumBlocks;
|
||||
QTimer* timer;
|
||||
|
||||
// Block hash denoting when the last balance update was done.
|
||||
uint256 m_cached_last_update_tip{};
|
||||
|
||||
void subscribeToCoreSignals();
|
||||
void unsubscribeFromCoreSignals();
|
||||
void checkBalanceChanged(const interfaces::WalletBalances& new_balances);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue