mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
Merge pull request #5479 from knst/bc-bp-v20-missing-9
backport: bitcoin#18160, #18454, #18487, #18524, #18532, #18546, #18551, #18561, #18563, #18587
This commit is contained in:
commit
a679f8b0e5
@ -164,6 +164,7 @@ BITCOIN_TESTS =\
|
|||||||
test/validation_chainstate_tests.cpp \
|
test/validation_chainstate_tests.cpp \
|
||||||
test/validation_chainstatemanager_tests.cpp \
|
test/validation_chainstatemanager_tests.cpp \
|
||||||
test/validation_flush_tests.cpp \
|
test/validation_flush_tests.cpp \
|
||||||
|
test/validationinterface_tests.cpp \
|
||||||
test/versionbits_tests.cpp
|
test/versionbits_tests.cpp
|
||||||
|
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
|
@ -1129,8 +1129,8 @@ public:
|
|||||||
std::vector<CAddress> vAddrToSend;
|
std::vector<CAddress> vAddrToSend;
|
||||||
const std::unique_ptr<CRollingBloomFilter> m_addr_known;
|
const std::unique_ptr<CRollingBloomFilter> m_addr_known;
|
||||||
bool fGetAddr{false};
|
bool fGetAddr{false};
|
||||||
int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0};
|
std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0};
|
||||||
int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0};
|
std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0};
|
||||||
|
|
||||||
// Don't relay addr messages to peers that we connect to as block-relay-only
|
// Don't relay addr messages to peers that we connect to as block-relay-only
|
||||||
// peers (to prevent adversaries from inferring these links from addr
|
// peers (to prevent adversaries from inferring these links from addr
|
||||||
|
@ -138,9 +138,9 @@ static const int MAX_UNCONNECTING_HEADERS = 10;
|
|||||||
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
|
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
|
||||||
|
|
||||||
/** Average delay between local address broadcasts in seconds. */
|
/** Average delay between local address broadcasts in seconds. */
|
||||||
static constexpr unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60;
|
static constexpr std::chrono::hours AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24};
|
||||||
/** Average delay between peer address broadcasts in seconds. */
|
/** Average delay between peer address broadcasts in seconds. */
|
||||||
static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
|
static constexpr std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30};
|
||||||
/** Average delay between trickled inventory transmissions in seconds.
|
/** Average delay between trickled inventory transmissions in seconds.
|
||||||
* Blocks and peers with noban permission bypass this, regular outbound peers get half this delay,
|
* Blocks and peers with noban permission bypass this, regular outbound peers get half this delay,
|
||||||
* Masternode outbound peers get quarter this delay. */
|
* Masternode outbound peers get quarter this delay. */
|
||||||
@ -1889,13 +1889,13 @@ void RelayTransaction(const uint256& txid, const CConnman& connman)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
|
static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman)
|
||||||
{
|
{
|
||||||
// Relay to a limited number of other nodes
|
// Relay to a limited number of other nodes
|
||||||
// Use deterministic randomness to send to the same nodes for 24 hours
|
// Use deterministic randomness to send to the same nodes for 24 hours
|
||||||
// at a time so the m_addr_knowns of the chosen nodes prevent repeats
|
// at a time so the m_addr_knowns of the chosen nodes prevent repeats
|
||||||
uint64_t hashAddr = addr.GetHash();
|
uint64_t hashAddr = addr.GetHash();
|
||||||
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
|
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
|
||||||
FastRandomContext insecure_rand;
|
FastRandomContext insecure_rand;
|
||||||
|
|
||||||
// Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
|
// Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
|
||||||
@ -4678,16 +4678,16 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
|||||||
int64_t nNow = GetTimeMicros();
|
int64_t nNow = GetTimeMicros();
|
||||||
auto current_time = GetTime<std::chrono::microseconds>();
|
auto current_time = GetTime<std::chrono::microseconds>();
|
||||||
|
|
||||||
if (pto->IsAddrRelayPeer() && !m_chainman.ActiveChainstate().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
|
if (pto->IsAddrRelayPeer() && !m_chainman.ActiveChainstate().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) {
|
||||||
AdvertiseLocal(pto);
|
AdvertiseLocal(pto);
|
||||||
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
pto->m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Message: addr
|
// Message: addr
|
||||||
//
|
//
|
||||||
if (pto->IsAddrRelayPeer() && pto->nNextAddrSend < nNow) {
|
if (pto->IsAddrRelayPeer() && pto->m_next_addr_send < current_time) {
|
||||||
pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
|
pto->m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
|
||||||
std::vector<CAddress> vAddr;
|
std::vector<CAddress> vAddr;
|
||||||
vAddr.reserve(pto->vAddrToSend.size());
|
vAddr.reserve(pto->vAddrToSend.size());
|
||||||
|
|
||||||
|
@ -151,7 +151,6 @@ public:
|
|||||||
interfaces::Node& node() const { return m_node; }
|
interfaces::Node& node() const { return m_node; }
|
||||||
interfaces::Wallet& wallet() const { return *m_wallet; }
|
interfaces::Wallet& wallet() const { return *m_wallet; }
|
||||||
void setClientModel(ClientModel* client_model);
|
void setClientModel(ClientModel* client_model);
|
||||||
ClientModel& clientModel() const { return *m_client_model; }
|
|
||||||
interfaces::CoinJoin::Client& coinJoin() const { return m_wallet->coinJoin(); }
|
interfaces::CoinJoin::Client& coinJoin() const { return m_wallet->coinJoin(); }
|
||||||
|
|
||||||
QString getWalletName() const;
|
QString getWalletName() const;
|
||||||
|
@ -2946,6 +2946,8 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterBlockchainRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -2991,8 +2993,6 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterBlockchainRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,8 @@ static UniValue getcoinjoininfo(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
void RegisterCoinJoinRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -181,8 +183,6 @@ static const CRPCCommand commands[] =
|
|||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
void RegisterCoinJoinRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -1755,6 +1755,8 @@ static UniValue _bls(const JSONRPCRequest& request)
|
|||||||
bls_help();
|
bls_help();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void RegisterEvoRPCCommands(CRPCTable &tableRPC)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function)
|
{ // category name actor (function)
|
||||||
@ -1763,8 +1765,6 @@ static const CRPCCommand commands[] =
|
|||||||
{ "evo", "protx", &protx, {} },
|
{ "evo", "protx", &protx, {} },
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
void RegisterEvoRPCCommands(CRPCTable &tableRPC)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
tableRPC.appendCommand(command.name, &command);
|
tableRPC.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -1191,6 +1191,8 @@ static UniValue getsuperblockbudget(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
return ValueFromAmount(CSuperblock::GetPaymentsLimit(nBlockHeight));
|
return ValueFromAmount(CSuperblock::GetPaymentsLimit(nBlockHeight));
|
||||||
}
|
}
|
||||||
|
void RegisterGovernanceRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -1203,8 +1205,6 @@ static const CRPCCommand commands[] =
|
|||||||
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
void RegisterGovernanceRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -736,6 +736,9 @@ static UniValue masternodelist(const JSONRPCRequest& request, ChainstateManager&
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterMasternodeRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -744,8 +747,6 @@ static const CRPCCommand commands[] =
|
|||||||
{ "dash", "masternodelist", &masternode, {} },
|
{ "dash", "masternodelist", &masternode, {} },
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
void RegisterMasternodeRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -1249,6 +1249,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterMiningRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -1276,8 +1278,6 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterMiningRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -1363,11 +1363,12 @@ static RPCHelpMan getindexinfo()
|
|||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
void RegisterMiscRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
// --------------------- ------------------------ ----------------------- ----------
|
// --------------------- ------------------------ ----------------------- ----------
|
||||||
@ -1404,8 +1405,6 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterMiscRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -884,6 +884,8 @@ static UniValue addpeeraddress(const JSONRPCRequest& request)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterNetRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -906,8 +908,6 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterNetRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -989,6 +989,8 @@ static UniValue verifyislock(const JSONRPCRequest& request)
|
|||||||
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) ||
|
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) ||
|
||||||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
|
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
|
||||||
}
|
}
|
||||||
|
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function)
|
{ // category name actor (function)
|
||||||
@ -998,8 +1000,6 @@ static const CRPCCommand commands[] =
|
|||||||
{ "evo", "verifyislock", &verifyislock, {"id", "txid", "signature", "maxHeight"} },
|
{ "evo", "verifyislock", &verifyislock, {"id", "txid", "signature", "maxHeight"} },
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
void RegisterQuorumsRPCCommands(CRPCTable &tableRPC)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
tableRPC.appendCommand(command.name, &command);
|
tableRPC.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
@ -1682,6 +1682,8 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterRawTransactionRPCCommands(CRPCTable &t)
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -1708,8 +1710,6 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterRawTransactionRPCCommands(CRPCTable &t)
|
|
||||||
{
|
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
t.appendCommand(command.name, &command);
|
t.appendCommand(command.name, &command);
|
||||||
}
|
}
|
||||||
|
60
src/test/validationinterface_tests.cpp
Normal file
60
src/test/validationinterface_tests.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (c) 2020 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 <boost/test/unit_test.hpp>
|
||||||
|
#include <consensus/validation.h>
|
||||||
|
#include <primitives/block.h>
|
||||||
|
#include <scheduler.h>
|
||||||
|
#include <test/util/setup_common.h>
|
||||||
|
#include <util/check.h>
|
||||||
|
#include <validationinterface.h>
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup)
|
||||||
|
|
||||||
|
class TestInterface : public CValidationInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestInterface(std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr)
|
||||||
|
: m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~TestInterface()
|
||||||
|
{
|
||||||
|
if (m_on_destroy) m_on_destroy();
|
||||||
|
}
|
||||||
|
void BlockChecked(const CBlock& block, const BlockValidationState& state) override
|
||||||
|
{
|
||||||
|
if (m_on_call) m_on_call();
|
||||||
|
}
|
||||||
|
static void Call()
|
||||||
|
{
|
||||||
|
CBlock block;
|
||||||
|
BlockValidationState state;
|
||||||
|
GetMainSignals().BlockChecked(block, state);
|
||||||
|
}
|
||||||
|
std::function<void()> m_on_call;
|
||||||
|
std::function<void()> m_on_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Regression test to ensure UnregisterAllValidationInterfaces calls don't
|
||||||
|
// destroy a validation interface while it is being called. Bug:
|
||||||
|
// https://github.com/bitcoin/bitcoin/pull/18551
|
||||||
|
BOOST_AUTO_TEST_CASE(unregister_all_during_call)
|
||||||
|
{
|
||||||
|
bool destroyed = false;
|
||||||
|
RegisterSharedValidationInterface(std::make_shared<TestInterface>(
|
||||||
|
[&] {
|
||||||
|
// First call should decrements reference count 2 -> 1
|
||||||
|
UnregisterAllValidationInterfaces();
|
||||||
|
BOOST_CHECK(!destroyed);
|
||||||
|
// Second call should not decrement reference count 1 -> 0
|
||||||
|
UnregisterAllValidationInterfaces();
|
||||||
|
BOOST_CHECK(!destroyed);
|
||||||
|
},
|
||||||
|
[&] { destroyed = true; }));
|
||||||
|
TestInterface::Call();
|
||||||
|
BOOST_CHECK(destroyed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
@ -21,56 +21,75 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <boost/signals2/signal.hpp>
|
//! The MainSignalsInstance manages a list of shared_ptr<CValidationInterface>
|
||||||
|
//! callbacks.
|
||||||
struct ValidationInterfaceConnections {
|
//!
|
||||||
boost::signals2::scoped_connection UpdatedBlockTip;
|
//! A std::unordered_map is used to track what callbacks are currently
|
||||||
boost::signals2::scoped_connection SynchronousUpdatedBlockTip;
|
//! registered, and a std::list is to used to store the callbacks that are
|
||||||
boost::signals2::scoped_connection TransactionAddedToMempool;
|
//! currently registered as well as any callbacks that are just unregistered
|
||||||
boost::signals2::scoped_connection BlockConnected;
|
//! and about to be deleted when they are done executing.
|
||||||
boost::signals2::scoped_connection BlockDisconnected;
|
|
||||||
boost::signals2::scoped_connection TransactionRemovedFromMempool;
|
|
||||||
boost::signals2::scoped_connection ChainStateFlushed;
|
|
||||||
boost::signals2::scoped_connection BlockChecked;
|
|
||||||
boost::signals2::scoped_connection NewPoWValidBlock;
|
|
||||||
boost::signals2::scoped_connection AcceptedBlockHeader;
|
|
||||||
boost::signals2::scoped_connection NotifyHeaderTip;
|
|
||||||
boost::signals2::scoped_connection NotifyTransactionLock;
|
|
||||||
boost::signals2::scoped_connection NotifyChainLock;
|
|
||||||
boost::signals2::scoped_connection NotifyGovernanceVote;
|
|
||||||
boost::signals2::scoped_connection NotifyGovernanceObject;
|
|
||||||
boost::signals2::scoped_connection NotifyInstantSendDoubleSpendAttempt;
|
|
||||||
boost::signals2::scoped_connection NotifyMasternodeListChanged;
|
|
||||||
boost::signals2::scoped_connection NotifyRecoveredSig;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MainSignalsInstance {
|
struct MainSignalsInstance {
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
|
private:
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> SynchronousUpdatedBlockTip;
|
Mutex m_mutex;
|
||||||
boost::signals2::signal<void (const CTransactionRef &, int64_t)> TransactionAddedToMempool;
|
//! List entries consist of a callback pointer and reference count. The
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex)> BlockConnected;
|
//! count is equal to the number of current executions of that entry, plus 1
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
|
//! if it's registered. It cannot be 0 because that would imply it is
|
||||||
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
|
//! unregistered and also not being executed (so shouldn't exist).
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
|
||||||
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
|
std::list<ListEntry> m_list GUARDED_BY(m_mutex);
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
|
||||||
boost::signals2::signal<void (const CBlockIndex *)>AcceptedBlockHeader;
|
|
||||||
boost::signals2::signal<void (const CBlockIndex *, bool)>NotifyHeaderTip;
|
public:
|
||||||
boost::signals2::signal<void (const CTransactionRef& tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock)>NotifyTransactionLock;
|
|
||||||
boost::signals2::signal<void (const CBlockIndex* pindex, const std::shared_ptr<const llmq::CChainLockSig>& clsig)>NotifyChainLock;
|
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CGovernanceVote>& vote)>NotifyGovernanceVote;
|
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CGovernanceObject>& object)>NotifyGovernanceObject;
|
|
||||||
boost::signals2::signal<void (const CTransactionRef& currentTx, const CTransactionRef& previousTx)>NotifyInstantSendDoubleSpendAttempt;
|
|
||||||
boost::signals2::signal<void (bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)>NotifyMasternodeListChanged;
|
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const llmq::CRecoveredSig>& sig)>NotifyRecoveredSig;
|
|
||||||
// We are not allowed to assume the scheduler only runs in one thread,
|
// We are not allowed to assume the scheduler only runs in one thread,
|
||||||
// but must ensure all callbacks happen in-order, so we end up creating
|
// but must ensure all callbacks happen in-order, so we end up creating
|
||||||
// our own queue here :(
|
// our own queue here :(
|
||||||
SingleThreadedSchedulerClient m_schedulerClient;
|
SingleThreadedSchedulerClient m_schedulerClient;
|
||||||
std::unordered_map<CValidationInterface*, ValidationInterfaceConnections> m_connMainSignals;
|
|
||||||
|
|
||||||
explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
|
explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
|
||||||
|
|
||||||
|
void Register(std::shared_ptr<CValidationInterface> callbacks)
|
||||||
|
{
|
||||||
|
LOCK(m_mutex);
|
||||||
|
auto inserted = m_map.emplace(callbacks.get(), m_list.end());
|
||||||
|
if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
|
||||||
|
inserted.first->second->callbacks = std::move(callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unregister(CValidationInterface* callbacks)
|
||||||
|
{
|
||||||
|
LOCK(m_mutex);
|
||||||
|
auto it = m_map.find(callbacks);
|
||||||
|
if (it != m_map.end()) {
|
||||||
|
if (!--it->second->count) m_list.erase(it->second);
|
||||||
|
m_map.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Clear unregisters every previously registered callback, erasing every
|
||||||
|
//! map entry. After this call, the list may still contain callbacks that
|
||||||
|
//! are currently executing, but it will be cleared when they are done
|
||||||
|
//! executing.
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
LOCK(m_mutex);
|
||||||
|
for (const auto& entry : m_map) {
|
||||||
|
if (!--entry.second->count) m_list.erase(entry.second);
|
||||||
|
}
|
||||||
|
m_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F> void Iterate(F&& f)
|
||||||
|
{
|
||||||
|
WAIT_LOCK(m_mutex, lock);
|
||||||
|
for (auto it = m_list.begin(); it != m_list.end();) {
|
||||||
|
++it->count;
|
||||||
|
{
|
||||||
|
REVERSE_LOCK(lock);
|
||||||
|
f(*it->callbacks);
|
||||||
|
}
|
||||||
|
it = --it->count ? std::next(it) : m_list.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static CMainSignals g_signals;
|
static CMainSignals g_signals;
|
||||||
@ -103,25 +122,7 @@ CMainSignals& GetMainSignals()
|
|||||||
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn) {
|
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn) {
|
||||||
// Each connection captures pwalletIn to ensure that each callback is
|
// Each connection captures pwalletIn to ensure that each callback is
|
||||||
// executed before pwalletIn is destroyed. For more details see #18338.
|
// executed before pwalletIn is destroyed. For more details see #18338.
|
||||||
ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn.get()];
|
g_signals.m_internals->Register(std::move(pwalletIn));
|
||||||
conns.AcceptedBlockHeader = g_signals.m_internals->AcceptedBlockHeader.connect(std::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, std::placeholders::_1));
|
|
||||||
conns.NotifyHeaderTip = g_signals.m_internals->NotifyHeaderTip.connect(std::bind(&CValidationInterface::NotifyHeaderTip, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
|
||||||
conns.SynchronousUpdatedBlockTip = g_signals.m_internals->SynchronousUpdatedBlockTip.connect(std::bind(&CValidationInterface::SynchronousUpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
|
||||||
conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.NotifyTransactionLock = g_signals.m_internals->NotifyTransactionLock.connect(std::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.NotifyChainLock = g_signals.m_internals->NotifyChainLock.connect(std::bind(&CValidationInterface::NotifyChainLock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
|
|
||||||
conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.NewPoWValidBlock = g_signals.m_internals->NewPoWValidBlock.connect(std::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.NotifyGovernanceObject = g_signals.m_internals->NotifyGovernanceObject.connect(std::bind(&CValidationInterface::NotifyGovernanceObject, pwalletIn, std::placeholders::_1));
|
|
||||||
conns.NotifyGovernanceVote = g_signals.m_internals->NotifyGovernanceVote.connect(std::bind(&CValidationInterface::NotifyGovernanceVote, pwalletIn, std::placeholders::_1));
|
|
||||||
conns.NotifyInstantSendDoubleSpendAttempt = g_signals.m_internals->NotifyInstantSendDoubleSpendAttempt.connect(std::bind(&CValidationInterface::NotifyInstantSendDoubleSpendAttempt, pwalletIn, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
conns.NotifyRecoveredSig = g_signals.m_internals->NotifyRecoveredSig.connect(std::bind(&CValidationInterface::NotifyRecoveredSig, pwalletIn, std::placeholders::_1));
|
|
||||||
conns.NotifyMasternodeListChanged = g_signals.m_internals->NotifyMasternodeListChanged.connect(std::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterValidationInterface(CValidationInterface* callbacks)
|
void RegisterValidationInterface(CValidationInterface* callbacks)
|
||||||
@ -138,7 +139,7 @@ void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> c
|
|||||||
|
|
||||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
if (g_signals.m_internals) {
|
if (g_signals.m_internals) {
|
||||||
g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
|
g_signals.m_internals->Unregister(pwalletIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ void UnregisterAllValidationInterfaces() {
|
|||||||
if (!g_signals.m_internals) {
|
if (!g_signals.m_internals) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_signals.m_internals->m_connMainSignals.clear();
|
g_signals.m_internals->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
|
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
|
||||||
@ -186,7 +187,7 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
|
|||||||
// in the same critical section where the chain is updated
|
// in the same critical section where the chain is updated
|
||||||
|
|
||||||
auto event = [pindexNew, pindexFork, fInitialDownload, this] {
|
auto event = [pindexNew, pindexFork, fInitialDownload, this] {
|
||||||
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
|
||||||
pindexNew->GetBlockHash().ToString(),
|
pindexNew->GetBlockHash().ToString(),
|
||||||
@ -195,12 +196,12 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::SynchronousUpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
|
void CMainSignals::SynchronousUpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
|
||||||
m_internals->SynchronousUpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.SynchronousUpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx, int64_t nAcceptTime) {
|
void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx, int64_t nAcceptTime) {
|
||||||
auto event = [ptx, nAcceptTime, this] {
|
auto event = [ptx, nAcceptTime, this] {
|
||||||
m_internals->TransactionAddedToMempool(ptx, nAcceptTime);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(ptx, nAcceptTime); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__,
|
||||||
ptx->GetHash().ToString());
|
ptx->GetHash().ToString());
|
||||||
@ -208,7 +209,7 @@ void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx, int64_t
|
|||||||
|
|
||||||
void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) {
|
void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) {
|
||||||
auto event = [ptx, reason, this] {
|
auto event = [ptx, reason, this] {
|
||||||
m_internals->TransactionRemovedFromMempool(ptx, reason);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(ptx, reason); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__,
|
||||||
ptx->GetHash().ToString());
|
ptx->GetHash().ToString());
|
||||||
@ -216,7 +217,7 @@ void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx, Mem
|
|||||||
|
|
||||||
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
|
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
|
||||||
auto event = [pblock, pindex, this] {
|
auto event = [pblock, pindex, this] {
|
||||||
m_internals->BlockConnected(pblock, pindex);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
|
||||||
pblock->GetHash().ToString(),
|
pblock->GetHash().ToString(),
|
||||||
@ -225,7 +226,7 @@ void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, c
|
|||||||
|
|
||||||
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex* pindex) {
|
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex* pindex) {
|
||||||
auto event = [pblock, pindex, this] {
|
auto event = [pblock, pindex, this] {
|
||||||
m_internals->BlockDisconnected(pblock, pindex);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
|
||||||
pblock->GetHash().ToString(),
|
pblock->GetHash().ToString(),
|
||||||
@ -234,7 +235,7 @@ void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock
|
|||||||
|
|
||||||
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
||||||
auto event = [locator, this] {
|
auto event = [locator, this] {
|
||||||
m_internals->ChainStateFlushed(locator);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
|
||||||
locator.IsNull() ? "null" : locator.vHave.front().ToString());
|
locator.IsNull() ? "null" : locator.vHave.front().ToString());
|
||||||
@ -243,27 +244,27 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
|||||||
void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||||
LOG_EVENT("%s: block hash=%s state=%s", __func__,
|
LOG_EVENT("%s: block hash=%s state=%s", __func__,
|
||||||
block.GetHash().ToString(), state.ToString());
|
block.GetHash().ToString(), state.ToString());
|
||||||
m_internals->BlockChecked(block, state);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
|
void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
|
||||||
LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
|
LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
|
||||||
m_internals->NewPoWValidBlock(pindex, block);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::AcceptedBlockHeader(const CBlockIndex *pindexNew) {
|
void CMainSignals::AcceptedBlockHeader(const CBlockIndex *pindexNew) {
|
||||||
LOG_EVENT("%s: accepted block header hash=%s", __func__, pindexNew->GetBlockHash().ToString());
|
LOG_EVENT("%s: accepted block header hash=%s", __func__, pindexNew->GetBlockHash().ToString());
|
||||||
m_internals->AcceptedBlockHeader(pindexNew);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.AcceptedBlockHeader(pindexNew); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) {
|
void CMainSignals::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) {
|
||||||
LOG_EVENT("%s: accepted block header hash=%s initial=%d", __func__, pindexNew->GetBlockHash().ToString(), fInitialDownload);
|
LOG_EVENT("%s: accepted block header hash=%s initial=%d", __func__, pindexNew->GetBlockHash().ToString(), fInitialDownload);
|
||||||
m_internals->NotifyHeaderTip(pindexNew, fInitialDownload);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyHeaderTip(pindexNew, fInitialDownload); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) {
|
void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) {
|
||||||
auto event = [tx, islock, this] {
|
auto event = [tx, islock, this] {
|
||||||
m_internals->NotifyTransactionLock(tx, islock);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyTransactionLock(tx, islock); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: transaction lock txid=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: transaction lock txid=%s", __func__,
|
||||||
tx->GetHash().ToString());
|
tx->GetHash().ToString());
|
||||||
@ -271,7 +272,7 @@ void CMainSignals::NotifyTransactionLock(const CTransactionRef &tx, const std::s
|
|||||||
|
|
||||||
void CMainSignals::NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr<const llmq::CChainLockSig>& clsig) {
|
void CMainSignals::NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr<const llmq::CChainLockSig>& clsig) {
|
||||||
auto event = [pindex, clsig, this] {
|
auto event = [pindex, clsig, this] {
|
||||||
m_internals->NotifyChainLock(pindex, clsig);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyChainLock(pindex, clsig); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: notify chainlock at block=%s cl=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: notify chainlock at block=%s cl=%s", __func__,
|
||||||
pindex->GetBlockHash().ToString(),
|
pindex->GetBlockHash().ToString(),
|
||||||
@ -280,21 +281,21 @@ void CMainSignals::NotifyChainLock(const CBlockIndex* pindex, const std::shared_
|
|||||||
|
|
||||||
void CMainSignals::NotifyGovernanceVote(const std::shared_ptr<const CGovernanceVote>& vote) {
|
void CMainSignals::NotifyGovernanceVote(const std::shared_ptr<const CGovernanceVote>& vote) {
|
||||||
auto event = [vote, this] {
|
auto event = [vote, this] {
|
||||||
m_internals->NotifyGovernanceVote(vote);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyGovernanceVote(vote); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance vote: %s", __func__, vote->GetHash().ToString());
|
ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance vote: %s", __func__, vote->GetHash().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::NotifyGovernanceObject(const std::shared_ptr<const CGovernanceObject>& object) {
|
void CMainSignals::NotifyGovernanceObject(const std::shared_ptr<const CGovernanceObject>& object) {
|
||||||
auto event = [object, this] {
|
auto event = [object, this] {
|
||||||
m_internals->NotifyGovernanceObject(object);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyGovernanceObject(object); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance object: %s", __func__, object->GetHash().ToString());
|
ENQUEUE_AND_LOG_EVENT(event, "%s: notify governance object: %s", __func__, object->GetHash().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) {
|
void CMainSignals::NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) {
|
||||||
auto event = [currentTx, previousTx, this] {
|
auto event = [currentTx, previousTx, this] {
|
||||||
m_internals->NotifyInstantSendDoubleSpendAttempt(currentTx, previousTx);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyInstantSendDoubleSpendAttempt(currentTx, previousTx); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: notify instant doublespendattempt currenttxid=%s previoustxid=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: notify instant doublespendattempt currenttxid=%s previoustxid=%s", __func__,
|
||||||
currentTx->GetHash().ToString(),
|
currentTx->GetHash().ToString(),
|
||||||
@ -303,7 +304,7 @@ void CMainSignals::NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& cu
|
|||||||
|
|
||||||
void CMainSignals::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& sig) {
|
void CMainSignals::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& sig) {
|
||||||
auto event = [sig, this] {
|
auto event = [sig, this] {
|
||||||
m_internals->NotifyRecoveredSig(sig);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyRecoveredSig(sig); });
|
||||||
};
|
};
|
||||||
ENQUEUE_AND_LOG_EVENT(event, "%s: notify recoveredsig=%s", __func__,
|
ENQUEUE_AND_LOG_EVENT(event, "%s: notify recoveredsig=%s", __func__,
|
||||||
sig->GetHash().ToString());
|
sig->GetHash().ToString());
|
||||||
@ -311,5 +312,5 @@ void CMainSignals::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecover
|
|||||||
|
|
||||||
void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman) {
|
void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman) {
|
||||||
LOG_EVENT("%s: notify mn list changed undo=%d", __func__, undo);
|
LOG_EVENT("%s: notify mn list changed undo=%d", __func__, undo);
|
||||||
m_internals->NotifyMasternodeListChanged(undo, oldMNList, diff, connman);
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyMasternodeListChanged(undo, oldMNList, diff, connman); });
|
||||||
}
|
}
|
||||||
|
@ -194,9 +194,7 @@ protected:
|
|||||||
* Notifies listeners that a block which builds directly on our current tip
|
* Notifies listeners that a block which builds directly on our current tip
|
||||||
* has been received and connected to the headers tree, though not validated yet */
|
* has been received and connected to the headers tree, though not validated yet */
|
||||||
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
|
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
|
||||||
friend void ::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface>);
|
friend class CMainSignals;
|
||||||
friend void ::UnregisterValidationInterface(CValidationInterface*);
|
|
||||||
friend void ::UnregisterAllValidationInterfaces();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MainSignalsInstance;
|
struct MainSignalsInstance;
|
||||||
|
@ -245,7 +245,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (name) {
|
if (name) {
|
||||||
*name = it->second.name;
|
*name = it->second.GetLabel();
|
||||||
}
|
}
|
||||||
if (is_mine) {
|
if (is_mine) {
|
||||||
*is_mine = m_wallet->IsMine(dest);
|
*is_mine = m_wallet->IsMine(dest);
|
||||||
@ -261,7 +261,7 @@ public:
|
|||||||
std::vector<WalletAddress> result;
|
std::vector<WalletAddress> result;
|
||||||
for (const auto& item : m_wallet->m_address_book) {
|
for (const auto& item : m_wallet->m_address_book) {
|
||||||
if (item.second.IsChange()) continue;
|
if (item.second.IsChange()) continue;
|
||||||
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.name, item.second.purpose);
|
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.GetLabel(), item.second.purpose);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1014,7 +1014,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||||||
file << strprintf("%s %s ", EncodeSecret(key), strTime);
|
file << strprintf("%s %s ", EncodeSecret(key), strTime);
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(pkhash);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(pkhash);
|
||||||
if (address_book_entry) {
|
if (address_book_entry) {
|
||||||
file << strprintf("label=%s", EncodeDumpString(address_book_entry->name));
|
file << strprintf("label=%s", EncodeDumpString(address_book_entry->GetLabel()));
|
||||||
} else if (mapKeyPool.count(keyid)) {
|
} else if (mapKeyPool.count(keyid)) {
|
||||||
file << "reserve=1";
|
file << "reserve=1";
|
||||||
} else {
|
} else {
|
||||||
|
@ -532,7 +532,7 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
||||||
if (address_book_entry) {
|
if (address_book_entry) {
|
||||||
addressInfo.push_back(address_book_entry->name);
|
addressInfo.push_back(address_book_entry->GetLabel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsonGrouping.push_back(addressInfo);
|
jsonGrouping.push_back(addressInfo);
|
||||||
@ -1151,7 +1151,7 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
|||||||
{
|
{
|
||||||
if (item_it->second.IsChange()) continue;
|
if (item_it->second.IsChange()) continue;
|
||||||
const CTxDestination& address = item_it->first;
|
const CTxDestination& address = item_it->first;
|
||||||
const std::string& label = item_it->second.name;
|
const std::string& label = item_it->second.GetLabel();
|
||||||
auto it = mapTally.find(address);
|
auto it = mapTally.find(address);
|
||||||
if (it == mapTally.end() && !fIncludeEmpty)
|
if (it == mapTally.end() && !fIncludeEmpty)
|
||||||
continue;
|
continue;
|
||||||
@ -1354,7 +1354,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
|||||||
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
|
||||||
if (address_book_entry) {
|
if (address_book_entry) {
|
||||||
entry.pushKV("label", address_book_entry->name);
|
entry.pushKV("label", address_book_entry->GetLabel());
|
||||||
}
|
}
|
||||||
entry.pushKV("vout", s.vout);
|
entry.pushKV("vout", s.vout);
|
||||||
entry.pushKV("fee", ValueFromAmount(-nFee));
|
entry.pushKV("fee", ValueFromAmount(-nFee));
|
||||||
@ -1373,7 +1373,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
|||||||
std::string label;
|
std::string label;
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
|
||||||
if (address_book_entry) {
|
if (address_book_entry) {
|
||||||
label = address_book_entry->name;
|
label = address_book_entry->GetLabel();
|
||||||
}
|
}
|
||||||
if (filter_label && label != *filter_label) {
|
if (filter_label && label != *filter_label) {
|
||||||
continue;
|
continue;
|
||||||
@ -1934,54 +1934,62 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
if (!wallet) return NullUniValue;
|
if (!wallet) return NullUniValue;
|
||||||
CWallet* const pwallet = wallet.get();
|
CWallet* const pwallet = wallet.get();
|
||||||
|
|
||||||
LOCK(pwallet->cs_wallet);
|
int64_t nSleepTime;
|
||||||
|
{
|
||||||
|
LOCK(pwallet->cs_wallet);
|
||||||
|
|
||||||
|
if (!pwallet->IsCrypted()) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
|
||||||
|
SecureString strWalletPass;
|
||||||
|
strWalletPass.reserve(100);
|
||||||
|
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
||||||
|
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
|
||||||
|
strWalletPass = request.params[0].get_str().c_str();
|
||||||
|
|
||||||
|
// Get the timeout
|
||||||
|
nSleepTime = request.params[1].get_int64();
|
||||||
|
// Timeout cannot be negative, otherwise it will relock immediately
|
||||||
|
if (nSleepTime < 0) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
|
||||||
|
}
|
||||||
|
// Clamp timeout
|
||||||
|
constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
|
||||||
|
if (nSleepTime > MAX_SLEEP_TIME) {
|
||||||
|
nSleepTime = MAX_SLEEP_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fForMixingOnly = false;
|
||||||
|
if (!request.params[2].isNull())
|
||||||
|
fForMixingOnly = request.params[2].get_bool();
|
||||||
|
|
||||||
|
if (fForMixingOnly && !pwallet->IsLocked()) {
|
||||||
|
// Downgrading from "fuly unlocked" mode to "mixing only" one is not supported.
|
||||||
|
// Updating unlock time when current unlock mode is not changed or when it is upgraded
|
||||||
|
// from "mixing only" to "fuly unlocked" is ok.
|
||||||
|
throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already fully unlocked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strWalletPass.empty()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pwallet->Unlock(strWalletPass, fForMixingOnly)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pwallet->TopUpKeyPool();
|
||||||
|
|
||||||
|
pwallet->nRelockTime = GetTime() + nSleepTime;
|
||||||
|
|
||||||
if (!pwallet->IsCrypted()) {
|
|
||||||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
|
|
||||||
}
|
}
|
||||||
|
// rpcRunLater must be called without cs_wallet held otherwise a deadlock
|
||||||
// Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
|
// can occur. The deadlock would happen when RPCRunLater removes the
|
||||||
SecureString strWalletPass;
|
// previous timer (and waits for the callback to finish if already running)
|
||||||
strWalletPass.reserve(100);
|
// and the callback locks cs_wallet.
|
||||||
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
AssertLockNotHeld(wallet->cs_wallet);
|
||||||
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
|
|
||||||
strWalletPass = request.params[0].get_str().c_str();
|
|
||||||
|
|
||||||
// Get the timeout
|
|
||||||
int64_t nSleepTime = request.params[1].get_int64();
|
|
||||||
// Timeout cannot be negative, otherwise it will relock immediately
|
|
||||||
if (nSleepTime < 0) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
|
|
||||||
}
|
|
||||||
// Clamp timeout
|
|
||||||
constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
|
|
||||||
if (nSleepTime > MAX_SLEEP_TIME) {
|
|
||||||
nSleepTime = MAX_SLEEP_TIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fForMixingOnly = false;
|
|
||||||
if (!request.params[2].isNull())
|
|
||||||
fForMixingOnly = request.params[2].get_bool();
|
|
||||||
|
|
||||||
if (fForMixingOnly && !pwallet->IsLocked()) {
|
|
||||||
// Downgrading from "fuly unlocked" mode to "mixing only" one is not supported.
|
|
||||||
// Updating unlock time when current unlock mode is not changed or when it is upgraded
|
|
||||||
// from "mixing only" to "fuly unlocked" is ok.
|
|
||||||
throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already fully unlocked.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strWalletPass.empty()) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pwallet->Unlock(strWalletPass, fForMixingOnly)) {
|
|
||||||
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pwallet->TopUpKeyPool();
|
|
||||||
|
|
||||||
pwallet->nRelockTime = GetTime() + nSleepTime;
|
|
||||||
|
|
||||||
// Keep a weak pointer to the wallet so that it is possible to unload the
|
// Keep a weak pointer to the wallet so that it is possible to unload the
|
||||||
// wallet before the following callback is called. If a valid shared pointer
|
// wallet before the following callback is called. If a valid shared pointer
|
||||||
// is acquired in the callback then the wallet is still loaded.
|
// is acquired in the callback then the wallet is still loaded.
|
||||||
@ -3186,7 +3194,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
||||||
if (address_book_entry) {
|
if (address_book_entry) {
|
||||||
entry.pushKV("label", address_book_entry->name);
|
entry.pushKV("label", address_book_entry->GetLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
||||||
@ -3706,7 +3714,7 @@ static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool v
|
|||||||
{
|
{
|
||||||
UniValue ret(UniValue::VOBJ);
|
UniValue ret(UniValue::VOBJ);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
ret.pushKV("name", data.name);
|
ret.pushKV("name", data.GetLabel());
|
||||||
}
|
}
|
||||||
ret.pushKV("purpose", data.purpose);
|
ret.pushKV("purpose", data.purpose);
|
||||||
return ret;
|
return ret;
|
||||||
@ -3808,7 +3816,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
|||||||
// value of the name key/value pair in the labels array below.
|
// value of the name key/value pair in the labels array below.
|
||||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
|
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
|
||||||
if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
|
if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
|
||||||
ret.pushKV("label", address_book_entry->name);
|
ret.pushKV("label", address_book_entry->GetLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
||||||
@ -3844,7 +3852,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
|||||||
if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
|
if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
|
||||||
labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
|
labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
|
||||||
} else {
|
} else {
|
||||||
labels.push_back(address_book_entry->name);
|
labels.push_back(address_book_entry->GetLabel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.pushKV("labels", std::move(labels));
|
ret.pushKV("labels", std::move(labels));
|
||||||
@ -3887,7 +3895,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
|
|||||||
std::set<std::string> addresses;
|
std::set<std::string> addresses;
|
||||||
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
|
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
|
||||||
if (item.second.IsChange()) continue;
|
if (item.second.IsChange()) continue;
|
||||||
if (item.second.name == label) {
|
if (item.second.GetLabel() == label) {
|
||||||
std::string address = EncodeDestination(item.first);
|
std::string address = EncodeDestination(item.first);
|
||||||
// CWallet::m_address_book is not expected to contain duplicate
|
// CWallet::m_address_book is not expected to contain duplicate
|
||||||
// address strings, but build a separate set as a precaution just in
|
// address strings, but build a separate set as a precaution just in
|
||||||
@ -3950,7 +3958,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
|
|||||||
for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
|
for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
|
||||||
if (entry.second.IsChange()) continue;
|
if (entry.second.IsChange()) continue;
|
||||||
if (purpose.empty() || entry.second.purpose == purpose) {
|
if (purpose.empty() || entry.second.purpose == purpose) {
|
||||||
label_set.insert(entry.second.name);
|
label_set.insert(entry.second.GetLabel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4188,6 +4196,8 @@ static UniValue upgradewallet(const JSONRPCRequest& request)
|
|||||||
return error.original;
|
return error.original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<const CRPCCommand> GetWalletRPCCommands()
|
||||||
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const CRPCCommand commands[] =
|
static const CRPCCommand commands[] =
|
||||||
{ // category name actor (function) argNames
|
{ // category name actor (function) argNames
|
||||||
@ -4258,7 +4268,5 @@ static const CRPCCommand commands[] =
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
Span<const CRPCCommand> GetWalletRPCCommands()
|
|
||||||
{
|
|
||||||
return MakeSpan(commands);
|
return MakeSpan(commands);
|
||||||
}
|
}
|
||||||
|
@ -3938,7 +3938,10 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
|||||||
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
|
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
|
||||||
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
||||||
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
||||||
assert(!IsMine(address));
|
if (IsMine(address)) {
|
||||||
|
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
@ -4190,7 +4193,7 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
|
|||||||
{
|
{
|
||||||
if (item.second.IsChange()) continue;
|
if (item.second.IsChange()) continue;
|
||||||
const CTxDestination& address = item.first;
|
const CTxDestination& address = item.first;
|
||||||
const std::string& strName = item.second.name;
|
const std::string& strName = item.second.GetLabel();
|
||||||
if (strName == label)
|
if (strName == label)
|
||||||
result.insert(address);
|
result.insert(address);
|
||||||
}
|
}
|
||||||
|
@ -191,15 +191,15 @@ private:
|
|||||||
bool m_change{true};
|
bool m_change{true};
|
||||||
std::string m_label;
|
std::string m_label;
|
||||||
public:
|
public:
|
||||||
const std::string& name;
|
|
||||||
std::string purpose;
|
std::string purpose;
|
||||||
|
|
||||||
CAddressBookData() : name(m_label), purpose("unknown") {}
|
CAddressBookData() : purpose("unknown") {}
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> StringMap;
|
typedef std::map<std::string, std::string> StringMap;
|
||||||
StringMap destdata;
|
StringMap destdata;
|
||||||
|
|
||||||
bool IsChange() const { return m_change; }
|
bool IsChange() const { return m_change; }
|
||||||
|
const std::string& GetLabel() const { return m_label; }
|
||||||
void SetLabel(const std::string& label) {
|
void SetLabel(const std::string& label) {
|
||||||
m_change = false;
|
m_change = false;
|
||||||
m_label = label;
|
m_label = label;
|
||||||
|
69
test/functional/p2p_addr_relay.py
Executable file
69
test/functional/p2p_addr_relay.py
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2020 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
"""
|
||||||
|
Test addr relay
|
||||||
|
"""
|
||||||
|
|
||||||
|
from test_framework.messages import (
|
||||||
|
CAddress,
|
||||||
|
NODE_NETWORK,
|
||||||
|
msg_addr,
|
||||||
|
)
|
||||||
|
from test_framework.mininode import (
|
||||||
|
P2PInterface,
|
||||||
|
)
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import (
|
||||||
|
assert_equal,
|
||||||
|
)
|
||||||
|
import time
|
||||||
|
|
||||||
|
ADDRS = []
|
||||||
|
for i in range(10):
|
||||||
|
addr = CAddress()
|
||||||
|
addr.time = int(time.time()) + i
|
||||||
|
addr.nServices = NODE_NETWORK
|
||||||
|
addr.ip = "123.123.123.{}".format(i % 256)
|
||||||
|
addr.port = 8333 + i
|
||||||
|
ADDRS.append(addr)
|
||||||
|
|
||||||
|
|
||||||
|
class AddrReceiver(P2PInterface):
|
||||||
|
def on_addr(self, message):
|
||||||
|
for addr in message.addrs:
|
||||||
|
assert_equal(addr.nServices, 9)
|
||||||
|
assert addr.ip.startswith('123.123.123.')
|
||||||
|
assert (8333 <= addr.port < 8343)
|
||||||
|
|
||||||
|
|
||||||
|
class AddrTest(BitcoinTestFramework):
|
||||||
|
def set_test_params(self):
|
||||||
|
self.setup_clean_chain = False
|
||||||
|
self.num_nodes = 1
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
self.log.info('Create connection that sends addr messages')
|
||||||
|
addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
|
||||||
|
msg = msg_addr()
|
||||||
|
|
||||||
|
self.log.info('Send too large addr message')
|
||||||
|
msg.addrs = ADDRS * 101
|
||||||
|
with self.nodes[0].assert_debug_log(['addr message size = 1010']):
|
||||||
|
addr_source.send_and_ping(msg)
|
||||||
|
|
||||||
|
self.log.info('Check that addr message content is relayed and added to addrman')
|
||||||
|
addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver())
|
||||||
|
msg.addrs = ADDRS
|
||||||
|
with self.nodes[0].assert_debug_log([
|
||||||
|
'Added 10 addresses from 127.0.0.1: 0 tried',
|
||||||
|
'received: addr (301 bytes) peer=0',
|
||||||
|
]):
|
||||||
|
addr_source.send_and_ping(msg)
|
||||||
|
self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
|
||||||
|
addr_receiver.sync_with_ping()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
AddrTest().main()
|
@ -272,6 +272,10 @@ class TestNode():
|
|||||||
# -342 Service unavailable, RPC server started but is shutting down due to error
|
# -342 Service unavailable, RPC server started but is shutting down due to error
|
||||||
if e.error['code'] != -28 and e.error['code'] != -342:
|
if e.error['code'] != -28 and e.error['code'] != -342:
|
||||||
raise # unknown JSON RPC exception
|
raise # unknown JSON RPC exception
|
||||||
|
except ConnectionResetError:
|
||||||
|
# This might happen when the RPC server is in warmup, but shut down before the call to getblockcount
|
||||||
|
# succeeds. Try again to properly raise the FailedToStartError
|
||||||
|
pass
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ETIMEDOUT:
|
if e.errno == errno.ETIMEDOUT:
|
||||||
pass # Treat identical to ConnectionResetError
|
pass # Treat identical to ConnectionResetError
|
||||||
|
@ -174,6 +174,7 @@ BASE_SCRIPTS = [
|
|||||||
'rpc_blockchain.py',
|
'rpc_blockchain.py',
|
||||||
'rpc_deprecated.py',
|
'rpc_deprecated.py',
|
||||||
'wallet_disable.py',
|
'wallet_disable.py',
|
||||||
|
'p2p_addr_relay.py',
|
||||||
'p2p_getaddr_caching.py',
|
'p2p_getaddr_caching.py',
|
||||||
'p2p_getdata.py',
|
'p2p_getdata.py',
|
||||||
'rpc_net.py',
|
'rpc_net.py',
|
||||||
|
@ -88,6 +88,7 @@ class AvoidReuseTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
self.nodes[0].generate(110)
|
self.nodes[0].generate(110)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
self.test_change_remains_change(self.nodes[1])
|
||||||
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
|
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
|
||||||
self.test_sending_from_reused_address_without_avoid_reuse()
|
self.test_sending_from_reused_address_without_avoid_reuse()
|
||||||
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
|
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
|
||||||
@ -141,6 +142,30 @@ class AvoidReuseTest(BitcoinTestFramework):
|
|||||||
# Unload temp wallet
|
# Unload temp wallet
|
||||||
self.nodes[1].unloadwallet(tempwallet)
|
self.nodes[1].unloadwallet(tempwallet)
|
||||||
|
|
||||||
|
def test_change_remains_change(self, node):
|
||||||
|
self.log.info("Test that change doesn't turn into non-change when spent")
|
||||||
|
|
||||||
|
reset_balance(node, node.getnewaddress())
|
||||||
|
addr = node.getnewaddress()
|
||||||
|
txid = node.sendtoaddress(addr, 1)
|
||||||
|
out = node.listunspent(minconf=0, query_options={'minimumAmount': 2})
|
||||||
|
assert_equal(len(out), 1)
|
||||||
|
assert_equal(out[0]['txid'], txid)
|
||||||
|
changeaddr = out[0]['address']
|
||||||
|
|
||||||
|
# Make sure it's starting out as change as expected
|
||||||
|
assert node.getaddressinfo(changeaddr)['ischange']
|
||||||
|
for logical_tx in node.listtransactions():
|
||||||
|
assert logical_tx.get('address') != changeaddr
|
||||||
|
|
||||||
|
# Spend it
|
||||||
|
reset_balance(node, node.getnewaddress())
|
||||||
|
|
||||||
|
# It should still be change
|
||||||
|
assert node.getaddressinfo(changeaddr)['ischange']
|
||||||
|
for logical_tx in node.listtransactions():
|
||||||
|
assert logical_tx.get('address') != changeaddr
|
||||||
|
|
||||||
def test_sending_from_reused_address_without_avoid_reuse(self):
|
def test_sending_from_reused_address_without_avoid_reuse(self):
|
||||||
'''
|
'''
|
||||||
Test the same as test_sending_from_reused_address_fails, except send the 10 BTC with
|
Test the same as test_sending_from_reused_address_fails, except send the 10 BTC with
|
||||||
|
Loading…
Reference in New Issue
Block a user