diff options
Diffstat (limited to 'src')
69 files changed, 797 insertions, 646 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 5dae4374e3..58a09cd4a4 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -74,6 +74,7 @@ endif if ENABLE_WALLET bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp +bench_bench_bitcoin_SOURCES += bench/wallet_loading.cpp endif bench_bench_bitcoin_LDADD += $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index f7f62dfc68..e614102de3 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -146,13 +146,21 @@ double base_uint<BITS>::getdouble() const template <unsigned int BITS> std::string base_uint<BITS>::GetHex() const { - return ArithToUint256(*this).GetHex(); + base_blob<BITS> b; + for (int x = 0; x < this->WIDTH; ++x) { + WriteLE32(b.begin() + x*4, this->pn[x]); + } + return b.GetHex(); } template <unsigned int BITS> void base_uint<BITS>::SetHex(const char* psz) { - *this = UintToArith256(uint256S(psz)); + base_blob<BITS> b; + b.SetHex(psz); + for (int x = 0; x < this->WIDTH; ++x) { + this->pn[x] = ReadLE32(b.begin() + x*4); + } } template <unsigned int BITS> @@ -164,7 +172,7 @@ void base_uint<BITS>::SetHex(const std::string& str) template <unsigned int BITS> std::string base_uint<BITS>::ToString() const { - return (GetHex()); + return GetHex(); } template <unsigned int BITS> @@ -183,20 +191,7 @@ unsigned int base_uint<BITS>::bits() const } // Explicit instantiations for base_uint<256> -template base_uint<256>::base_uint(const std::string&); -template base_uint<256>& base_uint<256>::operator<<=(unsigned int); -template base_uint<256>& base_uint<256>::operator>>=(unsigned int); -template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); -template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); -template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); -template int base_uint<256>::CompareTo(const base_uint<256>&) const; -template bool base_uint<256>::EqualTo(uint64_t) const; -template double base_uint<256>::getdouble() const; -template std::string base_uint<256>::GetHex() const; -template std::string base_uint<256>::ToString() const; -template void base_uint<256>::SetHex(const char*); -template void base_uint<256>::SetHex(const std::string&); -template unsigned int base_uint<256>::bits() const; +template class base_uint<256>; // This implementation directly uses shifts instead of going // through an intermediate MPI representation. diff --git a/src/arith_uint256.h b/src/arith_uint256.h index a0a0429c2a..19193972a4 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -284,4 +284,6 @@ public: uint256 ArithToUint256(const arith_uint256 &); arith_uint256 UintToArith256(const uint256 &); +extern template class base_uint<256>; + #endif // BITCOIN_ARITH_UINT256_H diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 2143bcf950..e6fc8d21f4 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench) { TestBlockAndIndex data; bench.run([&] { - auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); ankerl::nanobench::doNotOptimizeAway(univalue); }); } @@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose); static void BlockToJsonVerboseWrite(benchmark::Bench& bench) { TestBlockAndIndex data; - auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); bench.run([&] { auto str = univalue.write(); ankerl::nanobench::doNotOptimizeAway(str); diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp new file mode 100644 index 0000000000..38d3460001 --- /dev/null +++ b/src/bench/wallet_loading.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2022 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 <bench/bench.h> +#include <interfaces/chain.h> +#include <node/context.h> +#include <test/util/mining.h> +#include <test/util/setup_common.h> +#include <test/util/wallet.h> +#include <util/translation.h> +#include <validationinterface.h> +#include <wallet/context.h> +#include <wallet/receive.h> +#include <wallet/wallet.h> + +#include <optional> + +using wallet::CWallet; +using wallet::DatabaseOptions; +using wallet::DatabaseStatus; +using wallet::ISMINE_SPENDABLE; +using wallet::MakeWalletDatabase; +using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WalletContext; + +static const std::shared_ptr<CWallet> BenchLoadWallet(WalletContext& context, DatabaseOptions& options) +{ + DatabaseStatus status; + bilingual_str error; + std::vector<bilingual_str> warnings; + auto database = MakeWalletDatabase("", options, status, error); + assert(database); + auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings); + NotifyWalletLoaded(context, wallet); + if (context.chain) { + wallet->postInitProcess(); + } + return wallet; +} + +static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet) +{ + SyncWithValidationInterfaceQueue(); + wallet->m_chain_notifications_handler.reset(); + UnloadWallet(std::move(wallet)); +} + +static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) +{ + const auto test_setup = MakeNoLogFileContext<TestingSetup>(); + + WalletContext context; + context.args = &test_setup->m_args; + context.chain = test_setup->m_node.chain.get(); + + // Setup the wallet + // Loading the wallet will also create it + DatabaseOptions options; + if (!legacy_wallet) options.create_flags = WALLET_FLAG_DESCRIPTORS; + auto wallet = BenchLoadWallet(context, options); + + // Generate a bunch of transactions and addresses to put into the wallet + for (int i = 0; i < 5000; ++i) { + generatetoaddress(test_setup->m_node, getnewaddress(*wallet)); + } + + // reload the wallet for the actual benchmark + BenchUnloadWallet(std::move(wallet)); + + bench.minEpochIterations(10).run([&] { + wallet = BenchLoadWallet(context, options); + + // Cleanup + BenchUnloadWallet(std::move(wallet)); + }); +} + +static void WalletLoadingLegacy(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/true); } +static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); } + +BENCHMARK(WalletLoadingLegacy); +BENCHMARK(WalletLoadingDescriptors); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 6925a4c8c6..dea46693bc 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -1055,7 +1055,9 @@ static void ParseGetInfoResult(UniValue& result) result_string += "\n"; } - result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, result["warnings"].getValStr()); + const std::string warnings{result["warnings"].getValStr()}; + result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, warnings.empty() ? "(none)" : warnings); + result.setStr(result_string); } diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index cde543e68c..196f81ea16 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -586,17 +586,9 @@ std::string SHA256AutoDetect() bool have_sse4 = false; bool have_xsave = false; bool have_avx = false; - bool have_avx2 = false; - bool have_x86_shani = false; - bool enabled_avx = false; - - (void)AVXEnabled; - (void)have_sse4; - (void)have_avx; - (void)have_xsave; - (void)have_avx2; - (void)have_x86_shani; - (void)enabled_avx; + [[maybe_unused]] bool have_avx2 = false; + [[maybe_unused]] bool have_x86_shani = false; + [[maybe_unused]] bool enabled_avx = false; uint32_t eax, ebx, ecx, edx; GetCPUID(1, 0, eax, ebx, ecx, edx); @@ -641,7 +633,7 @@ std::string SHA256AutoDetect() ret += ",avx2(8way)"; } #endif -#endif +#endif // defined(USE_ASM) && defined(HAVE_GETCPUID) #if defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) bool have_arm_shani = false; diff --git a/src/init.cpp b/src/init.cpp index 86e6ec4451..c0af2b136f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -109,7 +109,6 @@ using node::LoadChainstate; using node::NodeContext; using node::ThreadImport; using node::VerifyLoadedChainstate; -using node::fHavePruned; using node::fPruneMode; using node::fReindex; using node::nPruneTarget; @@ -660,7 +659,8 @@ void InitParameterInteraction(ArgsManager& args) LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); } - if (args.IsArgSet("-proxy")) { + std::string proxy_arg = args.GetArg("-proxy", ""); + if (proxy_arg != "" && proxy_arg != "0") { // to protect privacy, do not listen by default if a default proxy server is specified if (args.SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); @@ -1480,7 +1480,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) try { uiInterface.InitMessage(_("Verifying blocks…").translated); auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); - if (fHavePruned && check_blocks > MIN_BLOCKS_TO_KEEP) { + if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) { LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n", MIN_BLOCKS_TO_KEEP); } @@ -1664,9 +1664,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime(); tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip()); } - if (tip_info && ::pindexBestHeader) { - tip_info->header_height = ::pindexBestHeader->nHeight; - tip_info->header_time = ::pindexBestHeader->GetBlockTime(); + if (tip_info && chainman.m_best_header) { + tip_info->header_height = chainman.m_best_header->nHeight; + tip_info->header_time = chainman.m_best_header->GetBlockTime(); } } LogPrintf("nBestHeight = %d\n", chain_active_height); diff --git a/src/logging/timer.h b/src/logging/timer.h index fc5307bc62..d954e46301 100644 --- a/src/logging/timer.h +++ b/src/logging/timer.h @@ -97,13 +97,13 @@ private: #define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category) \ - BCLog::Timer<std::chrono::microseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category) + BCLog::Timer<std::chrono::microseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category) #define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category) \ - BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category) + BCLog::Timer<std::chrono::milliseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category) #define LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE(end_msg, log_category) \ - BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category, /* msg_on_completion=*/false) + BCLog::Timer<std::chrono::milliseconds> UNIQUE_NAME(logging_timer)(__func__, end_msg, log_category, /* msg_on_completion=*/false) #define LOG_TIME_SECONDS(end_msg) \ - BCLog::Timer<std::chrono::seconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg) + BCLog::Timer<std::chrono::seconds> UNIQUE_NAME(logging_timer)(__func__, end_msg) #endif // BITCOIN_LOGGING_TIMER_H diff --git a/src/net.cpp b/src/net.cpp index 602d56ab98..5a0c057c3e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1190,7 +1190,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, // According to the internet TCP_NODELAY is not carried into accepted sockets // on all platforms. Set it again here just to be sure. - SetSocketNoDelay(sock->Get()); + const int on{1}; + if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { + LogPrint(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n", + addr.ToString()); + } // Don't accept connections from banned peers. bool banned = m_banman && m_banman->IsBanned(addr); @@ -2395,17 +2399,26 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, // Allow binding if the port is still in TIME_WAIT state after // the program was closed and restarted. - setsockopt(sock->Get(), SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)); + if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) { + strError = strprintf(Untranslated("Error setting SO_REUSEADDR on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError())); + LogPrintf("%s\n", strError.original); + } // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option // and enable it by default or not. Try to enable it, if possible. if (addrBind.IsIPv6()) { #ifdef IPV6_V6ONLY - setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)); + if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) { + strError = strprintf(Untranslated("Error setting IPV6_V6ONLY on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError())); + LogPrintf("%s\n", strError.original); + } #endif #ifdef WIN32 int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED; - setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)); + if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR) { + strError = strprintf(Untranslated("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway"), NetworkErrorString(WSAGetLastError())); + LogPrintf("%s\n", strError.original); + } #endif } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index ba72a11ec9..02eb3762b1 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1499,9 +1499,9 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex) { AssertLockHeld(cs_main); if (m_chainman.ActiveChain().Contains(pindex)) return true; - return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) && - (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT); + return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (m_chainman.m_best_header != nullptr) && + (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) && + (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT); } std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index) @@ -1896,7 +1896,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); // disconnect node in case we have reached the outbound limit for serving historical blocks if (m_connman.OutboundTargetReached(true) && - (((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) && + (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) && !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target ) { LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId()); @@ -2173,12 +2173,12 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, // nUnconnectingHeaders gets reset back to 0. if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256())); LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", - headers[0].GetHash().ToString(), - headers[0].hashPrevBlock.ToString(), - pindexBestHeader->nHeight, - pfrom.GetId(), nodestate->nUnconnectingHeaders); + headers[0].GetHash().ToString(), + headers[0].hashPrevBlock.ToString(), + m_chainman.m_best_header->nHeight, + pfrom.GetId(), nodestate->nUnconnectingHeaders); // Set hashLastUnknownBlock for this peer, so that if we // eventually get the headers - even from a different peer - // we can use this peer to download. @@ -2235,7 +2235,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. - // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue + // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or m_chainman.m_best_header, continue // from there instead. LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height); @@ -3102,8 +3102,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (best_block != nullptr) { - m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block)); - LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId()); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *best_block)); + LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", m_chainman.m_best_header->nHeight, best_block->ToString(), pfrom.GetId()); } return; @@ -3549,7 +3549,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) - m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256())); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256())); return; } @@ -4670,28 +4670,29 @@ bool PeerManagerImpl::SendMessages(CNode* pto) CNodeState &state = *State(pto->GetId()); // Start block sync - if (pindexBestHeader == nullptr) - pindexBestHeader = m_chainman.ActiveChain().Tip(); + if (m_chainman.m_best_header == nullptr) { + m_chainman.m_best_header = m_chainman.ActiveChain().Tip(); + } bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { + if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE + ( // Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling // to maintain precision std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} * - (GetAdjustedTime() - pindexBestHeader->GetBlockTime()) / consensusParams.nPowTargetSpacing + (GetAdjustedTime() - m_chainman.m_best_header->GetBlockTime()) / consensusParams.nPowTargetSpacing ); nSyncStarted++; - const CBlockIndex *pindexStart = pindexBestHeader; + const CBlockIndex* pindexStart = m_chainman.m_best_header; /* If possible, start at the block preceding the currently best known header. This ensures that we always get a non-empty list of headers back as long as the peer is up-to-date. With a non-empty response, we can initialise the peer's known best block. This wouldn't be possible - if we requested starting at pindexBestHeader and + if we requested starting at m_chainman.m_best_header and got back an empty response. */ if (pindexStart->pprev) pindexStart = pindexStart->pprev; @@ -5016,7 +5017,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // Check for headers sync timeouts if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) { // Detect whether this is a stalling initial-headers-sync peer - if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) { + if (m_chainman.m_best_header->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) { if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { // Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer, // and we have others we could be using instead. diff --git a/src/netbase.cpp b/src/netbase.cpp index 9a0b800565..9557297df1 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -305,7 +305,7 @@ enum class IntrRecvError { * * @see This function can be interrupted by calling InterruptSocks5(bool). * Sockets can be made non-blocking with SetSocketNonBlocking(const - * SOCKET&, bool). + * SOCKET&). */ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock) { @@ -499,10 +499,11 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family) return nullptr; } + auto sock = std::make_unique<Sock>(hSocket); + // Ensure that waiting for I/O on this socket won't result in undefined // behavior. - if (!IsSelectableSocket(hSocket)) { - CloseSocket(hSocket); + if (!IsSelectableSocket(sock->Get())) { LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); return nullptr; } @@ -511,19 +512,24 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family) int set = 1; // Set the no-sigpipe option on the socket for BSD systems, other UNIXes // should use the MSG_NOSIGNAL flag for every send. - setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); + if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)) == SOCKET_ERROR) { + LogPrintf("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n", + NetworkErrorString(WSAGetLastError())); + } #endif // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. - SetSocketNoDelay(hSocket); + const int on{1}; + if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { + LogPrint(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n"); + } // Set the non-blocking option on the socket. - if (!SetSocketNonBlocking(hSocket, true)) { - CloseSocket(hSocket); + if (!SetSocketNonBlocking(sock->Get())) { LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError())); return nullptr; } - return std::make_unique<Sock>(hSocket); + return sock; } std::function<std::unique_ptr<Sock>(const CService&)> CreateSock = CreateSockTCP; @@ -711,40 +717,21 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out) return false; } -bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking) +bool SetSocketNonBlocking(const SOCKET& hSocket) { - if (fNonBlocking) { -#ifdef WIN32 - u_long nOne = 1; - if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) { -#else - int fFlags = fcntl(hSocket, F_GETFL, 0); - if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) { -#endif - return false; - } - } else { #ifdef WIN32 - u_long nZero = 0; - if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) { + u_long nOne = 1; + if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) { #else - int fFlags = fcntl(hSocket, F_GETFL, 0); - if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) { + int fFlags = fcntl(hSocket, F_GETFL, 0); + if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) { #endif - return false; - } + return false; } return true; } -bool SetSocketNoDelay(const SOCKET& hSocket) -{ - int set = 1; - int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); - return rc == 0; -} - void InterruptSocks5(bool interrupt) { interruptSocks5Recv = interrupt; diff --git a/src/netbase.h b/src/netbase.h index f9e3872c16..bf7522210d 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -221,10 +221,8 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT */ bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed); -/** Disable or enable blocking-mode for a socket */ -bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking); -/** Set the TCP_NODELAY flag on a socket */ -bool SetSocketNoDelay(const SOCKET& hSocket); +/** Enable non-blocking mode for a socket */ +bool SetSocketNonBlocking(const SOCKET& hSocket); void InterruptSocks5(bool interrupt); /** diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 763fd29744..21cb0250d8 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -24,7 +24,6 @@ namespace node { std::atomic_bool fImporting(false); std::atomic_bool fReindex(false); -bool fHavePruned = false; bool fPruneMode = false; uint64_t nPruneTarget = 0; @@ -81,7 +80,7 @@ const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const return it == m_block_index.end() ? nullptr : &it->second; } -CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) +CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) { AssertLockHeld(cs_main); @@ -106,8 +105,9 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); pindexNew->RaiseValidity(BLOCK_VALID_TREE); - if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) - pindexBestHeader = pindexNew; + if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) { + best_header = pindexNew; + } m_dirty_blockindex.insert(pindexNew); @@ -285,8 +285,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params) if (pindex->pprev) { pindex->BuildSkip(); } - if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) - pindexBestHeader = pindex; } return true; @@ -302,6 +300,8 @@ void BlockManager::Unload() m_last_blockfile = 0; m_dirty_blockindex.clear(); m_dirty_fileinfo.clear(); + + m_have_pruned = false; } bool BlockManager::WriteBlockIndexDB() @@ -364,8 +364,8 @@ bool BlockManager::LoadBlockIndexDB() } // Check whether we have ever pruned block & undo files - m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned); - if (fHavePruned) { + m_block_tree_db->ReadFlag("prunedblockfiles", m_have_pruned); + if (m_have_pruned) { LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); } @@ -391,10 +391,10 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) return nullptr; } -bool IsBlockPruned(const CBlockIndex* pblockindex) +bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex) { AssertLockHeld(::cs_main); - return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0); + return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0); } // If we're using -prune with -reindex, then delete block files that will be ignored by the diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index a051e90808..11445aa22e 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -45,8 +45,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB extern std::atomic_bool fImporting; extern std::atomic_bool fReindex; /** Pruning-related variables and constants */ -/** True if any block files have ever been pruned. */ -extern bool fHavePruned; /** True if we're running in -prune mode. */ extern bool fPruneMode; /** Number of MiB of block files that we're trying to stay below. */ @@ -147,7 +145,7 @@ public: /** Clear all data members. */ void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); - CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Create a new block index entry for a given block hash */ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -171,15 +169,18 @@ public: //! Returns last CBlockIndex* that is a checkpoint const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** True if any block files have ever been pruned. */ + bool m_have_pruned = false; + + //! Check whether the block associated with this index entry is pruned or not. + bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + ~BlockManager() { Unload(); } }; -//! Check whether the block associated with this index entry is pruned or not. -bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - void CleanupBlockRevFiles(); /** Open a block file (blk?????.dat) */ diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 9fdeb036fd..e43211402c 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -49,7 +49,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset, if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED; - // LoadBlockIndex will load fHavePruned if we've ever removed a + // LoadBlockIndex will load m_have_pruned if we've ever removed a // block file from disk. // Note that it also sets fReindex based on the disk flag! // From here on out fReindex and fReset mean something different! @@ -65,7 +65,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset, // Check for changed -prune state. What we are concerned about is a user who has pruned blocks // in the past, but is now trying to run unpruned. - if (fHavePruned && !fPruneMode) { + if (chainman.m_blockman.m_have_pruned && !fPruneMode) { return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX; } diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 73d15652b1..954bd1c31d 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -212,9 +212,10 @@ public: bool getHeaderTip(int& height, int64_t& block_time) override { LOCK(::cs_main); - if (::pindexBestHeader) { - height = ::pindexBestHeader->nHeight; - block_time = ::pindexBestHeader->GetBlockTime(); + auto best_header = chainman().m_best_header; + if (best_header) { + height = best_header->nHeight; + block_time = best_header->GetBlockTime(); return true; } return false; @@ -644,7 +645,7 @@ public: bool havePruned() override { LOCK(cs_main); - return node::fHavePruned; + return m_node.chainman->m_blockman.m_have_pruned; } bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); } bool isInitialBlockDownload() override { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index c6b884e40a..8cac28400f 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -95,6 +95,8 @@ static void RegisterMetaTypes() qRegisterMetaType<std::function<void()>>("std::function<void()>"); qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon"); qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo"); + + qRegisterMetaTypeStreamOperators<BitcoinUnit>("BitcoinUnit"); } static QString GetLangTerritory() diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index a257e250e0..c92aecd095 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -14,6 +14,9 @@ #include <QHBoxLayout> #include <QKeyEvent> #include <QLineEdit> +#include <QVariant> + +#include <cassert> /** QSpinBox that uses fixed-point numbers internally and uses our own * formatting/parsing functions. @@ -96,7 +99,7 @@ public: setValue(val); } - void setDisplayUnit(int unit) + void setDisplayUnit(BitcoinUnit unit) { bool valid = false; CAmount val = value(&valid); @@ -122,7 +125,7 @@ public: const QFontMetrics fm(fontMetrics()); int h = lineEdit()->minimumSizeHint().height(); - int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS)); + int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnit::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS)); w += 2; // cursor blinking space QStyleOptionSpinBox opt; @@ -141,14 +144,13 @@ public: opt.rect = rect(); - cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this) - .expandedTo(QApplication::globalStrut()); + cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this); } return cachedMinimumSizeHint; } private: - int currentUnit{BitcoinUnits::BTC}; + BitcoinUnit currentUnit{BitcoinUnit::BTC}; CAmount singleStep{CAmount(100000)}; // satoshis mutable QSize cachedMinimumSizeHint; bool m_allow_empty{true}; @@ -326,14 +328,14 @@ void BitcoinAmountField::unitChanged(int idx) unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString()); // Determine new unit ID - int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt(); - - amount->setDisplayUnit(newUnit); + QVariant new_unit = unit->currentData(BitcoinUnits::UnitRole); + assert(new_unit.isValid()); + amount->setDisplayUnit(new_unit.value<BitcoinUnit>()); } -void BitcoinAmountField::setDisplayUnit(int newUnit) +void BitcoinAmountField::setDisplayUnit(BitcoinUnit new_unit) { - unit->setValue(newUnit); + unit->setValue(QVariant::fromValue(new_unit)); } void BitcoinAmountField::setSingleStep(const CAmount& step) diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 366a6fc4b5..a40cd38332 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_BITCOINAMOUNTFIELD_H #include <consensus/amount.h> +#include <qt/bitcoinunits.h> #include <QWidget> @@ -52,7 +53,7 @@ public: bool validate(); /** Change unit used to display amount. */ - void setDisplayUnit(int unit); + void setDisplayUnit(BitcoinUnit new_unit); /** Make field empty and ready for new input. */ void clear(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 85e3c23085..81b0e711b2 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -41,6 +41,7 @@ #include <validation.h> #include <QAction> +#include <QActionGroup> #include <QApplication> #include <QComboBox> #include <QCursor> @@ -355,7 +356,7 @@ void BitcoinGUI::createActions() showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME)); m_mask_values_action = new QAction(tr("&Mask values"), this); - m_mask_values_action->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_M)); + m_mask_values_action->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_M)); m_mask_values_action->setStatusTip(tr("Mask the values in the Overview tab")); m_mask_values_action->setCheckable(true); @@ -426,8 +427,8 @@ void BitcoinGUI::createActions() } #endif // ENABLE_WALLET - connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole); - connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow); + connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole); + connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow); } void BitcoinGUI::createMenuBar() @@ -1244,7 +1245,7 @@ void BitcoinGUI::showEvent(QShowEvent *event) } #ifdef ENABLE_WALLET -void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName) +void BitcoinGUI::incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName) { // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(date) + @@ -1495,11 +1496,10 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); - QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits(); + QList<BitcoinUnit> units = BitcoinUnits::availableUnits(); int max_width = 0; const QFontMetrics fm(font()); - for (const BitcoinUnits::Unit unit : units) - { + for (const BitcoinUnit unit : units) { max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit))); } setMinimumSize(max_width, 0); @@ -1529,8 +1529,8 @@ void UnitDisplayStatusBarControl::changeEvent(QEvent* e) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { - menu->addAction(BitcoinUnits::longName(u))->setData(QVariant(u)); + for (const BitcoinUnit u : BitcoinUnits::availableUnits()) { + menu->addAction(BitcoinUnits::longName(u))->setData(QVariant::fromValue(u)); } connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection); } @@ -1551,7 +1551,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) } /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ -void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits) +void UnitDisplayStatusBarControl::updateDisplayUnit(BitcoinUnit newUnits) { setText(BitcoinUnits::longName(newUnits)); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d2b29ba27b..5d9a978695 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -9,6 +9,7 @@ #include <config/bitcoin-config.h> #endif +#include <qt/bitcoinunits.h> #include <qt/guiutil.h> #include <qt/optionsdialog.h> @@ -260,7 +261,7 @@ public Q_SLOTS: bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); + void incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); #endif // ENABLE_WALLET private: @@ -341,7 +342,7 @@ private: private Q_SLOTS: /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ - void updateDisplayUnit(int newUnits); + void updateDisplayUnit(BitcoinUnit newUnits); /** Tells underlying optionsModel to update its current display unit. */ void onMenuSelection(QAction* action); }; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 69caf64d5c..fe3eb3240b 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -18,94 +18,75 @@ BitcoinUnits::BitcoinUnits(QObject *parent): { } -QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits() +QList<BitcoinUnit> BitcoinUnits::availableUnits() { - QList<BitcoinUnits::Unit> unitlist; - unitlist.append(BTC); - unitlist.append(mBTC); - unitlist.append(uBTC); - unitlist.append(SAT); + QList<BitcoinUnit> unitlist; + unitlist.append(Unit::BTC); + unitlist.append(Unit::mBTC); + unitlist.append(Unit::uBTC); + unitlist.append(Unit::SAT); return unitlist; } -bool BitcoinUnits::valid(int unit) +QString BitcoinUnits::longName(Unit unit) { - switch(unit) - { - case BTC: - case mBTC: - case uBTC: - case SAT: - return true; - default: - return false; - } -} - -QString BitcoinUnits::longName(int unit) -{ - switch(unit) - { - case BTC: return QString("BTC"); - case mBTC: return QString("mBTC"); - case uBTC: return QString::fromUtf8("µBTC (bits)"); - case SAT: return QString("Satoshi (sat)"); - default: return QString("???"); - } + switch (unit) { + case Unit::BTC: return QString("BTC"); + case Unit::mBTC: return QString("mBTC"); + case Unit::uBTC: return QString::fromUtf8("µBTC (bits)"); + case Unit::SAT: return QString("Satoshi (sat)"); + } // no default case, so the compiler can warn about missing cases + assert(false); } -QString BitcoinUnits::shortName(int unit) +QString BitcoinUnits::shortName(Unit unit) { - switch(unit) - { - case uBTC: return QString::fromUtf8("bits"); - case SAT: return QString("sat"); - default: return longName(unit); - } + switch (unit) { + case Unit::BTC: return longName(unit); + case Unit::mBTC: return longName(unit); + case Unit::uBTC: return QString("bits"); + case Unit::SAT: return QString("sat"); + } // no default case, so the compiler can warn about missing cases + assert(false); } -QString BitcoinUnits::description(int unit) +QString BitcoinUnits::description(Unit unit) { - switch(unit) - { - case BTC: return QString("Bitcoins"); - case mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)"); - case uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); - case SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); - default: return QString("???"); - } + switch (unit) { + case Unit::BTC: return QString("Bitcoins"); + case Unit::mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)"); + case Unit::uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); + case Unit::SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); + } // no default case, so the compiler can warn about missing cases + assert(false); } -qint64 BitcoinUnits::factor(int unit) +qint64 BitcoinUnits::factor(Unit unit) { - switch(unit) - { - case BTC: return 100000000; - case mBTC: return 100000; - case uBTC: return 100; - case SAT: return 1; - default: return 100000000; - } + switch (unit) { + case Unit::BTC: return 100'000'000; + case Unit::mBTC: return 100'000; + case Unit::uBTC: return 100; + case Unit::SAT: return 1; + } // no default case, so the compiler can warn about missing cases + assert(false); } -int BitcoinUnits::decimals(int unit) +int BitcoinUnits::decimals(Unit unit) { - switch(unit) - { - case BTC: return 8; - case mBTC: return 5; - case uBTC: return 2; - case SAT: return 0; - default: return 0; - } + switch (unit) { + case Unit::BTC: return 8; + case Unit::mBTC: return 5; + case Unit::uBTC: return 2; + case Unit::SAT: return 0; + } // no default case, so the compiler can warn about missing cases + assert(false); } -QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify) +QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. - if(!valid(unit)) - return QString(); // Refuse to format invalid unit qint64 n = (qint64)nIn; qint64 coin = factor(unit); int num_decimals = decimals(unit); @@ -147,19 +128,19 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator // Please take care to use formatHtmlWithUnit instead, when // appropriate. -QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::formatWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { return format(unit, amount, plussign, separators) + QString(" ") + shortName(unit); } -QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { QString str(formatWithUnit(unit, amount, plussign, separators)); str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML)); return QString("<span style='white-space: nowrap;'>%1</span>").arg(str); } -QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy) +QString BitcoinUnits::formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy) { assert(amount >= 0); QString value; @@ -171,10 +152,11 @@ QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, Separat return value + QString(" ") + shortName(unit); } -bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out) +bool BitcoinUnits::parse(Unit unit, const QString& value, CAmount* val_out) { - if(!valid(unit) || value.isEmpty()) + if (value.isEmpty()) { return false; // Refuse to parse invalid unit or empty string + } int num_decimals = decimals(unit); // Ignore spaces and thin spaces when parsing @@ -210,14 +192,9 @@ bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out) return ok; } -QString BitcoinUnits::getAmountColumnTitle(int unit) +QString BitcoinUnits::getAmountColumnTitle(Unit unit) { - QString amountTitle = QObject::tr("Amount"); - if (BitcoinUnits::valid(unit)) - { - amountTitle += " ("+BitcoinUnits::shortName(unit) + ")"; - } - return amountTitle; + return QObject::tr("Amount") + " (" + shortName(unit) + ")"; } int BitcoinUnits::rowCount(const QModelIndex &parent) const @@ -240,7 +217,7 @@ QVariant BitcoinUnits::data(const QModelIndex &index, int role) const case Qt::ToolTipRole: return QVariant(description(unit)); case UnitRole: - return QVariant(static_cast<int>(unit)); + return QVariant::fromValue(unit); } } return QVariant(); @@ -250,3 +227,40 @@ CAmount BitcoinUnits::maxMoney() { return MAX_MONEY; } + +namespace { +qint8 ToQint8(BitcoinUnit unit) +{ + switch (unit) { + case BitcoinUnit::BTC: return 0; + case BitcoinUnit::mBTC: return 1; + case BitcoinUnit::uBTC: return 2; + case BitcoinUnit::SAT: return 3; + } // no default case, so the compiler can warn about missing cases + assert(false); +} + +BitcoinUnit FromQint8(qint8 num) +{ + switch (num) { + case 0: return BitcoinUnit::BTC; + case 1: return BitcoinUnit::mBTC; + case 2: return BitcoinUnit::uBTC; + case 3: return BitcoinUnit::SAT; + } + assert(false); +} +} // namespace + +QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit) +{ + return out << ToQint8(unit); +} + +QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit) +{ + qint8 input; + in >> input; + unit = FromQint8(input); + return in; +} diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 9fedec0d4f..b3b5a8fc18 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -8,6 +8,7 @@ #include <consensus/amount.h> #include <QAbstractListModel> +#include <QDataStream> #include <QString> // U+2009 THIN SPACE = UTF-8 E2 80 89 @@ -38,13 +39,13 @@ public: /** Bitcoin units. @note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones */ - enum Unit - { + enum class Unit { BTC, mBTC, uBTC, SAT }; + Q_ENUM(Unit) enum class SeparatorStyle { @@ -59,30 +60,28 @@ public: //! Get list of units, for drop-down box static QList<Unit> availableUnits(); - //! Is unit ID valid? - static bool valid(int unit); //! Long name - static QString longName(int unit); + static QString longName(Unit unit); //! Short name - static QString shortName(int unit); + static QString shortName(Unit unit); //! Longer description - static QString description(int unit); + static QString description(Unit unit); //! Number of Satoshis (1e-8) per unit - static qint64 factor(int unit); + static qint64 factor(Unit unit); //! Number of decimals left - static int decimals(int unit); + static int decimals(Unit unit); //! Format as string - static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD, bool justify = false); + static QString format(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD, bool justify = false); //! Format as string (with unit) - static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD); + static QString formatWithUnit(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD); //! Format as HTML string (with unit) - static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD); + static QString formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD); //! Format as string (with unit) of fixed length to preserve privacy, if it is set. - static QString formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy); + static QString formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy); //! Parse string to coin amount - static bool parse(int unit, const QString &value, CAmount *val_out); + static bool parse(Unit unit, const QString& value, CAmount* val_out); //! Gets title for amount column including current display unit if optionsModel reference available */ - static QString getAmountColumnTitle(int unit); + static QString getAmountColumnTitle(Unit unit); ///@} //! @name AbstractListModel implementation @@ -107,8 +106,11 @@ public: static CAmount maxMoney(); private: - QList<BitcoinUnits::Unit> unitlist; + QList<Unit> unitlist; }; typedef BitcoinUnits::Unit BitcoinUnit; +QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit); +QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit); + #endif // BITCOIN_QT_BITCOINUNITS_H diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d3103492a4..bd9a90a890 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -507,7 +507,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel * } // actually update labels - int nDisplayUnit = BitcoinUnits::BTC; + BitcoinUnit nDisplayUnit = BitcoinUnit::BTC; if (model && model->getOptionsModel()) nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); @@ -588,9 +588,9 @@ void CoinControlDialog::updateView() ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox ui->treeWidget->setAlternatingRowColors(!treeMode); QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; - QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate; - int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + BitcoinUnit nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); for (const auto& coins : model->wallet().listCoins()) { CCoinControlWidgetItem* itemWalletAddress{nullptr}; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 362601b512..6fb5fce5b3 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -60,6 +60,7 @@ #include <QSettings> #include <QShortcut> #include <QSize> +#include <QStandardPaths> #include <QString> #include <QTextDocument> // for Qt::mightBeRichText #include <QThread> @@ -80,6 +81,8 @@ void ForceActivation(); #endif +using namespace std::chrono_literals; + namespace GUIUtil { QString dateTimeStr(const QDateTime &date) @@ -175,8 +178,7 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) { if(!i->second.isEmpty()) { - if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount)) - { + if (!BitcoinUnits::parse(BitcoinUnit::BTC, i->second, &rv.amount)) { return false; } } @@ -208,7 +210,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) if (info.amount) { - ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount, false, BitcoinUnits::SeparatorStyle::NEVER)); + ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnit::BTC, info.amount, false, BitcoinUnits::SeparatorStyle::NEVER)); paramCount++; } @@ -728,6 +730,16 @@ QString formatDurationStr(std::chrono::seconds dur) return str_list.join(" "); } +QString FormatPeerAge(std::chrono::seconds time_connected) +{ + const auto time_now{GetTime<std::chrono::seconds>()}; + const auto age{time_now - time_connected}; + if (age >= 24h) return QObject::tr("%1 d").arg(age / 24h); + if (age >= 1h) return QObject::tr("%1 h").arg(age / 1h); + if (age >= 1min) return QObject::tr("%1 m").arg(age / 1min); + return QObject::tr("%1 s").arg(age / 1s); +} + QString formatServicesStr(quint64 mask) { QStringList strList; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 0224b18b4e..76e5207d81 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -223,6 +223,9 @@ namespace GUIUtil /** Convert seconds into a QString with days, hours, mins, secs */ QString formatDurationStr(std::chrono::seconds dur); + /** Convert peer connection time to a QString denominated in the most relevant unit. */ + QString FormatPeerAge(std::chrono::seconds time_connected); + /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index b097ef080c..51151b0be8 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -14,8 +14,9 @@ #include <QTemporaryFile> #include <QVariant> #ifdef USE_DBUS -#include <stdint.h> +#include <QDBusMetaType> #include <QtDBus> +#include <stdint.h> #endif #ifdef Q_OS_MAC #include <qt/macnotificationhandler.h> @@ -73,8 +74,6 @@ public: FreedesktopImage() {} explicit FreedesktopImage(const QImage &img); - static int metaType(); - // Image to variant that can be marshalled over DBus static QVariant toVariant(const QImage &img); @@ -136,15 +135,10 @@ const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i) return a; } -int FreedesktopImage::metaType() -{ - return qDBusRegisterMetaType<FreedesktopImage>(); -} - QVariant FreedesktopImage::toVariant(const QImage &img) { FreedesktopImage fimg(img); - return QVariant(FreedesktopImage::metaType(), &fimg); + return QVariant(qDBusRegisterMetaType<FreedesktopImage>(), &fimg); } void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 52bda59748..40b9ed5483 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -24,6 +24,7 @@ #include <QLatin1Char> #include <QSettings> #include <QStringList> +#include <QVariant> const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1"; @@ -71,9 +72,16 @@ void OptionsModel::Init(bool resetSettings) fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool(); // Display - if (!settings.contains("nDisplayUnit")) - settings.setValue("nDisplayUnit", BitcoinUnits::BTC); - nDisplayUnit = settings.value("nDisplayUnit").toInt(); + if (!settings.contains("DisplayBitcoinUnit")) { + settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(BitcoinUnit::BTC)); + } + QVariant unit = settings.value("DisplayBitcoinUnit"); + if (unit.canConvert<BitcoinUnit>()) { + m_display_bitcoin_unit = unit.value<BitcoinUnit>(); + } else { + m_display_bitcoin_unit = BitcoinUnit::BTC; + settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit)); + } if (!settings.contains("strThirdPartyTxUrls")) settings.setValue("strThirdPartyTxUrls", ""); @@ -376,7 +384,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const return m_sub_fee_from_amount; #endif case DisplayUnit: - return nDisplayUnit; + return QVariant::fromValue(m_display_bitcoin_unit); case ThirdPartyTxUrls: return strThirdPartyTxUrls; case Language: @@ -584,16 +592,13 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in return successful; } -/** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */ -void OptionsModel::setDisplayUnit(const QVariant &value) +void OptionsModel::setDisplayUnit(const QVariant& new_unit) { - if (!value.isNull()) - { - QSettings settings; - nDisplayUnit = value.toInt(); - settings.setValue("nDisplayUnit", nDisplayUnit); - Q_EMIT displayUnitChanged(nDisplayUnit); - } + if (new_unit.isNull() || new_unit.value<BitcoinUnit>() == m_display_bitcoin_unit) return; + m_display_bitcoin_unit = new_unit.value<BitcoinUnit>(); + QSettings settings; + settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit)); + Q_EMIT displayUnitChanged(m_display_bitcoin_unit); } void OptionsModel::setRestartRequired(bool fRequired) diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index bb9a8c1f8c..510ebb5cfd 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_OPTIONSMODEL_H #include <cstdint> +#include <qt/bitcoinunits.h> #include <qt/guiconstants.h> #include <QAbstractListModel> @@ -55,7 +56,7 @@ public: ProxyUseTor, // bool ProxyIPTor, // QString ProxyPortTor, // int - DisplayUnit, // BitcoinUnits::Unit + DisplayUnit, // BitcoinUnit ThirdPartyTxUrls, // QString Language, // QString UseEmbeddedMonospacedFont, // bool @@ -79,14 +80,14 @@ public: int rowCount(const QModelIndex & parent = QModelIndex()) const override; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) override; - /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */ - void setDisplayUnit(const QVariant &value); + /** Updates current unit in memory, settings and emits displayUnitChanged(new_unit) signal */ + void setDisplayUnit(const QVariant& new_unit); /* Explicit getters */ bool getShowTrayIcon() const { return m_show_tray_icon; } bool getMinimizeToTray() const { return fMinimizeToTray; } bool getMinimizeOnClose() const { return fMinimizeOnClose; } - int getDisplayUnit() const { return nDisplayUnit; } + BitcoinUnit getDisplayUnit() const { return m_display_bitcoin_unit; } QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; } bool getUseEmbeddedMonospacedFont() const { return m_use_embedded_monospaced_font; } bool getCoinControlFeatures() const { return fCoinControlFeatures; } @@ -112,7 +113,7 @@ private: bool fMinimizeToTray; bool fMinimizeOnClose; QString language; - int nDisplayUnit; + BitcoinUnit m_display_bitcoin_unit; QString strThirdPartyTxUrls; bool m_use_embedded_monospaced_font; bool fCoinControlFeatures; @@ -127,7 +128,7 @@ private: // Check settings version and upgrade default values if required void checkAndMigrate(); Q_SIGNALS: - void displayUnitChanged(int unit); + void displayUnitChanged(BitcoinUnit unit); void coinControlFeaturesChanged(bool); void showTrayIconChanged(bool); void useEmbeddedMonospacedFontChanged(bool); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 7127706463..820bcbf3cd 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -34,9 +34,9 @@ class TxViewDelegate : public QAbstractItemDelegate { Q_OBJECT public: - explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr): - QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC), - platformStyle(_platformStyle) + explicit TxViewDelegate(const PlatformStyle* _platformStyle, QObject* parent = nullptr) + : QAbstractItemDelegate(parent), unit(BitcoinUnit::BTC), + platformStyle(_platformStyle) { connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged); } @@ -125,7 +125,7 @@ public: return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE}; } - int unit; + BitcoinUnit unit; Q_SIGNALS: //! An intermediate signal for emitting from the `paint() const` member function. @@ -197,7 +197,7 @@ OverviewPage::~OverviewPage() void OverviewPage::setBalance(const interfaces::WalletBalances& balances) { - int unit = walletModel->getOptionsModel()->getDisplayUnit(); + BitcoinUnit unit = walletModel->getOptionsModel()->getDisplayUnit(); m_balances = balances; if (walletModel->wallet().isLegacy()) { if (walletModel->wallet().privateKeysDisabled()) { diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 563bca76e5..41c389d9cc 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -71,6 +71,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const switch (column) { case NetNodeId: return (qint64)rec->nodeStats.nodeid; + case Age: + return GUIUtil::FormatPeerAge(rec->nodeStats.m_connected); case Address: return QString::fromStdString(rec->nodeStats.m_addr_name); case Direction: @@ -96,6 +98,7 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const } else if (role == Qt::TextAlignmentRole) { switch (column) { case NetNodeId: + case Age: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case Address: return {}; diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 11064cdbfe..e2515de775 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -47,6 +47,7 @@ public: enum ColumnIndex { NetNodeId = 0, + Age, Address, Direction, ConnectionType, @@ -82,6 +83,9 @@ private: /*: Title of Peers Table column which contains a unique number used to identify a connection. */ tr("Peer"), + /*: Title of Peers Table column which indicates the duration (length of time) + since the peer connection started. */ + tr("Age"), /*: Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. */ tr("Address"), diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp index 26fedb4127..d87f10c365 100644 --- a/src/qt/peertablesortproxy.cpp +++ b/src/qt/peertablesortproxy.cpp @@ -24,6 +24,8 @@ bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelInd switch (static_cast<PeerTableModel::ColumnIndex>(left_index.column())) { case PeerTableModel::NetNodeId: return left_stats.nodeid < right_stats.nodeid; + case PeerTableModel::Age: + return left_stats.m_connected > right_stats.m_connected; case PeerTableModel::Address: return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0; case PeerTableModel::Direction: diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 6880c157c0..333766ce21 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -181,7 +181,7 @@ std::string PSBTOperationsDialog::renderTransaction(const PartiallySignedTransac ExtractDestination(out.scriptPubKey, address); totalAmount += out.nValue; tx_description.append(tr(" * Sends %1 to %2") - .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, out.nValue)) + .arg(BitcoinUnits::formatWithUnit(BitcoinUnit::BTC, out.nValue)) .arg(QString::fromStdString(EncodeDestination(address)))); tx_description.append("<br>"); } @@ -193,7 +193,7 @@ std::string PSBTOperationsDialog::renderTransaction(const PartiallySignedTransac tx_description.append(tr("Unable to calculate transaction fee or total transaction amount.")); } else { tx_description.append(tr("Pays transaction fee: ")); - tx_description.append(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, *analysis.fee)); + tx_description.append(BitcoinUnits::formatWithUnit(BitcoinUnit::BTC, *analysis.fee)); // add total amount in all subdivision units tx_description.append("<hr />"); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index dcc4f36aaa..eb69fabe89 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -618,17 +618,16 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event) case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break; case Qt::Key_PageUp: /* pass paging keys to messages widget */ case Qt::Key_PageDown: - if(obj == ui->lineEdit) - { - QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt)); + if (obj == ui->lineEdit) { + QApplication::sendEvent(ui->messagesWidget, keyevt); return true; } break; case Qt::Key_Return: case Qt::Key_Enter: // forward these events to lineEdit - if(obj == autoCompleter->popup()) { - QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + if (obj == autoCompleter->popup()) { + QApplication::sendEvent(ui->lineEdit, keyevt); autoCompleter->popup()->hide(); return true; } @@ -642,7 +641,7 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event) ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) { ui->lineEdit->setFocus(); - QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + QApplication::sendEvent(ui->lineEdit, keyevt); return true; } } @@ -694,6 +693,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); } + ui->peerWidget->horizontalHeader()->setSectionResizeMode(PeerTableModel::Age, QHeaderView::ResizeToContents); ui->peerWidget->horizontalHeader()->setStretchLastSection(true); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); @@ -726,6 +726,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); } + ui->banlistWidget->horizontalHeader()->setSectionResizeMode(BanTableModel::Address, QHeaderView::ResizeToContents); ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); // create ban table context menu diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index c924789796..fd8eccb86d 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -380,8 +380,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa question_string.append("<hr />"); CAmount totalAmount = m_current_transaction->getTotalTransactionAmount() + txFee; QStringList alternativeUnits; - for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) - { + for (const BitcoinUnit u : BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 07d256f05a..aeedd92834 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -21,8 +21,10 @@ #endif // ENABLE_WALLET #include <QApplication> +#include <QDebug> #include <QObject> #include <QTest> + #include <functional> #if defined(QT_STATICPLUGIN) @@ -69,8 +71,6 @@ int main(int argc, char* argv[]) gArgs.ForceSetArg("-upnp", "0"); gArgs.ForceSetArg("-natpmp", "0"); - bool fInvalid = false; - // Prefer the "minimal" platform for the test instead of the normal default // platform ("xcb", "windows", or "cocoa") so tests can't unintentionally // interfere with any background GUIs and don't require extra resources. @@ -86,32 +86,32 @@ int main(int argc, char* argv[]) app.setApplicationName("Bitcoin-Qt-test"); app.createNode(*init); + int num_test_failures{0}; + AppTests app_tests(app); - if (QTest::qExec(&app_tests) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&app_tests); + OptionTests options_tests(app.node()); - if (QTest::qExec(&options_tests) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&options_tests); + URITests test1; - if (QTest::qExec(&test1) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&test1); + RPCNestedTests test3(app.node()); - if (QTest::qExec(&test3) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&test3); + #ifdef ENABLE_WALLET WalletTests test5(app.node()); - if (QTest::qExec(&test5) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&test5); + AddressBookTests test6(app.node()); - if (QTest::qExec(&test6) != 0) { - fInvalid = true; - } + num_test_failures += QTest::qExec(&test6); #endif - return fInvalid; + if (num_test_failures) { + qWarning("\nFailed tests: %d\n", num_test_failures); + } else { + qDebug("\nAll tests passed.\n"); + } + return num_test_failures; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 6ab534764b..c4cd0f4cd1 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -7,24 +7,25 @@ #include <interfaces/chain.h> #include <interfaces/node.h> +#include <key_io.h> #include <qt/bitcoinamountfield.h> +#include <qt/bitcoinunits.h> #include <qt/clientmodel.h> #include <qt/optionsmodel.h> +#include <qt/overviewpage.h> #include <qt/platformstyle.h> #include <qt/qvalidatedlineedit.h> +#include <qt/receivecoinsdialog.h> +#include <qt/receiverequestdialog.h> +#include <qt/recentrequeststablemodel.h> #include <qt/sendcoinsdialog.h> #include <qt/sendcoinsentry.h> #include <qt/transactiontablemodel.h> #include <qt/transactionview.h> #include <qt/walletmodel.h> -#include <key_io.h> #include <test/util/setup_common.h> #include <validation.h> #include <wallet/wallet.h> -#include <qt/overviewpage.h> -#include <qt/receivecoinsdialog.h> -#include <qt/recentrequeststablemodel.h> -#include <qt/receiverequestdialog.h> #include <chrono> #include <memory> @@ -196,7 +197,7 @@ void TestGUI(interfaces::Node& node) // Check balance in send dialog QLabel* balanceLabel = sendCoinsDialog.findChild<QLabel*>("labelBalance"); QString balanceText = balanceLabel->text(); - int unit = walletModel.getOptionsModel()->getDisplayUnit(); + BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit(); CAmount balance = walletModel.wallet().getBalance(); QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS); QCOMPARE(balanceText, balanceComparison); @@ -222,7 +223,7 @@ void TestGUI(interfaces::Node& node) overviewPage.setWalletModel(&walletModel); QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance"); QString balanceText = balanceLabel->text().trimmed(); - int unit = walletModel.getOptionsModel()->getDisplayUnit(); + BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit(); CAmount balance = walletModel.wallet().getBalance(); QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS); QCOMPARE(balanceText, balanceComparison); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index be5851d627..9e92f89543 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -32,20 +32,18 @@ using wallet::ISMINE_SPENDABLE; using wallet::ISMINE_WATCH_ONLY; using wallet::isminetype; -QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks) +QString TransactionDesc::FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool) { - { - int nDepth = status.depth_in_main_chain; - if (nDepth < 0) { - return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth); - } else if (nDepth == 0) { - const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()}; - return tr("0/unconfirmed, %1").arg(inMempool ? tr("in memory pool") : tr("not in memory pool")) + abandoned; - } else if (nDepth < 6) { - return tr("%1/unconfirmed").arg(nDepth); - } else { - return tr("%1 confirmations").arg(nDepth); - } + int depth = status.depth_in_main_chain; + if (depth < 0) { + return tr("conflicted with a transaction with %1 confirmations").arg(-depth); + } else if (depth == 0) { + const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()}; + return tr("0/unconfirmed, %1").arg(inMempool ? tr("in memory pool") : tr("not in memory pool")) + abandoned; + } else if (depth < 6) { + return tr("%1/unconfirmed").arg(depth); + } else { + return tr("%1 confirmations").arg(depth); } } @@ -77,7 +75,7 @@ bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant) return false; } -QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit) +QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit) { int numBlocks; interfaces::WalletTxStatus status; @@ -95,7 +93,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall CAmount nDebit = wtx.debit; CAmount nNet = nCredit - nDebit; - strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks); + strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(status, inMempool); strHTML += "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index cf955a433c..803e41b699 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_QT_TRANSACTIONDESC_H #define BITCOIN_QT_TRANSACTIONDESC_H +#include <qt/bitcoinunits.h> + #include <QObject> #include <QString> @@ -24,12 +26,12 @@ class TransactionDesc: public QObject Q_OBJECT public: - static QString toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit); + static QString toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit); private: TransactionDesc() {} - static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks); + static QString FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool); }; #endif // BITCOIN_QT_TRANSACTIONDESC_H diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index dd34656d5f..d8748d7dc9 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -20,13 +20,7 @@ struct WalletTxStatus; /** UI model for transaction status. The transaction status is the part of a transaction that will change over time. */ -class TransactionStatus -{ -public: - TransactionStatus() : countsForBalance(false), sortKey(""), - matures_in(0), status(Unconfirmed), depth(0), open_for(0) - { } - +struct TransactionStatus { enum Status { Confirmed, /**< Have 6 or more confirmations (normal tx) or fully mature (mined tx) **/ /// Normal (sent/received) transactions @@ -40,28 +34,25 @@ public: }; /// Transaction counts towards available balance - bool countsForBalance; + bool countsForBalance{false}; /// Sorting key based on status std::string sortKey; /** @name Generated (mined) transactions @{*/ - int matures_in; + int matures_in{0}; /**@}*/ /** @name Reported status @{*/ - Status status; - qint64 depth; - qint64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number - of additional blocks that need to be mined before - finalization */ + Status status{Unconfirmed}; + qint64 depth{0}; /**@}*/ /** Current block hash (to know whether cached status is still valid) */ uint256 m_cur_block_hash{}; - bool needsUpdate; + bool needsUpdate{false}; }; /** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 6b0495f5a8..7b932890cf 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -5,6 +5,7 @@ #include <qt/transactiontablemodel.h> #include <qt/addresstablemodel.h> +#include <qt/bitcoinunits.h> #include <qt/clientmodel.h> #include <qt/guiconstants.h> #include <qt/guiutil.h> @@ -232,7 +233,7 @@ public: return nullptr; } - QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit) + QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit) { return TransactionDesc::toHTML(node, wallet, rec, unit); } diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index e7ec54721a..344bf628bb 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -23,7 +23,6 @@ #include <util/strencodings.h> #include <QAction> -#include <QActionGroup> #include <QFileDialog> #include <QHBoxLayout> #include <QProgressDialog> diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 2f9d344bc8..301084ffa9 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_WALLETVIEW_H #include <consensus/amount.h> +#include <qt/bitcoinunits.h> #include <QStackedWidget> @@ -115,7 +116,7 @@ Q_SIGNALS: /** Encryption status of wallet changed */ void encryptionStatusChanged(); /** Notify that a new transaction appeared */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); + void incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); /** Notify that the out of sync warning icon has been pressed */ void outOfSyncWarningClicked(); }; diff --git a/src/random.cpp b/src/random.cpp index b862510524..77d2ae4d43 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -13,7 +13,7 @@ #include <compat.h> // for Windows API #include <wincrypt.h> #endif -#include <logging.h> // for LogPrintf() +#include <logging.h> #include <randomenv.h> #include <support/allocators/secure.h> #include <sync.h> // for Mutex diff --git a/src/rest.cpp b/src/rest.cpp index a8eba05c3f..2aeb9c68c3 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -37,7 +37,6 @@ #include <univalue.h> using node::GetTransaction; -using node::IsBlockPruned; using node::NodeContext; using node::ReadBlockFromDisk; @@ -295,10 +294,10 @@ static bool rest_block(const std::any& context, CBlock block; const CBlockIndex* pblockindex = nullptr; const CBlockIndex* tip = nullptr; + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; { - ChainstateManager* maybe_chainman = GetChainman(context, req); - if (!maybe_chainman) return false; - ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); tip = chainman.ActiveChain().Tip(); pblockindex = chainman.m_blockman.LookupBlockIndex(hash); @@ -306,7 +305,7 @@ static bool rest_block(const std::any& context, return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } - if (IsBlockPruned(pblockindex)) + if (chainman.m_blockman.IsBlockPruned(pblockindex)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) @@ -333,7 +332,7 @@ static bool rest_block(const std::any& context, } case RESTResponseFormat::JSON: { - UniValue objBlock = blockToJSON(block, tip, pblockindex, tx_verbosity); + UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a124e0267c..f46e5e9fef 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -54,7 +54,6 @@ using node::BlockManager; using node::CCoinsStats; using node::CoinStatsHashType; using node::GetUTXOStats; -using node::IsBlockPruned; using node::NodeContext; using node::ReadBlockFromDisk; using node::SnapshotMetadata; @@ -161,7 +160,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex return result; } -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) +UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) { UniValue result = blockheaderToJSON(tip, blockindex); @@ -180,7 +179,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn case TxVerbosity::SHOW_DETAILS: case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: CBlockUndo blockUndo; - const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))}; + const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))}; for (size_t i = 0; i < block.vtx.size(); ++i) { const CTransactionRef& tx = block.vtx.at(i); @@ -565,11 +564,11 @@ static RPCHelpMan getblockheader() }; } -static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) +static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); CBlock block; - if (IsBlockPruned(pblockindex)) { + if (blockman.IsBlockPruned(pblockindex)) { throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); } @@ -583,11 +582,11 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_RE return block; } -static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(::cs_main); CBlockUndo blockUndo; - if (IsBlockPruned(pblockindex)) { + if (blockman.IsBlockPruned(pblockindex)) { throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); } @@ -701,8 +700,8 @@ static RPCHelpMan getblock() CBlock block; const CBlockIndex* pblockindex; const CBlockIndex* tip; + ChainstateManager& chainman = EnsureAnyChainman(request.context); { - ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); pblockindex = chainman.m_blockman.LookupBlockIndex(hash); tip = chainman.ActiveChain().Tip(); @@ -711,7 +710,7 @@ static RPCHelpMan getblock() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - block = GetBlockChecked(pblockindex); + block = GetBlockChecked(chainman.m_blockman, pblockindex); } if (verbosity <= 0) @@ -731,7 +730,7 @@ static RPCHelpMan getblock() tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT; } - return blockToJSON(block, tip, pblockindex, tx_verbosity); + return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity); }, }; } @@ -1205,18 +1204,18 @@ RPCHelpMan getblockchaininfo() CHECK_NONFATAL(tip); const int height = tip->nHeight; UniValue obj(UniValue::VOBJ); - obj.pushKV("chain", Params().NetworkIDString()); - obj.pushKV("blocks", height); - obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); - obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); - obj.pushKV("difficulty", (double)GetDifficulty(tip)); - obj.pushKV("time", (int64_t)tip->nTime); - obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); - obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); - obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); - obj.pushKV("chainwork", tip->nChainWork.GetHex()); + obj.pushKV("chain", Params().NetworkIDString()); + obj.pushKV("blocks", height); + obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1); + obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); + obj.pushKV("difficulty", (double)GetDifficulty(tip)); + obj.pushKV("time", (int64_t)tip->nTime); + obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); + obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); + obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); + obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); - obj.pushKV("pruned", node::fPruneMode); + obj.pushKV("pruned", node::fPruneMode); if (node::fPruneMode) { const CBlockIndex* block = tip; CHECK_NONFATAL(block); @@ -1777,8 +1776,8 @@ static RPCHelpMan getblockstats() } } - const CBlock block = GetBlockChecked(pindex); - const CBlockUndo blockUndo = GetUndoChecked(pindex); + const CBlock block = GetBlockChecked(chainman.m_blockman, pindex); + const CBlockUndo blockUndo = GetUndoChecked(chainman.m_blockman, pindex); const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0; diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index a8c6d171cc..5fbd9d5fd3 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -10,6 +10,7 @@ #include <fs.h> #include <streams.h> #include <sync.h> +#include <validation.h> #include <any> #include <stdint.h> @@ -39,7 +40,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(const CBlockIndex*); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); +UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); /** Block header to JSON */ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main); diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp index d0bb937885..019f02f159 100644 --- a/src/script/miniscript.cpp +++ b/src/script/miniscript.cpp @@ -116,7 +116,8 @@ Type ComputeType(Fragment nodetype, Type x, Type y, Type z, const std::vector<Ty "e"_mst.If(x << "f"_mst) | // e=f_x (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x (x & "ms"_mst) | // m=m_x, s=s_x - "nudx"_mst; // n, u, d, x + // NOTE: 'd:' is not 'u' under P2WSH as MINIMALIF is only a policy rule there. + "ndx"_mst; // n, d, x case Fragment::WRAP_V: return "V"_mst.If(x << "B"_mst) | // V=B_x (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x diff --git a/src/sync.h b/src/sync.h index af7595e6fa..c69b58741b 100644 --- a/src/sync.h +++ b/src/sync.h @@ -223,12 +223,12 @@ public: friend class reverse_lock; }; -#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__) +#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__) template<typename MutexArg> using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>; -#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) +#define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) \ DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__); diff --git a/src/test/data/key_io_invalid.json b/src/test/data/key_io_invalid.json index abe07dad24..8f55abfec7 100644 --- a/src/test/data/key_io_invalid.json +++ b/src/test/data/key_io_invalid.json @@ -6,207 +6,207 @@ "x" ], [ - "2v7k5Bb8Lr1MMgTgW6HAf5YHXi6BzpPjHpQ4srD4RSwHYpzXKiXmLAgiLhkXvp3JF5v7nq45EWr" + "1GAdfviErV2Ew95FPtZyikz2qGP3gyCB6Hyu94sedAkPpA523m3fQwps9YKUZkKgQckGPKhRsFR" ], [ - "RAZzCGtMbiUgMiiyrZySrSpdfnQReFXA3r" + "37G2kMDLpmWVhimxRdzwNfE8JFvWXnJYnVcXeeGrek2qumdJuK7XArcVVpRtLLjRra3t64BEPF2" ], [ - "NYamy7tcPQTzoU5iyQojD3sqhiz7zxkvn8" + "giymtio7u7oqWtmC9YnvAEKkLF3JQpAdkEFkVJKYrVDfaLbhaDpX1ihfF2vZmya1i61fwLPC3YQ" ], [ - "geaFG555Ex5nyRf7JjW6Pj2GwZA8KYxtJJLbr1eZhVW75STbYBZeRszy3wg4pkKdF4ez9J4wQiz" + "8iVk9nLM3nYwRuwypjy9NK5rsuZH7BbrQRZ1pgcQmvMnjAgRXD" ], [ - "2Cxmid3c2XQ2zvQ8SA1ha2TKqvqbJS9XFmXRsCneBS3Po7Qqb65z5zNdsoF9AfieXFcpoVPmkmfa" + "cPTVQ1hbo4qdoysf6Jx5GthqucNmdfqt6J2pZRFeXv8Ep7Kmjqud" ], [ - "gaJ7UVge2njVg9tFTetJrtHgruMm7aQDiSAxfHrVEgzK8N2ooagDVmDkdph434xzc4K96Gjyxcs" + "cQbR2Ny85XFBzUMx3Ed6HsTLw2pVruSgPvt5AofnBUnhiv86gYeW" ], [ - "5JN5BEVQPZ3tAiatz1RGXkrJuE3EC6bervMaPb38wTNgEuZCeqp" + "2UB3iG3VJbX2TRrMwm6ssWskgvU9VjFBYSqCzwqkrihCwo7mg4mtS4WuGZgxTKuxf5A3EcotYEymz" ], [ - "3TnFbyUtBRS5rE1KTW81qLVspjJNaB3uu6uuvLjxhZo2DB6PCGh" + "cQe12pqwPR6ExtZKfrKf1q4b3CTh1Qi7MwuvMvzs79nWXDvESfBJ" ], [ - "7UgSZGaMaTc4d2mdEgcGBFiMeS6eMsithGUqvBsKTQdGzD7XQDbMEYo3gojdbXEPbUdFF3CQoK72f" + "tc1qeul5g2xfkvdkrhcfmdursv73ad64jnkjl9c40f" ], [ - "9261wfqQqruNDnBDhbbb4tN9oKA1KpRFHeoYeufyJApVGixyAG4V" + "bt1pq65rzej5glw3ra79gav6fqnx4haa0z257qr3mc8cggkefahmgvyseufhc0" ], [ - "cS824CTUh18scFmYuqt6BgxuRhdR4dEEnCHs3fzBbcyQgbfasHbw" + "tb13hty4qmumlwpp6chxjvcyzza4duqgtmxw3xhm3u9ahj4nyhtwz8eq7ynrj4" ], [ - "tc1q0ywf7wkz6t580n3yemd3ucfw8jxn93tpc6wskt" + "bcrt1r2qxpwuge" ], [ - "bt1pxeeuh96wpm5c6u3kavts2qgwlv6y8um7u7ga6ltlwrhrv7w9vers8lgt3k" + "bc10uexgzna2dpfk0vjt35srz6a27ps6m0l89jweznt83n2sqn2fx4hvn9ym5af8wut34sfrqhk3" ], [ - "tb130lvl2lyugsk2tf3zhwcjjv39dmwt2tt7ytqaexy8edwcuwks6p5scll5kz" + "tb1qum6uh0pt4q253qaf520929737v63w5gf" ], [ - "bcrt1rhsveeudk" + "bcrt1q888ryfgxpvl0k7vum8zpyar2u2sexvdhkf38ue37yknmqq0ycrwpl3w48y" ], [ - "bc10rmfwl8nxdweeyc4sf89t0tn9fv9w6qpyzsnl2r4k48vjqh03qas9asdje0rlr0phru0wqw0p" + "bc1qdsuzmn04k2z8vryw8l4dj8m5ygqgnne5n" ], [ - "tb1qjqnfsuatr54e957xzg9sqk7yqcry9lns" + "tb1qlj8es50nc8j8r8xshrjgzmw5azx89efghmw8ju6zcqla0g6xcnrstsjz7k" ], [ - "bcrt1q8p08mv8echkf3es027u4cdswxlylm3th76ls8v6y4zy4vwsavngpr4e4td" + "bcrt1qzwmyj0z924g7fzs5yvnrkc43y76RVyr2lh5t4r" ], [ - "BC1QNC2H66VLWTWTW52DP0FYUSNU3QQG5VT4V" + "bc1qpu6d26mrulzetu4jqhd7rsunv9aqru26f5c4j8" ], [ - "tb1qgk665m2auw09rc7pqyf7aulcuhmatz9xqtr5mxew7zuysacaascqs9v0vn" + "tb1qun6d26ufh77ghny6u5u8cwz9da7qwc6k4wkuceae9tth06eqlw0syupl4w" ], [ - "bcrt17CAPP7" + "bcrt1qj7g2jps453kj9htk9cxyyc2nxe69x4kzzmth7v" ], [ - "bc1qxmf2d6aerjzam3rur0zufqxqnyqfts5u302s7x" + "bc1p702xksx4z3uqf0u2phllxkfe5cgu0adxptqs0uelx0tqt8e885sqryes2l" ], [ - "tb1qn8x5dnzpexq7nnvrvnhwr9c3wkakpcyu9wwsjzq9pstkwg0t6qhs4l3rv6" + "tb1z7gmh0v6pc30z4xum76lmw8w86yswrlmw" ], [ - "BCRT1Q397G2RNVYRL5LK07CE8NCKHVKP8Z4SC9U0MVH9" + "bcrt1sjsrw6nun4h502cr97xmnyyuhkr22q0s6efrgtu" ], [ - "bc1pgxwyajq0gdn389f69uwn2fw9q0z5c9s063j5dgkdd23ajaud4hpsercr9h" + "2UVPFpGYnLHJezFzjUo42our6PMEoozzRdM" ], [ - "tb1z6mnmp5k542l6yk4ul0mp4rq3yvz44lfm" + "2MygHQjE1U33q3LSC53p69YqFjP8PihumJAF" ], [ - "bcrt17capp7" + "KzNbAQ4mexfAxa6RKBzHQqfoTycaeWpv2p" ], [ - "2D2bqvKseKHdoKjCNvjVULUgmxHu9hjKGwDbPRjTRH59tsHNLeyKwq3vyVBbo9LByY9wiapqjwFY" + "2jDPrDfAKihCGPbPD9ztY8TswAia4V8Bc6vx" ], [ - "2SSjAim4wZpeQRe5zTj1qqS6Li9ttJDaZ3ze" + "4VQUNG1hG64QFtaNyQZQWDdwpxB275Pwb3tvyPt2HDxB8Mi2MgH8Tz3AC83YYiz9LydsLNXEZJLHY" ], [ - "mi9H6MjLwXxy9kxe1x4ToxyLRBsmcZxgVi" + "39TKsUQ5QpEL1wowc6GMUqak94ijirPuP69ooV3xsFmiKQX2dau" ], [ - "VciXoxEitcn88jy197J9n9cpJ1pZahzU3SyWUiHqLgcfjttLEEJz" + "2UEJjT3dSdwc8dAo7oedPzznXceXCEsBbDfAvSymqpqDrkZMv7JBEUpLyhkghioYAWC9W4sKysry" ], [ - "KppmwADGoExPT9Eq5hjRWpWFDbzJyfzHFgsfxBiDHNpVBgWPRNuy" + "7VmMEkphxCFSV1y659Th4dkk6x6bJS5eQvbt8rzUYKQyd6ACgwQ4vXHtXKFUwP2kW3XULipnHJdZ7" ], [ - "TN7EQXMxKffzvHo54yHHu9R4ks9f5gWBW3MMVf5k72zAqrgVK9ys" + "tc1qdlapns4zkn03juf2k9xwwpct209suj6mgcd9gh" ], [ - "92dbrMEYzP5dD5UhQ6maNkCQ4GLG42BM4Gc6XKZzSSMSfosfkkcB" + "bt1psa5eptk29c4jc9yumeseat3a0l5e2fpmw635za2p4gpwdnthueysxga9je" ], [ - "J7VQxPxyzuWEkRstQWpCz2AgysEz1APgnWCEQrFvkN3umAnCrhQF" + "tb13w8c43lykfj3lvm9sgp6dsnfjla3d57cm83seykunf0ltxjc9lt2q4efm4d" ], [ - "tc1qymllj6c96v5qj2504y27ldtner6eh8ldx38t83" + "bcrt1rjqr2tdkm" ], [ - "bt1flep4g" + "bc10lyxwnxa70l270e6fcmxr4x7dtgu2yvy7gzkurwxy4zhdvgaqrrn6pfg2flyhqzy5t5se8yu3" ], [ - "tb13c553hwygcgj48qwmr9f8q0hgdcfklyaye5sxzcpcjnmxv4z506xs90tchn" + "TB1QFDFM763VXVSUNZHQLPWC0Q8FG5LJX6ZN" ], [ - "bcrt1tyddyu" + "bcrt1q60chha7wfwlau4kdr4mlvyeyc8mnnh9dhxk05e0hmrxcuhghefj36uwyha" ], [ - "bc10qssq2mknjqf0glwe2f3587wc4jysvs3f8s6chysae6hcl6fxzdm4wxyyscrl5k9f5qmnf05a" + "bc1gmk9yu" ], [ - "tb1q425lmgvxdgtyl2m6xuu2pc354y4fvgg8" + "tb1ly0q7p" ], [ - "bcrt1q9wp8e5d2u3u4g0pll0cy7smeeuqezdun9xl439n3p2gg4fvgfvk3hu52hj" + "bcrt1qdwttaw38uf42wxw40kwk3u8nguyTQH3hx6jmqp" ], [ - "bc1qrz5acazpue8vl4zsaxn8fxtmeuqmyjkq3" + "bc1qtsvlht6730n04f2mpaj5vv8hrledn5n5ug8c79" ], [ - "tb1qkeuglpgmnex9tv3fr7htzfrh3rwrk23r52rx9halxzmv9fr85lwq0fwhmp" + "tb1dclvmr" ], [ - "bcrt1qd0t2wrhl7s57z99rsyaekpq0dyjcQRSSmz80r4" + "bcrt1q3fqvctqu48wsvggrt09vj0yk2gzzcscdp4h98u" ], [ - "BC1QXLFDUCGX90T3E53PQCNKJ2PK25MSF3VLPMVY6T" + "bc1prklpq7tjcawg89cmwwqr3u5apwav36xa4zz56ady7crsllm6mpnqts7p86" ], [ - "tb1qmycg4zszgnk34vaurx3cu8wpvteg9h40yq6cp52gt26gjel03t3su3x3xu" + "tb1zkm58zyhxz3ffkfgsyprflg543slsl4c4" ], [ - "bcrt1q9hy58r4fnuxqzdqndpmq9pptc9nt2dw3rczf5e" + "bcrt1snzr5kaypnfhpnjanrhd20fhqcjxm3hfh7dw9fu" ], [ - "BC1PA7682NAY6JQSLUWAJYTC0ERWTMW7A4RPWLNTUS32LCXWLHVKKKTQ2UL8CG" + "2GgnYKqBGuA2Mm5GnrPsMTZR81xPhNtgMYoFUZngZGiobhCuUpCaTriUHRcgFreEekNdPAR17q8d" ], [ - "tb1z850dpxnwz2fzae5h2myatj4yvu6rq5xq" + "AZEah8d1EK362okRBS66e8SvdtYkrE8tsX" ], [ - "bcrt1sp525pzjsmpqvcrawjreww36e9keg876skjvpwt" + "gep8xr77FyPW6zYP15RiV9W8nL6w2HyHB16cUDakfyDceMA6ZzUdhJjk2LPuLYHnLkBqkRTTi6z" ], [ - "xcAvW5jurCpzSpLxBKEhCewCgwwuGhqJnC" + "2NDNP7GY59tTJPZTpbkprhM9SR99Nn5rUs7" ], [ - "2Cvv8yp9kXbQt8EKh6Yma95yJ1uwYF9YKXuVhGJyu3dHGVsb2AVpTC62TFACZZ3KDNrALxR2CVNs" + "2Csgzy2T287YAjeU5tFtt1nPshBZAUFQi4WtgaWyZGKSBNnKXHy2Tmxo8QK4Mfdds977ShcDWC5o" ], [ - "niUuL46hCuEVvkAzZKHvD746qbmLmzip9Pv3F6UZV14JxzEXBnTkVxCT4URapChJG6qAEgsZs6G" + "Kwjk3Vy6sdXMQDGWJzaWmqFxUNtWZCX1q4F4Kpt8jNNUoWJUUaTY" ], [ - "2UHHgGfiipzvB8Eumnmvq6SowvrMJimjT3NwwG1839XEiUfwtpSdkUrseNsQuagXv21ce7aZu6yo" + "Svj8kk98bAS9V4L2crmxakbhmnPm3cJ1tJ4Je4yVzDreU8eSTFURS1SPYv5oWEQD8Q9VBDvx5uF" ], [ - "8u9djKu4u6o3bsgeR4BKNnLK3akpo64FYzDAmA9239wKeshgF97" + "KNYsv6v9GtkGeD4WdQnBEJCrPKQm91PTxAbCfXr66LEd4JDmhPWC" ], [ - "TC1QPAARXSLVMXHVRR0474LZXQYZWLGFZYPSFVL9E4" + "2UJ2H2xvAeXmFKfQwMyDoSdQTTPFMNCT3SsoUafBWKzoGP3NsUK1buEgQZG38viyD53jgMdpqfT7" ], [ - "bt1pakek0n2267t9yaksxaczgr2syhv9y3xkx0wnsdwchfa6xkmjtvuqg3kgyr" + "6aLMfayKF4TW4ecn5SEc8FExpyJA2peKxYRGZhes6tQ4NTTzuGy" ], [ - "tb13h83rtwq62udrhwpn87uely7cyxcjrj0azz6a4r3n9s87x5uj98ys6ufp83" + "7VP4FmcebU2thJns9MnXde7LWfuqR5vMizrAuUoq2GcJjzTyA4RHFcPVdZL8PLg1SbpSFdJrvLXoY5" ], [ - "bcrt1rk5vw5qf2" + "tc1q5qdvt99uc92jyz663dtdpfpv6nr67ahmgwcpq2" ], [ - "bc10d3rmtg62h747en5j6fju5g5qyvsransrkty6ghh96pu647wumctejlsngh9pf26cysrys2x2" + "bt1peu3ppd7x796sjjenp09r8cs22rhylqm9lhggk72qp8q22vzft0wq2a0x6j" ], [ - "tb1qajuy2cdwqgmrzc7la85al5cwcq374tsp" + "tb1323z3lnz7dl3kd0nsuh6xy4he9almzl67anxgg3xdzkaxc9rwntlqdhdzd7" ], [ - "bcrt1q3udxvj6x20chqh723mn064mzz65yr56ef00xk8czvu3jnx04ydapzk02s5" + "bcrt1r2gc42sky" ], [ - "bc1qule2szwzyaq4qy0s3aa4mauucyqt6fewe" + "bc10fd889x4hd54tqu2ewg9t4hhft2wl7m6x50av4uswzw46xe6as0xmltfg7vrjfkvm459vld7w" ], [ - "tb1ql0qny5vg9gh5tyzke6dw36px5ulkrp24x53x0pl2t5lpwrtejw3s2seej2" + "TB1QZY7V0F2AT3308YGGNGN66ULJTCN3RY6F" ], [ - "bcrt17CAPP7" + "bcrt1qjg3cwht92znyw0l4r5rtctmls337nrc7g0ry9drjxmlecjd3atl3fake7c" ], [ - "bc1qtvm6davyf725wfedc2d5mrgfewqgcrce8gjrpl" + "bc1qmgf8xt8xkecl79k04mma3lz34gqep7hg4" ], [ - "tb1q5acjgtqrrw3an0dzavxxxzlex8k7aukjzjk9v2u4rmfdqxjphcyq7ge97e" + "TB1Q3F9WGNXE9ZMTTMDN5VKVKHYZ8Y0LCV72YV7V5LSXTJXEYHNHEHASLYL0TZ" ] ] diff --git a/src/test/data/key_io_valid.json b/src/test/data/key_io_valid.json index 5dee44c04b..c051f8b76b 100644 --- a/src/test/data/key_io_valid.json +++ b/src/test/data/key_io_valid.json @@ -1,71 +1,71 @@ [ [ - "1BShJZ8A5q53oJJfMJoEF1gfZCWdZqZwwD", - "76a914728d4cc27d19707b0197cfcd7c412d43287864b588ac", + "1FsSia9rv4NeEwvJ2GvXrX7LyxYspbN2mo", + "76a914a31c06bd463e3923bc1aadbde48b16976c08071788ac", { "chain": "main", "isPrivkey": false } ], [ - "3L1YkZjdeNSqaZcNKZFXQfyokx3zVYm7r6", - "a914c8f37c3cc21561296ad81f4bec6b5de10ebc185187", + "36j4NfKv6Akva9amjWrLG6MuSQym1GuEmm", + "a914373b819a068f32b7a6b38b6b38729647cfde01c287", { "chain": "main", "isPrivkey": false } ], [ - "mhJuoGLgnJC8gdBgBzEigsoyG4omQXejPT", - "76a91413a92d1998e081354d36c13ce0c9dc04b865d40a88ac", + "mzK2FFDEhxqHcmrJw1ysqFkVyhUULo45hZ", + "76a914ce28b26c57472737f5c3561a1761185bd8589a4388ac", { "chain": "test", "isPrivkey": false } ], [ - "2N5VpzKEuYvZJbmg6eUNGnfrrD1ir92FWGu", - "a91486648cc2faaf05660e72c04c7a837bcc3e986f1787", + "2NC2hEhe28ULKAJkW5MjZ3jtTMJdvXmByvK", + "a914ce0bba75891ff9ec60148d4bd4a09ee2dc5c933187", { "chain": "test", "isPrivkey": false } ], [ - "mtQueCtmAnP3E4aBHXCiFNEQAuPaLMuQNy", - "76a9148d74ecd86c845baf9c6d4484d2d00e731b79e34788ac", + "mww4LvqtTMKvmeQvizPz2EQv26xTneWrbg", + "76a914b4110ba93ac54afc14da3bdd19614774a2d55d2988ac", { "chain": "signet", "isPrivkey": false } ], [ - "2NEvWRTHjh89gV52fkperFtwzoFWQiQmiCh", - "a914edc895152c67ccff0ba620bcc373b789ec68266f87", + "2N1r7aC69VHeE7yQJPDLi9T1PYq4wnwvjuT", + "a9145e5a35ab44b3efaea5129ba22b88ba3e2976614587", { "chain": "signet", "isPrivkey": false } ], [ - "mngdx94qJFhSf7A7SAEgQSC9fQJuapujJp", - "76a9144e9dba545455a80ce94c343d1cac9dec62cbf22288ac", + "n4fajahJrAuKbN7uNsKjLjQkz9Qn5ewJXQ", + "76a914fdeca3b08e38af53d7c4c60e3ad208ce5066441088ac", { "chain": "regtest", "isPrivkey": false } ], [ - "2NBzRN3pV56k3JUvSHifaHyzjGHv7ZS9FZZ", - "a914cd9da5642451273e5b6d088854cc1fad4a8d442187", + "2MxFajLApXpYk4VodBSZSt7rw8y4ryABkfA", + "a91436e9f191e0b75036a77f65e2eaa4752443233fbe87", { "chain": "regtest", "isPrivkey": false } ], [ - "5KcrFZvJ2p4dM6QVUPu53cKXcCfozA1PJLHm1mNAxkDYhgThLu4", - "ed6c796e2f62377410766214f55aa81ac9a6590ad7ed57c509c983bf648409ac", + "5JuW2AMDYu4xVwRG9DZW18VbzQrGcd5RCgb99sS6ehJsNQXu5b9", + "8f8943bf956de595665c38ffff23827e17c10cdc1c27a028caae6c9810626198", { "chain": "main", "isCompressed": false, @@ -73,8 +73,8 @@ } ], [ - "L195WBrf2G3nCnun4CLxrb8XKk9LbCqH43THh4n4QrL5SzRzpq9j", - "74f76c106e38d20514a99a86e4fe3bb28319e7dd2ad21dbc170cbb516a5358fa", + "L5nJeqKmpHp4P7F8ZYyjwc5a7P4d8EabuGAzfGJk7yC1BJyzNaEd", + "ff778740f88ddcf102aeb81daee289c044c4a4571c4b6f287400f4b8e0b843f8", { "chain": "main", "isCompressed": true, @@ -82,8 +82,8 @@ } ], [ - "92z6HnMQR4tWqjfVA3UaUN5EuUMgoVMdCa5rZFYZfmgyD7wxYCw", - "b8511e1d74549e305517d48a1d394d1be2cfa5d0f3c0d83f9f450316ffa01276", + "92ZdE5HoLafywnTBbzPxbvRmp75pSfzvdU3XaZGh1cToipgdHVh", + "80c32d81e91bdea04cd7a3819b32275fc3298af4c7ec87eb0099527d041ced5c", { "chain": "test", "isCompressed": false, @@ -91,8 +91,8 @@ } ], [ - "cTPnaF52x4w4Tq6afPxRHux3wbYb86thS7S45A7r3oZc1AHTQ6Qm", - "ad68c48d337181da125de9061933ececcdf7d917631af7d34f7e38082bff9a11", + "cV83kKisF3RQSvXbUCm9ox3kaz5JjEUBWcx8tNydfGJcyeUxuH47", + "e0fcd4ce4e3d0e3de091f21415bb7cd011fac288c42020a879f28c2a4387df9b", { "chain": "test", "isCompressed": true, @@ -100,8 +100,8 @@ } ], [ - "924U35yFcYkxe2JXGmuhSRVaShGyhRDZx1ysPmw1sAHuszGMoxq", - "3e8dfaf78d4f02b11d0b645648a4f3080d71d0d068979c47f7255c9a29eee01d", + "92QuSnywrhsV7WPZChTgSQA23uSmj9MCEEno1eRBDG9sg8M29cX", + "6cf636ed8ac1bab033b64f66feaba65f70e684731e3f39105605968d3a963801", { "chain": "signet", "isCompressed": false, @@ -109,8 +109,8 @@ } ], [ - "cRy1qCf2LUesGPQagTkYwk2V3PyN2KCPKgxeg6k6KoJPzH7nrVjw", - "82d4187690d6b59bcffda27dae52f2ecb87313cfc0904e0b674a27d906a65fde", + "cND53Dhp8eCZqG2ghe8YhSCGesXZ8fE5PGD1khrqNvEi4RBoXhEK", + "12b5a10f3a11e708dc5412833c47ab7c368a21b9efe19293793ec879ce683018", { "chain": "signet", "isCompressed": true, @@ -118,8 +118,8 @@ } ], [ - "932NTcHK35Apf2C3K9Zv1ZdeZEmB1x7ZT2Ju3SjoEY6pUgUpT7H", - "bd7dba24df9e003e145ae9b4862776413a0bb6fa5b4e42753397f2d9536e58a9", + "91mn1wYKEB1zyof1VFm8tMtocZx1oBrKKRCu9GCpgZvPmBLEJjp", + "18a86e5a6c6977ddba0daca7fba5190f67ba56ccdc1b3f31308972236c2e4776", { "chain": "regtest", "isCompressed": false, @@ -127,8 +127,8 @@ } ], [ - "cNa75orYQ2oos52zCnMaS5PG6XbNZKc5LpGxTHacrxwWeX4WAK3E", - "1d87e3c58b08766fea03598380ec8d59f8c88d5392bf683ab1088bd4caf073ee", + "cPisAUdLvqqAr6MYtXnrWvgvyUAwuNyuTvZkDGw6miPhZdaiSDNH", + "3fdfec1371cedcdb8c190ca6ff8ad603f817edc0d93c2a687c7b36dd66e70f2a", { "chain": "regtest", "isCompressed": true, @@ -136,8 +136,8 @@ } ], [ - "bc1q5cuatynjmk4szh40mmunszfzh7zrc5xm9w8ccy", - "0014a639d59272ddab015eafdef9380922bf843c50db", + "bc1qvyq0cc6rahyvsazfdje0twl7ez82ndmuac2lhv", + "00146100fc6343edc8c874496cb2f5bbfec88ea9b77c", { "chain": "main", "isPrivkey": false, @@ -145,8 +145,8 @@ } ], [ - "bc1qkw7lz3ahms6e0ajv27mzh7g62tchjpmve4afc29u7w49tddydy2syv0087", - "0020b3bdf147b7dc3597f64c57b62bf91a52f179076ccd7a9c28bcf3aa55b5a46915", + "bc1qyucykdlhp62tezs0hagqury402qwhk589q80tqs5myh3rxq34nwqhkdhv7", + "002027304b37f70e94bc8a0fbf500e0c957a80ebda87280ef58214d92f119811acdc", { "chain": "main", "isPrivkey": false, @@ -154,8 +154,8 @@ } ], [ - "bc1p5rgvqejqh9dh37t9g94dd9cm8vtqns7dndgj423egwggsggcdzmsspvr7j", - "5120a0d0c06640b95b78f965416ad6971b3b1609c3cd9b512aaa39439088211868b7", + "bc1p83n3au0rjylefxq2nc2xh2y4jzz4pm6zxj4mw5pagdjjr2a9f36s6jjnnu", + "51203c671ef1e3913f94980a9e146ba895908550ef4234abb7503d436521aba54c75", { "chain": "main", "isPrivkey": false, @@ -163,8 +163,8 @@ } ], [ - "bc1zr4pq63udck", - "52021d42", + "bc1z2rksukkjr8", + "520250ed", { "chain": "main", "isPrivkey": false, @@ -172,8 +172,8 @@ } ], [ - "tb1q74fxwnvhsue0l8wremgq66xzvn48jlc5zthsvz", - "0014f552674d978732ff9dc3ced00d68c264ea797f14", + "tb1qcrh3yqn4nlleplcez2yndq2ry8h9ncg3qh7n54", + "0014c0ef1202759fff90ff19128936814321ee59e111", { "chain": "test", "isPrivkey": false, @@ -181,8 +181,8 @@ } ], [ - "tb1qpt7cqgq8ukv92dcraun9c3n0s3aswrt62vtv8nqmkfpa2tjfghesv9ln74", - "00200afd802007e598553703ef265c466f847b070d7a5316c3cc1bb243d52e4945f3", + "tb1quyl9ujpgwr2chdzdnnalen48sup245vdfnh2jxhsuq3yx80rrwlq5hqfe4", + "0020e13e5e482870d58bb44d9cfbfccea78702aad18d4ceea91af0e022431de31bbe", { "chain": "test", "isPrivkey": false, @@ -190,8 +190,8 @@ } ], [ - "tb1ph9v3e8nxct57hknlkhkz75p5pnxnkn05cw8ewpxu6tek56g29xgqydzfu7", - "5120b9591c9e66c2e9ebda7fb5ec2f50340ccd3b4df4c38f9704dcd2f36a690a2990", + "tb1p35n52jy6xkm4wd905tdy8qtagrn73kqdz73xe4zxpvq9t3fp50aqk3s6gz", + "51208d2745489a35b75734afa2da43817d40e7e8d80d17a26cd4460b0055c521a3fa", { "chain": "test", "isPrivkey": false, @@ -199,8 +199,8 @@ } ], [ - "tb1ray6e8gxfx49ers6c4c70l3c8lsxtcmlx", - "5310e93593a0c9354b91c358ae3cffc707fc", + "tb1rgv5m6uvdk3kc7qsuz0c79v88ycr5w4wa", + "53104329bd718db46d8f021c13f1e2b0e726", { "chain": "test", "isPrivkey": false, @@ -208,8 +208,8 @@ } ], [ - "tb1q0sqzfp3zj42u0perxr6jahhu4y03uw4dypk6sc", - "00147c002486229555c7872330f52edefca91f1e3aad", + "tb1q3vya2h5435jkugq2few7dmktlrwq4ejmfaw7kr", + "00148b09d55e958d256e200a4e5de6eecbf8dc0ae65b", { "chain": "signet", "isPrivkey": false, @@ -217,8 +217,8 @@ } ], [ - "tb1q9jv4qnawnuevqaeadn47gkq05ev78m4qg3zqejykdr9u0cm7yutq6gu5dj", - "00202c99504fae9f32c0773d6cebe4580fa659e3eea044440cc89668cbc7e37e2716", + "tb1qxkhrl2s6ttrclckldruea0e8anhrehffl8xv7t0pdyrzm08v2hyqy408nf", + "002035ae3faa1a5ac78fe2df68f99ebf27ecee3cdd29f9cccf2de169062dbcec55c8", { "chain": "signet", "isPrivkey": false, @@ -226,8 +226,8 @@ } ], [ - "tb1pxqf7d825wjtcftj7uep8w24jq3tz8vudfaqj20rns8ahqya56gcs92eqtu", - "51203013e69d54749784ae5ee642772ab2045623b38d4f41253c7381fb7013b4d231", + "tb1pae5um27ahn8n73pgexe3kcwlp8dhswpn684h2k2w6t9a7w3eq65qephd5y", + "5120ee69cdabddbccf3f4428c9b31b61df09db783833d1eb75594ed2cbdf3a3906a8", { "chain": "signet", "isPrivkey": false, @@ -235,8 +235,8 @@ } ], [ - "tb1rsrzkyvu2rt0dcgexajtazlw5nft4j7494ay396q6auw9375wxsrsgag884", - "532080c562338a1adedc2326ec97d17dd49a57597aa5af4912e81aef1c58fa8e3407", + "tb1rx9n9g37az8mu236e5jpxdt0m67y4fuq8rhs0ss3djnm0kscfrwvq0ntlyg", + "532031665447dd11f7c54759a48266adfbd78954f0071de0f8422d94f6fb43091b98", { "chain": "signet", "isPrivkey": false, @@ -244,8 +244,8 @@ } ], [ - "bcrt1qwf52dt9y2sv0f7fwkcpmtfjf74d4np2saeljt6", - "00147268a6aca45418f4f92eb603b5a649f55b598550", + "bcrt1qdavt4j2sd7dlhqsavtnfxvzppw6k7qy97tmnu9", + "00146f58bac9506f9bfb821d62e69330410bb56f0085", { "chain": "regtest", "isPrivkey": false, @@ -253,8 +253,8 @@ } ], [ - "bcrt1q0lma84unycxl4n96etffthqlf7y5axyp4fxf64kmhymvw8l6pwfs39futd", - "00207ff7d3d793260dfaccbacad295dc1f4f894e9881aa4c9d56dbb936c71ffa0b93", + "bcrt1qan8gntac7z7me2ejt4hpru42ad2f759fmy0m3ejvs98656znv7eqga4uhv", + "0020ecce89afb8f0bdbcab325d6e11f2aaeb549f50a9d91fb8e64c814faa685367b2", { "chain": "regtest", "isPrivkey": false, @@ -262,8 +262,8 @@ } ], [ - "bcrt1p3xat2ryucc2v0adrktqnavfzttvezrr27ngltsa2726p2ehvxz4se722v2", - "512089bab50c9cc614c7f5a3b2c13eb1225ad9910c6af4d1f5c3aaf2b41566ec30ab", + "bcrt1pfwxjqvtt4tcxrtdluukfmy2dv7xd2qzdfy6kajv5nwn4yam3wxkq3553uh", + "51204b8d20316baaf061adbfe72c9d914d678cd5004d49356ec9949ba752777171ac", { "chain": "regtest", "isPrivkey": false, @@ -271,8 +271,8 @@ } ], [ - "bcrt1saflydw6e26xhp29euhy5jke5jjqyywk3wvtc9ulgw9dvxyuqy9hdnxthyw755c7ldavy7u", - "6028ea7e46bb59568d70a8b9e5c9495b349480423ad1731782f3e8715ac31380216ed9997723bd4a63df", + "bcrt1sx6p8njlx7h9mc2agz4yg82dzne23050ncq72cneeecez2pst8mahn8xecsf8g6hzx94420", + "6028368279cbe6f5cbbc2ba8154883a9a29e5517d1f3c03cac4f39ce3225060b3efb799cd9c412746ae2", { "chain": "regtest", "isPrivkey": false, @@ -280,72 +280,72 @@ } ], [ - "16y3Q1XVRZqMR9T1XL1FkvNtD2E1bXBuYa", - "76a9144171ec673aeb9fcf42af6094a3c82207e3b9a78188ac", + "1FjL87pn8ky6Vbavd1ZHeChRXtoxwRGCRd", + "76a914a19331b7b2627e663e25a7b001e4c0dcc5e21bc788ac", { "chain": "main", "isPrivkey": false } ], [ - "3CmZZnAiHVQgiAKSakf864oJMxN2BP1eLC", - "a914798575fc1041b9440c4e63c28e57e597d00b7e4387", + "3BZECeAH8gSKkjrTx8PwMrNQBLG18yHpvf", + "a9146c382dcdf5b284760c8e3fead91f7422cd76aa8787", { "chain": "main", "isPrivkey": false } ], [ - "mtCB3SoBo7EYUv8j54kUubGY4x3aJPY8nk", - "76a9148b0c5f9ee714e0d1d24642ad63d9d5f398d9b56588ac", + "n4YNbYuFdPwFrxSP8sjHFbAhUbLMUiY9jE", + "76a914fc8f9851f3c1e4719cd0b8e4816dd4e88c72e52888ac", { "chain": "test", "isPrivkey": false } ], [ - "2N5ymzzKpx6EdUR4UdMZ7t9hcuwqtpHwgw5", - "a9148badb3c3b5c0d39f906f7618e0018b7eae4baf7387", + "2NAeQVZayzVFAtgeC3iYJsjpjWDmsDph71A", + "a914bedc797342c03fd7a346c4c7857ca03d467013b687", { "chain": "test", "isPrivkey": false } ], [ - "myXnpYbub28zgiJupDdZSWZtDbjcyfJVby", - "76a914c59ac57661b57daadd7c0caf7318c14f54c6c0fa88ac", + "mnCBpkNMJEJLehgdEkzSo2eioniyJMxLpZ", + "76a914493c455551e48a1423263b62b127b436106a685488ac", { "chain": "signet", "isPrivkey": false } ], [ - "2MtLg8jS5jSXm9evMzTtvpLjy26dBmjFEoT", - "a9140c0007e89cea625d3bf9543baa5a470bb7e5b67287", + "2N5sNHomeNJDZv67AcFx9ES7FBZY4jx9KDA", + "a9148a776a0f34d56b63e7c595f2b205dbe1c393617a87", { "chain": "signet", "isPrivkey": false } ], [ - "mzCyqdf2UNGdpgkD9NBgLcxdwXRg1i9buY", - "76a914cd04311bdd1ef9c5c24e41930e032aade82a863a88ac", + "mfhE6jAUwjUDNZhaX1PAsDTKfneQF2Nshc", + "76a91401f15a4cc063dae4f4d56b89bfbc8bcc9ae5387c88ac", { "chain": "regtest", "isPrivkey": false } ], [ - "2N3zGiwFku2vQjYnAqXv5Qu2ztfYRhh7tbF", - "a91475d56d75c88e704d6c72fbe84ac1505abf736b4087", + "2MxNm1VHyVU4RuP3u1c1v5aQLk2dQjwy1Qk", + "a91438456f7c076356abadcc67b92ad777eb20fb9f8887", { "chain": "regtest", "isPrivkey": false } ], [ - "5JUHCgyxNSHg64wwju72eNsG6ajqo4Z2fHHw9iLDLfh69rSiL7w", - "5644d06d88855dacf3192a31df8f4acd8e4c155c52a86d2c1fa48303f5cff053", + "5HsL2nZuEebU5nM3RxNVQD9GcAnvNMahqQskf4fkqHe54zwd14e", + "06e8649790a90615a46d22dd762e0c42615336745356c2e16147c0f3d46b40d5", { "chain": "main", "isCompressed": false, @@ -353,8 +353,8 @@ } ], [ - "L2kZaexG69VSriMe9T2m1jkS86iPe3xNbjcdfakRC1PHe7ay78Ji", - "a50ee94aefcabf5a5d7c85be5b3844dee03c5604861dbfc77fe388c91e5a30f8", + "KwuVvu6hsuEMHrfFWJQV64tRrWX3QzqHH18JuAHYqYV6dqBvNKxd", + "147804bf8a0dfff35939a611c7f5a60ac107f33f33d6059f273d2079ab1d90f2", { "chain": "main", "isCompressed": true, @@ -362,8 +362,8 @@ } ], [ - "927JwT1ViCr5TD2ZX8CsMNhg17dXmou5xu4y2KiH54zD7i34UJq", - "4502a54c0026b0150281d41f40860d1e23870c63cdc32645bbed688f2ee41f64", + "921M1RNxghFcsVGqAJksQVbSgx36Yz4u6vebfz1wDujNvgNt93B", + "3777b341c45e2a9b9bf6bfb71dc7d129f64f1b9406ed4f93ade8f56065f1b732", { "chain": "test", "isCompressed": false, @@ -371,8 +371,8 @@ } ], [ - "cTpGGNPVy2Eagawohbr4aGtRJzpLnjxGsGYh9DUcBM45f3KdKGF6", - "ba005a0cb39587aab00bd54c848b59e8adaed47403228567ddc739c2a344ff59", + "cNEnbfF2fcxmmCLWqMAaq6fxJvVkwMbyU3kCbpQznz4Z1j6TZDGb", + "1397b0d4a03e1ab2c54dd9af99ce1ecbfb90c80a58886da95e1181a55703d96b", { "chain": "test", "isCompressed": true, @@ -380,8 +380,8 @@ } ], [ - "932PLCLA19yPNqV67qwHBSGjxi82LVzWBF7josL9ab4Q1kxgPGF", - "bd8677e076eb39770bf7e9f9e8d3f2cf257effab9b4c220fd3439ccfc208c984", + "93BcpCMKPmFCuY8bqS4k3HFrhJ1Afxi4uSsEeJFvX86GYW7PC7W", + "d27d1b6ef55ca2e4d475b5276f2dbb85f7a6459dceeb89c67b776fd3bb974452", { "chain": "signet", "isCompressed": false, @@ -389,8 +389,8 @@ } ], [ - "cViUpEy8URSsLjUvxwL7cEuNgCVqM7oKBzd1ZPbA4khcQsQJuj1j", - "f2b36ade8393e29dc71e52cb75ba1109ba210203cd7d0a5ae881ad6846516203", + "cUtwbyxoL1owPxUafgH2meEpydeywjhnTYv2mJaFHHchz39AaEgy", + "da3ed4ef1647e1733ec076919cab6156077ed9532e7c365acc425747e198b3e1", { "chain": "signet", "isCompressed": true, @@ -398,8 +398,8 @@ } ], [ - "92jddDjJCVDmJtgvBHQ9i58PMash8kwsYhRdNo22ea2MYPXdCBE", - "977bf8686f1bcad28f86c4c14afbd33215746bd19203647bf7ff9c6fddc9cc87", + "927zPWny2SiNaUmHF5NnGQXQWDwbByfFzXGgu88j91ZoutSosvE", + "468e0284f230153db8687d8ec23db079a5b67d72ca04174b3867b13e4ea9945e", { "chain": "regtest", "isCompressed": false, @@ -407,8 +407,8 @@ } ], [ - "cVwAuMoUqRo399X7vXzuzQyPEvZJMXM8c82zHzRkFCxPCSGx8A6y", - "f93acbbce02b8cb9ddca3fad495441e324cc01eb640b0a7b4c9f0e31644c822a", + "cRez45VGSp5EXNqm89K3NJJPSKKapJg5Kbw3atxr2337x2gtgYed", + "798d87586cffbe8c545ab374454e403b1eb831501ebe89f3c3b02f3137bd7b46", { "chain": "regtest", "isCompressed": true, @@ -416,8 +416,8 @@ } ], [ - "bc1qz377zwe5awr68dnggengqx9vrjt05k98q3sw2n", - "0014147de13b34eb87a3b66846668018ac1c96fa58a7", + "bc1qhxt04s5xnpy0kxw4x99n5hpdf5pmtzpqs52es2", + "0014b996fac2869848fb19d5314b3a5c2d4d03b58820", { "chain": "main", "isPrivkey": false, @@ -425,8 +425,8 @@ } ], [ - "bc1qkmhskpdzg8kdkfywhu09kswwn9qan9vnkrf6mk40jvnr06s6sz5ssf82ya", - "0020b6ef0b05a241ecdb248ebf1e5b41ce9941d99593b0d3addaaf932637ea1a80a9", + "bc1qgc9ljrvdf2e0zg9rmmq86xklqwfys7r6wptjlacdgrcdc7sa6ggqu4rrxf", + "0020460bf90d8d4ab2f120a3dec07d1adf039248787a70572ff70d40f0dc7a1dd210", { "chain": "main", "isPrivkey": false, @@ -434,8 +434,8 @@ } ], [ - "bc1ps8cndas60cntk8x79sg9f5e5jz7x050z8agyugln2ukkks23rryqpejzkc", - "512081f136f61a7e26bb1cde2c1054d33490bc67d1e23f504e23f3572d6b415118c8", + "bc1pve739yap4uxjvfk0jrey69078u0gasm2nwvv483ec6zkzulgw9xqu4w9fd", + "5120667d1293a1af0d2626cf90f24d15fe3f1e8ec36a9b98ca9e39c6856173e8714c", { "chain": "main", "isPrivkey": false, @@ -443,8 +443,8 @@ } ], [ - "bc1zn4tsczge9l", - "52029d57", + "bc1zmjtqxkzs89", + "5202dc96", { "chain": "main", "isPrivkey": false, @@ -452,8 +452,8 @@ } ], [ - "tb1q6xw0wwd9n9d7ge87dryz4vm5vtahzhvz6yett3", - "0014d19cf739a5995be464fe68c82ab37462fb715d82", + "tb1ql4k5ayv7p7w0t0ge7tpntgpkgw53g2payxkszr", + "0014fd6d4e919e0f9cf5bd19f2c335a03643a914283d", { "chain": "test", "isPrivkey": false, @@ -461,8 +461,8 @@ } ], [ - "tb1qwn9zq9fu5uk35ykpgsc7rz4uawy4yh0r5m5er26768h5ur50su3qj6evun", - "002074ca20153ca72d1a12c14431e18abceb89525de3a6e991ab5ed1ef4e0e8f8722", + "tb1q9jx3x2qqdpempxrcfgyrkjd5fzeacaqj4ua7cs7fe2sfd2wdaueq5wn26y", + "00202c8d1328006873b098784a083b49b448b3dc7412af3bec43c9caa096a9cdef32", { "chain": "test", "isPrivkey": false, @@ -470,8 +470,8 @@ } ], [ - "tb1pmcdc5d8gr92rtemfsnhpeqanvs0nr82upn5dktxluz9n0qcv34lqxke0wq", - "5120de1b8a34e8195435e76984ee1c83b3641f319d5c0ce8db2cdfe08b37830c8d7e", + "tb1pdswckwd9ym5yf5eyzg8j4jjwnzla8y0tf9cp7aasfkek0u29sz9qfr00yf", + "51206c1d8b39a526e844d324120f2aca4e98bfd391eb49701f77b04db367f145808a", { "chain": "test", "isPrivkey": false, @@ -479,8 +479,8 @@ } ], [ - "tb1rgxjvtfzp0xczz6dlzqv8d5cmuykk4qkk", - "531041a4c5a44179b02169bf101876d31be1", + "tb1r0ecpfxg2udhtc556gqrpwwhk4sw3f0kc", + "53107e7014990ae36ebc529a4006173af6ac", { "chain": "test", "isPrivkey": false, @@ -488,8 +488,8 @@ } ], [ - "tb1qa9dlyt6fydestul4y4wh72yshh044w32np8etk", - "0014e95bf22f49237305f3f5255d7f2890bddf5aba2a", + "tb1q6mwf89hnqhlu8txjgjfs4s7p93ugffn3k062ll", + "0014d6dc9396f305ffc3acd244930ac3c12c7884a671", { "chain": "signet", "isPrivkey": false, @@ -497,8 +497,8 @@ } ], [ - "tb1qu4p26n0033720xm0rjgkds5ehdwf039k2fgv75um5krrvfhrrj7qckl9r2", - "0020e542ad4def8c7ca79b6f1c9166c299bb5c97c4b65250cf539ba5863626e31cbc", + "tb1qafrjalu4d73dql0czau9j6z422434kef235mzljf48ckd5xz3sys09jm97", + "0020ea472eff956fa2d07df8177859685552ab1adb295469b17e49a9f166d0c28c09", { "chain": "signet", "isPrivkey": false, @@ -506,8 +506,8 @@ } ], [ - "tb1pjyukm4n4flwd0ey3lrl06c9kalr60ggmlkcxq2rhhxmy4lvkmkpqexdzqy", - "512091396dd6754fdcd7e491f8fefd60b6efc7a7a11bfdb0602877b9b64afd96dd82", + "tb1pwst9qszjrhuv2e7as0flcq9gm698v6gdxzz9e87p07s8rssdx3zqklm3vf", + "512074165040521df8c567dd83d3fc00a8de8a76690d30845c9fc17fa071c20d3444", { "chain": "signet", "isPrivkey": false, @@ -515,8 +515,8 @@ } ], [ - "tb1r4k75s5syvewsvxufdc3xfhf4tw4u30alw39xny3dnxrl6hau7systymfdv", - "5320adbd485204665d061b896e2264dd355babc8bfbf744a69922d9987fd5fbcf409", + "tb1r3ss76jtsuxe8c8c8lxsehnpak55ylrgr345pww076l536ahjr6jsydamx3", + "53208c21ed4970e1b27c1f07f9a19bcc3db5284f8d038d681739fed7e91d76f21ea5", { "chain": "signet", "isPrivkey": false, @@ -524,8 +524,8 @@ } ], [ - "bcrt1qnk3tdwwj47ppc4pqmxkjdusegedn9ru5gvccwa", - "00149da2b6b9d2af821c5420d9ad26f219465b328f94", + "bcrt1q65nhlm4hf2ptg3t264al57p7wjxj2c3s6kyt83", + "0014d5277feeb74a82b4456ad57bfa783e748d256230", { "chain": "regtest", "isPrivkey": false, @@ -533,8 +533,8 @@ } ], [ - "bcrt1qz7prfshfkwsxuk72pt6mzr6uumq4qllxe4vmwqt89tat48d362yqlykk6a", - "0020178234c2e9b3a06e5bca0af5b10f5ce6c1507fe6cd59b701672afaba9db1d288", + "bcrt1qawvc90lpytw3z3k9etdx54l0exq5f5sqfzu5e45kjnl6slwayeeqx2dyac", + "0020eb9982bfe122dd1146c5cada6a57efc98144d20048b94cd69694ffa87ddd2672", { "chain": "regtest", "isPrivkey": false, @@ -542,8 +542,8 @@ } ], [ - "bcrt1pumee3wj80xvyr7wjmj7zsk26x5pn095aegy862yhx6f2j9sgc9hq6cj4cm", - "5120e6f398ba47799841f9d2dcbc28595a350337969dca087d28973692a91608c16e", + "bcrt1p39a4s4vdcw9kqa8w2t0rp7aj8kfxyw7mce5sk5d70x6wnnmpvt7skf2kxy", + "5120897b58558dc38b6074ee52de30fbb23d92623bdbc6690b51be79b4e9cf6162fd", { "chain": "regtest", "isPrivkey": false, @@ -551,8 +551,8 @@ } ], [ - "bcrt1szqz8hj64d2hhc6nt65v09jxal66pgff2xpcp9kj648qkk8kjzxelsts4dktd799g47uase", - "602810047bcb556aaf7c6a6bd518f2c8ddfeb414252a307012da5aa9c16b1ed211b3f82e156d96df14a8", + "bcrt1s489d9fhmyel0vzfqsrmew4x7r80asuqesm5hgqacy35daflcyufh3j8cgdtflvt99ph05m", + "6028a9cad2a6fb267ef6092080f79754de19dfd8701986e97403b82468dea7f8271378c8f843569fb165", { "chain": "regtest", "isPrivkey": false, @@ -560,48 +560,48 @@ } ], [ - "12agZTajtRE3STSchwWNWnrm467zzTQ916", - "76a9141156e00f70061e5faba8b71593a8c7554b47090c88ac", + "1G9A9j6W8TLuh6dEeVwWeyibK1Uc5MfVFV", + "76a914a614da54daacdb8861f451a0b7e3c27cdf8a099e88ac", { "chain": "main", "isPrivkey": false } ], [ - "3NXqB6iZiPYbKruNT3d9xNBTmtb73xMvvf", - "a914e49decc9e5d97e0547d3642f3a4795b13ae62bca87", + "33GA3ZXbw5o5HeUrBEaqkWXFYYZmdxGRRP", + "a914113ca1afeb49ff3abf176ffa19c2a2b4df19712a87", { "chain": "main", "isPrivkey": false } ], [ - "mjgt4BoCYxjzWvJFoh68x7cj5GeaKDYhyx", - "76a9142dc11fc7b8072f733f690ffb0591c00f4062295c88ac", + "mwgS2HRbjyfYxFnR1nF9VKLvmdgMfFBmGq", + "76a914b14ce7070b53cb0e4b5b5f6e253e876990aeca2e88ac", { "chain": "test", "isPrivkey": false } ], [ - "2NCT6FdQ5MxorHgnFxLeHyGwTGRdkHcrJDH", - "a914d2a8ec992b0894a0d9391ca5d9c45c388c41be7e87", + "2MwBVrJQ76BdaGD76CTmou8cZzQYLpe4NqU", + "a9142b2c149cde619eae3d7fe995243b76a3417541aa87", { "chain": "test", "isPrivkey": false } ], [ - "mpomiA7wqDnMcxaNLC23eBuXAb4U6H4ZqW", - "76a91465e75e340415ed297c58d6a14d3c17ceeaa17bbd88ac", + "mfnJ8tEkqKNFE5YaHTXFxyHk2mnDK2fvDh", + "76a91402e6cd77e649ad8b281271f158fc964ca3f66cb088ac", { "chain": "signet", "isPrivkey": false } ], [ - "2N1pGAA5uatbU2PKvMA9BnJmHcK6yHfMiZa", - "a9145e008b6cc232164570befc23d216060bf4ea793b87", + "2My83D67ir7K8PPzeT6mE2oth3ZwNTVRS9F", + "a9144074d84d32ff62da7b1b3c61925b934bfeb34b0587", { "chain": "signet", "isPrivkey": false diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 6766fbf2d9..033c6e18d5 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -193,6 +193,19 @@ int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* op return 0; } +int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const +{ + constexpr std::array setsockopt_errnos{ + ENOMEM, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); + return -1; + } + return 0; +} + bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const { constexpr std::array wait_errnos{ diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 6c91844633..580105e442 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -68,6 +68,8 @@ public: int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; + int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override; + bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; bool IsConnected(std::string& errmsg) const override; diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 949d30dfd5..930582ea24 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(fixed_tests) Test("and_b(hash256(32ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac),a:and_b(hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),a:older(1)))", "82012088aa2032ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac876b82012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876b51b26c9a6c9a", TESTMODE_VALID | TESTMODE_NONMAL, 15, 3); Test("thresh(2,multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),a:multi(1,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),ac:pk_k(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01))", "522103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c721036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0052ae6b5121036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0051ae6c936b21022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ac6c935287", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 13, 7); Test("and_n(sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68),t:or_i(v:older(4252898),v:older(144)))", "82012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68876400676303e2e440b26967029000b269685168", TESTMODE_VALID, 14, 3); - Test("or_d(d:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b26968736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", TESTMODE_VALID, 14, 3); + Test("or_d(nd:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b2696892736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", TESTMODE_VALID, 15, 3); Test("c:and_v(or_c(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),v:multi(1,02c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db)),pk_k(03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764512102c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db51af682103acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeac", TESTMODE_VALID | TESTMODE_NEEDSIG, 8, 3); Test("c:and_v(or_c(multi(2,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00,02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),v:ripemd160(1b0f3c404d12075c68c938f9f60ebea4f74941a0)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "5221036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a002102352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d552ae6482012088a6141b0f3c404d12075c68c938f9f60ebea4f74941a088682103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 10, 6); Test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", TESTMODE_VALID, 14, 3); @@ -263,6 +263,15 @@ BOOST_AUTO_TEST_CASE(fixed_tests) BOOST_CHECK(ms_multi); BOOST_CHECK_EQUAL(ms_multi->GetOps(), 4); // 3 pubkeys + CMS BOOST_CHECK_EQUAL(ms_multi->GetStackSize(), 3); // 1 sig + dummy elem + script push + // The 'd:' wrapper leaves on the stack what was DUP'ed at the beginning of its execution. + // Since it contains an OP_IF just after on the same element, we can make sure that the element + // in question must be OP_1 if OP_IF enforces that its argument must only be OP_1 or the empty + // vector (since otherwise the execution would immediately fail). This is the MINIMALIF rule. + // Unfortunately, this rule is consensus for Taproot but only policy for P2WSH. Therefore we can't + // (for now) have 'd:' be 'u'. This tests we can't use a 'd:' wrapper for a thresh, which requires + // its subs to all be 'u' (taken from https://github.com/rust-bitcoin/rust-miniscript/discussions/341). + const auto ms_minimalif = miniscript::FromString("thresh(3,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),sc:pk_k(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798),sdv:older(32))", CONVERTER); + BOOST_CHECK(!ms_minimalif); // Timelock tests Test("after(100)", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock diff --git a/src/test/util/logging.h b/src/test/util/logging.h index ebe0ecf623..f477088392 100644 --- a/src/test/util/logging.h +++ b/src/test/util/logging.h @@ -36,6 +36,6 @@ public: ~DebugLogHelper() { check_found(); } }; -#define ASSERT_DEBUG_LOG(message) DebugLogHelper PASTE2(debugloghelper, __COUNTER__)(message) +#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message) #endif // BITCOIN_TEST_UTIL_LOGGING_H diff --git a/src/test/util/net.h b/src/test/util/net.h index 20c45058a1..e980fe4967 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -150,6 +150,8 @@ public: return 0; } + int SetSockOpt(int, int, const void*, socklen_t) const override { return 0; } + bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 211153f06c..13f17ca277 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -15,10 +15,10 @@ #include <interfaces/chain.h> #include <net.h> #include <net_processing.h> -#include <node/miner.h> -#include <noui.h> #include <node/blockstorage.h> #include <node/chainstate.h> +#include <node/miner.h> +#include <noui.h> #include <policy/fees.h> #include <pow.h> #include <rpc/blockchain.h> @@ -28,6 +28,7 @@ #include <script/sigcache.h> #include <shutdown.h> #include <streams.h> +#include <test/util/net.h> #include <txdb.h> #include <util/strencodings.h> #include <util/string.h> @@ -226,7 +227,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const /*deterministic=*/false, m_node.args->GetIntArg("-checkaddrman", 0)); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); - m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. + m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.chainman, *m_node.mempool, false); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f73cc5da5f..65c8b4ea60 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -481,8 +481,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces indexed_transaction_set::iterator newit = mapTx.insert(entry).first; // Update transaction for any feeDelta created by PrioritiseTransaction - // TODO: refactor so that the fee delta is calculated before inserting - // into mapTx. CAmount delta{0}; ApplyDelta(entry.GetTx().GetHash(), delta); if (delta) { diff --git a/src/util/epochguard.h b/src/util/epochguard.h index 0fec7d2624..7f6477fb3b 100644 --- a/src/util/epochguard.h +++ b/src/util/epochguard.h @@ -7,6 +7,7 @@ #define BITCOIN_UTIL_EPOCHGUARD_H #include <threadsafety.h> +#include <util/macros.h> #include <cassert> @@ -96,6 +97,6 @@ public: } }; -#define WITH_FRESH_EPOCH(epoch) const Epoch::Guard PASTE2(epoch_guard_, __COUNTER__)(epoch) +#define WITH_FRESH_EPOCH(epoch) const Epoch::Guard UNIQUE_NAME(epoch_guard_)(epoch) #endif // BITCOIN_UTIL_EPOCHGUARD_H diff --git a/src/util/macros.h b/src/util/macros.h index c9740c8e82..bf6ba665dc 100644 --- a/src/util/macros.h +++ b/src/util/macros.h @@ -8,6 +8,8 @@ #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) +#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) + /** * Converts the parameter X to a string after macro replacement on X has been performed. * Don't merge these into one macro! diff --git a/src/util/sock.cpp b/src/util/sock.cpp index 2029d70a37..b5c1e28294 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -105,6 +105,11 @@ int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len); } +int Sock::SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const +{ + return setsockopt(m_socket, level, opt_name, static_cast<const char*>(opt_val), opt_len); +} + bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const { #ifdef USE_POLL diff --git a/src/util/sock.h b/src/util/sock.h index 7510482857..dd2913a66c 100644 --- a/src/util/sock.h +++ b/src/util/sock.h @@ -115,6 +115,16 @@ public: void* opt_val, socklen_t* opt_len) const; + /** + * setsockopt(2) wrapper. Equivalent to + * `setsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this + * wrapper can be unit tested if this method is overridden by a mock Sock implementation. + */ + [[nodiscard]] virtual int SetSockOpt(int level, + int opt_name, + const void* opt_val, + socklen_t opt_len) const; + using Event = uint8_t; /** diff --git a/src/util/time.cpp b/src/util/time.cpp index f7712f0dc8..e428430bac 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -23,16 +23,6 @@ void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread static std::atomic<int64_t> nMockTime(0); //!< For testing -int64_t GetTime() -{ - int64_t mocktime = nMockTime.load(std::memory_order_relaxed); - if (mocktime) return mocktime; - - time_t now = time(nullptr); - assert(now > 0); - return now; -} - bool ChronoSanityCheck() { // std::chrono::system_clock.time_since_epoch and time_t(0) are not guaranteed @@ -80,11 +70,12 @@ template <typename T> T GetTime() { const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)}; - - return std::chrono::duration_cast<T>( + const auto ret{ mocktime.count() ? mocktime : - std::chrono::microseconds{GetTimeMicros()}); + std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch())}; + assert(ret > 0s); + return ret; } template std::chrono::seconds GetTime(); template std::chrono::milliseconds GetTime(); @@ -129,6 +120,8 @@ int64_t GetTimeSeconds() return int64_t{GetSystemTime<std::chrono::seconds>().count()}; } +int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); } + std::string FormatISO8601DateTime(int64_t nTime) { struct tm ts; time_t time_val = nTime; diff --git a/src/validation.cpp b/src/validation.cpp index f4b316f67a..58686632f9 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -69,7 +69,6 @@ using node::CBlockIndexHeightOnlyComparator; using node::CBlockIndexWorkComparator; using node::CCoinsStats; using node::CoinStatsHashType; -using node::fHavePruned; using node::fImporting; using node::fPruneMode; using node::fReindex; @@ -120,7 +119,6 @@ const std::vector<std::string> CHECKLEVEL_DOC { */ RecursiveMutex cs_main; -CBlockIndex *pindexBestHeader = nullptr; Mutex g_best_block_mutex; std::condition_variable g_best_block_cv; uint256 g_best_block; @@ -280,8 +278,9 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_ return false; if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE)) return false; - if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1) + if (active_chainstate.m_chain.Height() < active_chainstate.m_chainman.m_best_header->nHeight - 1) { return false; + } return true; } @@ -1602,8 +1601,8 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew) if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) { m_chainman.m_best_invalid = pindexNew; } - if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { - pindexBestHeader = m_chain.Tip(); + if (m_chainman.m_best_header != nullptr && m_chainman.m_best_header->GetAncestor(pindexNew->nHeight) == pindexNew) { + m_chainman.m_best_header = m_chain.Tip(); } LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__, @@ -2029,8 +2028,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid); if (it != m_blockman.m_block_index.end()) { if (it->second.GetAncestor(pindex->nHeight) == pindex && - pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && - pindexBestHeader->nChainWork >= nMinimumChainWork) { + m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex && + m_chainman.m_best_header->nChainWork >= nMinimumChainWork) { // This block is a member of the assumed verified chain and an ancestor of the best header. // Script verification is skipped when connecting blocks under the // assumevalid block. Assuming the assumevalid block is valid this @@ -2045,7 +2044,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, // artificially set the default assumed verified block further back. // The test against nMinimumChainWork prevents the skipping when denied access to any chain at // least as good as the expected chain. - fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); + fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); } } } @@ -2358,9 +2357,9 @@ bool CChainState::FlushStateToDisk( } if (!setFilesToPrune.empty()) { fFlushForPrune = true; - if (!fHavePruned) { + if (!m_blockman.m_have_pruned) { m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true); - fHavePruned = true; + m_blockman.m_have_pruned = true; } } } @@ -2904,7 +2903,7 @@ static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) { CBlockIndex* pindexHeader = nullptr; { LOCK(cs_main); - pindexHeader = pindexBestHeader; + pindexHeader = chainstate.m_chainman.m_best_header; if (pindexHeader != pindexHeaderOld) { fNotify = true; @@ -3621,7 +3620,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida } } } - CBlockIndex* pindex{m_blockman.AddToBlockIndex(block)}; + CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, m_best_header)}; if (ppindex) *ppindex = pindex; @@ -4122,13 +4121,11 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) { AssertLockHeld(::cs_main); chainman.Unload(); - pindexBestHeader = nullptr; if (mempool) mempool->clear(); g_versionbitscache.Clear(); for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { warningcache[b].clear(); } - fHavePruned = false; } bool ChainstateManager::LoadBlockIndex() @@ -4203,6 +4200,8 @@ bool ChainstateManager::LoadBlockIndex() if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) { m_best_invalid = pindex; } + if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex))) + m_best_header = pindex; } needs_init = m_blockman.m_block_index.empty(); @@ -4237,7 +4236,7 @@ bool CChainState::LoadGenesisBlock() if (blockPos.IsNull()) { return error("%s: writing genesis block to disk failed", __func__); } - CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); + CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, m_chainman.m_best_header); ReceivedBlockTransactions(block, pindex, blockPos); } catch (const std::runtime_error& e) { return error("%s: failed to write genesis block: %s", __func__, e.what()); @@ -4448,7 +4447,7 @@ void CChainState::CheckBlockIndex() // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. // Unless these indexes are assumed valid and pending block download on a // background chainstate. - if (!fHavePruned && !pindex->IsAssumedValid()) { + if (!m_blockman.m_have_pruned && !pindex->IsAssumedValid()) { // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0 assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); assert(pindexFirstMissing == pindexFirstNeverProcessed); @@ -4522,7 +4521,7 @@ void CChainState::CheckBlockIndex() if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked. if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) { // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent. - assert(fHavePruned); // We must have pruned. + assert(m_blockman.m_have_pruned); // We must have pruned. // This block may have entered m_blocks_unlinked if: // - it has a descendant that at some point had more work than the // tip, and @@ -5169,6 +5168,7 @@ void ChainstateManager::Unload() m_failed_blocks.clear(); m_blockman.Unload(); + m_best_header = nullptr; m_best_invalid = nullptr; } diff --git a/src/validation.h b/src/validation.h index 53ea2d4aea..2e7ab42f88 100644 --- a/src/validation.h +++ b/src/validation.h @@ -131,9 +131,6 @@ extern uint256 hashAssumeValid; /** Minimum work we will assume exists on some valid chain. */ extern arith_uint256 nMinimumChainWork; -/** Best header we've seen so far (used for getheaders queries' starting points). */ -extern CBlockIndex *pindexBestHeader; - /** Documentation for argument 'checklevel'. */ extern const std::vector<std::string> CHECKLEVEL_DOC; @@ -883,6 +880,9 @@ public: */ std::set<CBlockIndex*> m_failed_blocks; + /** Best header we've seen so far (used for getheaders queries' starting points). */ + CBlockIndex* m_best_header = nullptr; + //! The total number of bytes available for us to use across all in-memory //! coins caches. This will be split somehow across chainstates. int64_t m_total_coinstip_cache{0}; diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 4baf16fdcb..1291663847 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -257,7 +257,7 @@ static RPCHelpMan setwalletflag() { {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"}, {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"}, - {RPCResult::Type::STR, "warnings", "Any warnings associated with the change"}, + {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"}, } }, RPCExamples{ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2a0653c719..c3ae098aee 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -299,6 +299,13 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& return nullptr; } + // Do not allow a passphrase when private keys are disabled + if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled."); + status = DatabaseStatus::FAILED_CREATE; + return nullptr; + } + // Wallet::Verify will check if we're trying to create a wallet with a duplicate name. std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error); if (!database) { @@ -307,13 +314,6 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& return nullptr; } - // Do not allow a passphrase when private keys are disabled - if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled."); - status = DatabaseStatus::FAILED_CREATE; - return nullptr; - } - // Make the wallet context.chain->initMessage(_("Loading wallet…").translated); const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings); |