diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.test.include | 1 | ||||
-rw-r--r-- | src/bitcoin-cli.cpp | 13 | ||||
-rw-r--r-- | src/fs.h | 22 | ||||
-rw-r--r-- | src/index/base.h | 4 | ||||
-rw-r--r-- | src/index/coinstatsindex.cpp | 8 | ||||
-rw-r--r-- | src/primitives/transaction.h | 2 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 2 | ||||
-rw-r--r-- | src/streams.h | 101 | ||||
-rw-r--r-- | src/test/dbwrapper_tests.cpp | 4 | ||||
-rw-r--r-- | src/test/fs_tests.cpp | 24 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 8 | ||||
-rw-r--r-- | src/test/fuzz/script_format.cpp | 30 | ||||
-rw-r--r-- | src/util/overflow.h | 1 | ||||
-rw-r--r-- | src/util/syscall_sandbox.cpp | 6 | ||||
-rw-r--r-- | src/validation.cpp | 13 | ||||
-rw-r--r-- | src/validation.h | 2 |
16 files changed, 161 insertions, 80 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 1763dcb562..e2e08468a7 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -294,6 +294,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/script_bitcoin_consensus.cpp \ test/fuzz/script_descriptor_cache.cpp \ test/fuzz/script_flags.cpp \ + test/fuzz/script_format.cpp \ test/fuzz/script_interpreter.cpp \ test/fuzz/script_ops.cpp \ test/fuzz/script_sigcache.cpp \ diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 6557360a71..a85a74835d 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -606,8 +606,9 @@ public: "Suggestion: use with the Linux watch(1) command for a live dashboard; see example below.\n\n" "Arguments:\n" + strprintf("1. level (integer 0-%d, optional) Specify the info level of the peers dashboard (default 0):\n", MAX_DETAIL_LEVEL) + - " 0 - Connection counts and local addresses\n" - " 1 - Like 0 but with a peers listing (without address or version columns)\n" + " 0 - Peer counts for each reachable network as well as for block relay peers\n" + " and manual peers, and the list of local addresses and ports\n" + " 1 - Like 0 but preceded by a peers listing (without address and version columns)\n" " 2 - Like 1 but with an address column\n" " 3 - Like 1 but with a version column\n" " 4 - Like 1 but with both address and version columns\n" @@ -645,13 +646,13 @@ public: " id Peer index, in increasing order of peer connections since node startup\n" " address IP address and port of the peer\n" " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n" - "* The connection counts table displays the number of peers by direction, network, and the totals\n" - " for each, as well as two special outbound columns for block relay peers and manual peers.\n\n" + "* The peer counts table displays the number of peers for each reachable network as well as\n" + " the number of block relay peers and manual peers.\n\n" "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n" "Examples:\n\n" - "Connection counts and local addresses only\n" + "Peer counts table of reachable networks and list of local addresses\n" "> bitcoin-cli -netinfo\n\n" - "Compact peers listing\n" + "The same, preceded by a peers listing without address and version columns\n" "> bitcoin-cli -netinfo 1\n\n" "Full dashboard\n" + strprintf("> bitcoin-cli -netinfo %d\n\n", MAX_DETAIL_LEVEL) + @@ -140,6 +140,28 @@ static inline path PathFromString(const std::string& string) return std::filesystem::path(string); #endif } + +/** + * Create directory (and if necessary its parents), unless the leaf directory + * already exists or is a symlink to an existing directory. + * This is a temporary workaround for an issue in libstdc++ that has been fixed + * upstream [PR101510]. + */ +static inline bool create_directories(const std::filesystem::path& p) +{ + if (std::filesystem::is_symlink(p) && std::filesystem::is_directory(p)) { + return false; + } + return std::filesystem::create_directories(p); +} + +/** + * This variant is not used. Delete it to prevent it from accidentally working + * around the workaround. If it is needed, add a workaround in the same pattern + * as above. + */ +bool create_directories(const std::filesystem::path& p, std::error_code& ec) = delete; + } // namespace fs /** Bridge operations to C stdio */ diff --git a/src/index/base.h b/src/index/base.h index 66149686f0..c4a8215bc4 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -40,10 +40,10 @@ protected: DB(const fs::path& path, size_t n_cache_size, bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); - /// Read block locator of the chain that the txindex is in sync with. + /// Read block locator of the chain that the index is in sync with. bool ReadBestBlock(CBlockLocator& locator) const; - /// Write block locator of the chain that the txindex is in sync with. + /// Write block locator of the chain that the index is in sync with. void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator); }; diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index 7d4860b20b..a1c8a5937c 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -363,6 +363,14 @@ bool CoinStatsIndex::Init() return error("%s: Cannot read current %s state; index may be corrupted", __func__, GetName()); } + + uint256 out; + m_muhash.Finalize(out); + if (entry.muhash != out) { + return error("%s: Cannot read current %s state; index may be corrupted", + __func__, GetName()); + } + m_transaction_output_count = entry.transaction_output_count; m_bogo_size = entry.bogo_size; m_total_amount = entry.total_amount; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1fcbc45c72..fb98fb6868 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -201,7 +201,7 @@ struct CMutableTransaction; * - std::vector<CTxIn> vin * - std::vector<CTxOut> vout * - if (flags & 1): - * - CTxWitness wit; + * - CScriptWitness scriptWitness; (deserialized into CTxIn) * - uint32_t nLockTime */ template<typename Stream, typename TxType> diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 69204e346a..e5ad8f1a60 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1417,7 +1417,7 @@ static RPCHelpMan verifychain() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()); + const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()}; const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()}; ChainstateManager& chainman = EnsureAnyChainman(request.context); diff --git a/src/streams.h b/src/streams.h index cf8b4eb96f..96b7696f72 100644 --- a/src/streams.h +++ b/src/streams.h @@ -9,6 +9,7 @@ #include <serialize.h> #include <span.h> #include <support/allocators/zeroafterfree.h> +#include <util/overflow.h> #include <algorithm> #include <assert.h> @@ -186,7 +187,7 @@ class CDataStream protected: using vector_type = SerializeData; vector_type vch; - unsigned int nReadPos{0}; + vector_type::size_type m_read_pos{0}; int nType; int nVersion; @@ -229,37 +230,37 @@ public: // // Vector subset // - const_iterator begin() const { return vch.begin() + nReadPos; } - iterator begin() { return vch.begin() + nReadPos; } + const_iterator begin() const { return vch.begin() + m_read_pos; } + iterator begin() { return vch.begin() + m_read_pos; } const_iterator end() const { return vch.end(); } iterator end() { return vch.end(); } - size_type size() const { return vch.size() - nReadPos; } - bool empty() const { return vch.size() == nReadPos; } - void resize(size_type n, value_type c = value_type{}) { vch.resize(n + nReadPos, c); } - void reserve(size_type n) { vch.reserve(n + nReadPos); } - const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } - reference operator[](size_type pos) { return vch[pos + nReadPos]; } - void clear() { vch.clear(); nReadPos = 0; } - value_type* data() { return vch.data() + nReadPos; } - const value_type* data() const { return vch.data() + nReadPos; } + size_type size() const { return vch.size() - m_read_pos; } + bool empty() const { return vch.size() == m_read_pos; } + void resize(size_type n, value_type c = value_type{}) { vch.resize(n + m_read_pos, c); } + void reserve(size_type n) { vch.reserve(n + m_read_pos); } + const_reference operator[](size_type pos) const { return vch[pos + m_read_pos]; } + reference operator[](size_type pos) { return vch[pos + m_read_pos]; } + void clear() { vch.clear(); m_read_pos = 0; } + value_type* data() { return vch.data() + m_read_pos; } + const value_type* data() const { return vch.data() + m_read_pos; } inline void Compact() { - vch.erase(vch.begin(), vch.begin() + nReadPos); - nReadPos = 0; + vch.erase(vch.begin(), vch.begin() + m_read_pos); + m_read_pos = 0; } bool Rewind(std::optional<size_type> n = std::nullopt) { // Total rewind if no size is passed if (!n) { - nReadPos = 0; + m_read_pos = 0; return true; } // Rewind by n characters if the buffer hasn't been compacted yet - if (*n > nReadPos) + if (*n > m_read_pos) return false; - nReadPos -= *n; + m_read_pos -= *n; return true; } @@ -281,36 +282,32 @@ public: if (dst.size() == 0) return; // Read from the beginning of the buffer - unsigned int nReadPosNext = nReadPos + dst.size(); - if (nReadPosNext > vch.size()) { + auto next_read_pos{CheckedAdd(m_read_pos, dst.size())}; + if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) { throw std::ios_base::failure("CDataStream::read(): end of data"); } - memcpy(dst.data(), &vch[nReadPos], dst.size()); - if (nReadPosNext == vch.size()) - { - nReadPos = 0; + memcpy(dst.data(), &vch[m_read_pos], dst.size()); + if (next_read_pos.value() == vch.size()) { + m_read_pos = 0; vch.clear(); return; } - nReadPos = nReadPosNext; + m_read_pos = next_read_pos.value(); } - void ignore(int nSize) + void ignore(size_t num_ignore) { // Ignore from the beginning of the buffer - if (nSize < 0) { - throw std::ios_base::failure("CDataStream::ignore(): nSize negative"); + auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)}; + if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) { + throw std::ios_base::failure("CDataStream::ignore(): end of data"); } - unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) - { - if (nReadPosNext > vch.size()) - throw std::ios_base::failure("CDataStream::ignore(): end of data"); - nReadPos = 0; + if (next_read_pos.value() == vch.size()) { + m_read_pos = 0; vch.clear(); return; } - nReadPos = nReadPosNext; + m_read_pos = next_read_pos.value(); } void write(Span<const value_type> src) @@ -594,7 +591,7 @@ private: FILE *src; //!< source file uint64_t nSrcPos; //!< how many bytes have been read from source - uint64_t nReadPos; //!< how many bytes have been read from this + uint64_t m_read_pos; //!< how many bytes have been read from this uint64_t nReadLimit; //!< up to which position we're allowed to read uint64_t nRewind; //!< how many bytes we guarantee to rewind std::vector<std::byte> vchBuf; //!< the buffer @@ -604,7 +601,7 @@ protected: bool Fill() { unsigned int pos = nSrcPos % vchBuf.size(); unsigned int readNow = vchBuf.size() - pos; - unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind; + unsigned int nAvail = vchBuf.size() - (nSrcPos - m_read_pos) - nRewind; if (nAvail < readNow) readNow = nAvail; if (readNow == 0) @@ -619,7 +616,7 @@ protected: public: CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) - : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0}) + : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), m_read_pos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0}) { if (nRewindIn >= nBufSize) throw std::ios_base::failure("Rewind limit must be less than buffer size"); @@ -648,33 +645,33 @@ public: //! check whether we're at the end of the source file bool eof() const { - return nReadPos == nSrcPos && feof(src); + return m_read_pos == nSrcPos && feof(src); } //! read a number of bytes void read(Span<std::byte> dst) { - if (dst.size() + nReadPos > nReadLimit) { + if (dst.size() + m_read_pos > nReadLimit) { throw std::ios_base::failure("Read attempted past buffer limit"); } while (dst.size() > 0) { - if (nReadPos == nSrcPos) + if (m_read_pos == nSrcPos) Fill(); - unsigned int pos = nReadPos % vchBuf.size(); + unsigned int pos = m_read_pos % vchBuf.size(); size_t nNow = dst.size(); if (nNow + pos > vchBuf.size()) nNow = vchBuf.size() - pos; - if (nNow + nReadPos > nSrcPos) - nNow = nSrcPos - nReadPos; + if (nNow + m_read_pos > nSrcPos) + nNow = nSrcPos - m_read_pos; memcpy(dst.data(), &vchBuf[pos], nNow); - nReadPos += nNow; + m_read_pos += nNow; dst = dst.subspan(nNow); } } //! return the current reading position uint64_t GetPos() const { - return nReadPos; + return m_read_pos; } //! rewind to a given reading position @@ -682,22 +679,22 @@ public: size_t bufsize = vchBuf.size(); if (nPos + bufsize < nSrcPos) { // rewinding too far, rewind as far as possible - nReadPos = nSrcPos - bufsize; + m_read_pos = nSrcPos - bufsize; return false; } if (nPos > nSrcPos) { // can't go this far forward, go as far as possible - nReadPos = nSrcPos; + m_read_pos = nSrcPos; return false; } - nReadPos = nPos; + m_read_pos = nPos; return true; } //! prevent reading beyond a certain position //! no argument removes the limit bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) { - if (nPos < nReadPos) + if (nPos < m_read_pos) return false; nReadLimit = nPos; return true; @@ -714,12 +711,12 @@ public: void FindByte(uint8_t ch) { while (true) { - if (nReadPos == nSrcPos) + if (m_read_pos == nSrcPos) Fill(); - if (vchBuf[nReadPos % vchBuf.size()] == std::byte{ch}) { + if (vchBuf[m_read_pos % vchBuf.size()] == std::byte{ch}) { break; } - nReadPos++; + m_read_pos++; } } }; diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 2f95cc27a3..fc89fe1450 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { // We're going to share this fs::path between two wrappers fs::path ph = m_args.GetDataDirBase() / "existing_data_no_obfuscate"; - create_directories(ph); + fs::create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false); @@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) { // We're going to share this fs::path between two wrappers fs::path ph = m_args.GetDataDirBase() / "existing_data_reindex"; - create_directories(ph); + fs::create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false); diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index 4fb2c23d98..313064b294 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -152,4 +152,28 @@ BOOST_AUTO_TEST_CASE(rename) fs::remove(path2); } +#ifndef WIN32 +BOOST_AUTO_TEST_CASE(create_directories) +{ + // Test fs::create_directories workaround. + const fs::path tmpfolder{m_args.GetDataDirBase()}; + + const fs::path dir{GetUniquePath(tmpfolder)}; + fs::create_directory(dir); + BOOST_CHECK(fs::exists(dir)); + BOOST_CHECK(fs::is_directory(dir)); + BOOST_CHECK(!fs::create_directories(dir)); + + const fs::path symlink{GetUniquePath(tmpfolder)}; + fs::create_directory_symlink(dir, symlink); + BOOST_CHECK(fs::exists(symlink)); + BOOST_CHECK(fs::is_symlink(symlink)); + BOOST_CHECK(fs::is_directory(symlink)); + BOOST_CHECK(!fs::create_directories(symlink)); + + fs::remove(symlink); + fs::remove(dir); +} +#endif // WIN32 + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 14a59912db..fdcd0da37d 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -167,12 +167,4 @@ FUZZ_TARGET_INIT(script, initialize_script) Assert(dest == GetScriptForDestination(tx_destination_2)); } } - - (void)FormatScript(script); - (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool()); - - UniValue o1(UniValue::VOBJ); - ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool()); - UniValue o3(UniValue::VOBJ); - ScriptToUniv(script, o3); } diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp new file mode 100644 index 0000000000..2fa893f812 --- /dev/null +++ b/src/test/fuzz/script_format.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2019-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 <chainparams.h> +#include <core_io.h> +#include <script/script.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <univalue.h> + +void initialize_script_format() +{ + SelectParams(CBaseChainParams::REGTEST); +} + +FUZZ_TARGET_INIT(script_format, initialize_script_format) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const CScript script{ConsumeScript(fuzzed_data_provider)}; + + (void)FormatScript(script); + (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool()); + + UniValue o1(UniValue::VOBJ); + ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool()); + UniValue o3(UniValue::VOBJ); + ScriptToUniv(script, o3); +} diff --git a/src/util/overflow.h b/src/util/overflow.h index 5982af8d04..c70a8b663e 100644 --- a/src/util/overflow.h +++ b/src/util/overflow.h @@ -6,6 +6,7 @@ #define BITCOIN_UTIL_OVERFLOW_H #include <limits> +#include <optional> #include <type_traits> template <class T> diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp index f513dba598..f2a9cf664d 100644 --- a/src/util/syscall_sandbox.cpp +++ b/src/util/syscall_sandbox.cpp @@ -68,6 +68,10 @@ bool g_syscall_sandbox_log_violation_before_terminating{false}; #define __NR_copy_file_range 326 #endif +#ifndef __NR_rseq +#define __NR_rseq 334 +#endif + // This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in // order to be able to print user friendly error messages which include the syscall name in addition // to the syscall number. @@ -327,6 +331,7 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{ {__NR_request_key, "request_key"}, {__NR_restart_syscall, "restart_syscall"}, {__NR_rmdir, "rmdir"}, + {__NR_rseq, "rseq"}, {__NR_rt_sigaction, "rt_sigaction"}, {__NR_rt_sigpending, "rt_sigpending"}, {__NR_rt_sigprocmask, "rt_sigprocmask"}, @@ -723,6 +728,7 @@ public: allowed_syscalls.insert(__NR_fork); // create a child process allowed_syscalls.insert(__NR_tgkill); // send a signal to a thread allowed_syscalls.insert(__NR_wait4); // wait for process to change state, BSD style + allowed_syscalls.insert(__NR_rseq); // register restartable sequence for thread } void AllowScheduling() diff --git a/src/validation.cpp b/src/validation.cpp index 5b52638fc5..2813b62462 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2373,14 +2373,13 @@ bool CChainState::FlushStateToDisk( return AbortNode(state, "Failed to write to coin database"); nLastFlush = nNow; full_flush_completed = true; + TRACE5(utxocache, flush, + (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) + (u_int32_t)mode, + (u_int64_t)coins_count, + (u_int64_t)coins_mem_usage, + (bool)fFlushForPrune); } - TRACE6(utxocache, flush, - (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) - (u_int32_t)mode, - (u_int64_t)coins_count, - (u_int64_t)coins_mem_usage, - (bool)fFlushForPrune, - (bool)fDoFullFlush); } if (full_flush_completed) { // Update best block in wallet (so we can detect restored wallets). diff --git a/src/validation.h b/src/validation.h index 968f62aa9a..7766d77a88 100644 --- a/src/validation.h +++ b/src/validation.h @@ -90,7 +90,7 @@ static const int DEFAULT_STOPATHEIGHT = 0; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; static const signed int DEFAULT_CHECKBLOCKS = 6; -static const unsigned int DEFAULT_CHECKLEVEL = 3; +static constexpr int DEFAULT_CHECKLEVEL{3}; // Require that user allocate at least 550 MiB for block & undo files (blk???.dat and rev???.dat) // At 1MB per block, 288 blocks = 288MB. // Add 15% for Undo data = 331MB |