diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.test.include | 3 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 3 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 6 | ||||
-rw-r--r-- | src/qt/guiutil.h | 5 | ||||
-rw-r--r-- | src/test/fuzz/addrman.cpp | 147 | ||||
-rw-r--r-- | src/test/script_parse_tests.cpp | 55 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 12 | ||||
-rw-r--r-- | src/util/syscall_sandbox.cpp | 14 | ||||
-rw-r--r-- | src/validation.cpp | 9 | ||||
-rw-r--r-- | src/wallet/coincontrol.h | 2 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 6 | ||||
-rw-r--r-- | src/wallet/spend.cpp | 4 |
12 files changed, 174 insertions, 92 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index be63214c23..d70793ffa9 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -119,8 +119,9 @@ BITCOIN_TESTS =\ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/script_p2sh_tests.cpp \ - test/script_tests.cpp \ + test/script_parse_tests.cpp \ test/script_standard_tests.cpp \ + test/script_tests.cpp \ test/scriptnum_tests.cpp \ test/serfloat_tests.cpp \ test/serialize_tests.cpp \ diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 00c9fd3059..7de56a648a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -46,7 +46,6 @@ #include <QApplication> #include <QDebug> -#include <QFontDatabase> #include <QLatin1String> #include <QLibraryInfo> #include <QLocale> @@ -492,7 +491,7 @@ int GuiMain(int argc, char* argv[]) #endif BitcoinApplication app; - QFontDatabase::addApplicationFont(":/fonts/monospace"); + GUIUtil::LoadFont(QStringLiteral(":/fonts/monospace")); /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these // Command-line options take precedence: diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 7b1384b485..12d3a48d01 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -272,6 +272,12 @@ bool hasEntryData(const QAbstractItemView *view, int column, int role) return !selection.at(0).data(role).toString().isEmpty(); } +void LoadFont(const QString& file_name) +{ + const int id = QFontDatabase::addApplicationFont(file_name); + assert(id != -1); +} + QString getDefaultDataDirectory() { return boostPathToQString(GetDefaultDataDir()); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 6287f95192..211f3f506d 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -114,6 +114,11 @@ namespace GUIUtil void setClipboard(const QString& str); /** + * Loads the font from the file specified by file_name, aborts if it fails. + */ + void LoadFont(const QString& file_name); + + /** * Determine default data directory for operating system. */ QString getDefaultDataDirectory(); diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index cfeab9dcdc..8df3707fc9 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -7,6 +7,7 @@ #include <addrman_impl.h> #include <chainparams.h> #include <merkleblock.h> +#include <random.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -35,92 +36,86 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) } } -class AddrManDeterministic : public AddrMan +/** + * Generate a random address. Always returns a valid address. + */ +CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context) { -public: - FuzzedDataProvider& m_fuzzed_data_provider; - - explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider) - : AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0) - , m_fuzzed_data_provider(fuzzed_data_provider) - { - WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); - } - - /** - * Generate a random address. Always returns a valid address. - */ - CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs) - { - CNetAddr addr; - if (m_fuzzed_data_provider.remaining_bytes() > 1 && m_fuzzed_data_provider.ConsumeBool()) { - addr = ConsumeNetAddr(m_fuzzed_data_provider); - } else { - // The networks [1..6] correspond to CNetAddr::BIP155Network (private). - static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE}, - {2, ADDR_IPV6_SIZE}, - {4, ADDR_TORV3_SIZE}, - {5, ADDR_I2P_SIZE}, - {6, ADDR_CJDNS_SIZE}}; - uint8_t net = m_impl->insecure_rand.randrange(5) + 1; // [1..5] - if (net == 3) { - net = 6; - } - - CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); - - s << net; - s << m_impl->insecure_rand.randbytes(net_len_map.at(net)); - - s >> addr; - } - - // Return a dummy IPv4 5.5.5.5 if we generated an invalid address. - if (!addr.IsValid()) { - in_addr v4_addr = {}; - v4_addr.s_addr = 0x05050505; - addr = CNetAddr{v4_addr}; + CNetAddr addr; + if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) { + addr = ConsumeNetAddr(fuzzed_data_provider); + } else { + // The networks [1..6] correspond to CNetAddr::BIP155Network (private). + static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE}, + {2, ADDR_IPV6_SIZE}, + {4, ADDR_TORV3_SIZE}, + {5, ADDR_I2P_SIZE}, + {6, ADDR_CJDNS_SIZE}}; + uint8_t net = fast_random_context.randrange(5) + 1; // [1..5] + if (net == 3) { + net = 6; } - return addr; - } - - /** - * Fill this addrman with lots of addresses from lots of sources. - */ - void Fill() - { - LOCK(m_impl->cs); + CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); - // Add some of the addresses directly to the "tried" table. + s << net; + s << fast_random_context.randbytes(net_len_map.at(net)); - // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% - const size_t n = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); + s >> addr; + } - const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); - CNetAddr prev_source; - // Use insecure_rand inside the loops instead of m_fuzzed_data_provider because when - // the latter is exhausted it just returns 0. - for (size_t i = 0; i < num_sources; ++i) { - const auto source = RandAddr(); - const size_t num_addresses = m_impl->insecure_rand.randrange(500) + 1; // [1..500] + // Return a dummy IPv4 5.5.5.5 if we generated an invalid address. + if (!addr.IsValid()) { + in_addr v4_addr = {}; + v4_addr.s_addr = 0x05050505; + addr = CNetAddr{v4_addr}; + } - for (size_t j = 0; j < num_addresses; ++j) { - const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK}; - const auto time_penalty = m_impl->insecure_rand.randrange(100000001); - m_impl->Add_(addr, source, time_penalty); + return addr; +} - if (n > 0 && m_impl->mapInfo.size() % n == 0) { - m_impl->Good_(addr, false, GetTime()); - } +/** Fill addrman with lots of addresses from lots of sources. */ +void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider) +{ + // Add a fraction of the addresses to the "tried" table. + // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% + const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); + + const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); + CNetAddr prev_source; + // Generate a FastRandomContext seed to use inside the loops instead of + // fuzzed_data_provider. When fuzzed_data_provider is exhausted it + // just returns 0. + FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; + for (size_t i = 0; i < num_sources; ++i) { + const auto source = RandAddr(fuzzed_data_provider, fast_random_context); + const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500] + + for (size_t j = 0; j < num_addresses; ++j) { + const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK}; + const auto time_penalty = fast_random_context.randrange(100000001); + addrman.Add({addr}, source, time_penalty); + + if (n > 0 && addrman.size() % n == 0) { + addrman.Good(addr, GetTime()); + } - // Add 10% of the addresses from more than one source. - if (m_impl->insecure_rand.randrange(10) == 0 && prev_source.IsValid()) { - m_impl->Add_({addr}, prev_source, time_penalty); - } + // Add 10% of the addresses from more than one source. + if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) { + addrman.Add({addr}, prev_source, time_penalty); } - prev_source = source; } + prev_source = source; + } +} + +class AddrManDeterministic : public AddrMan +{ +public: + explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider) + : AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0) + { + WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); } /** @@ -307,7 +302,7 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman) CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); - addr_man1.Fill(); + FillAddrman(addr_man1, fuzzed_data_provider); data_stream << addr_man1; data_stream >> addr_man2; assert(addr_man1 == addr_man2); diff --git a/src/test/script_parse_tests.cpp b/src/test/script_parse_tests.cpp new file mode 100644 index 0000000000..5b8b6a725f --- /dev/null +++ b/src/test/script_parse_tests.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2021 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 <core_io.h> +#include <script/script.h> +#include <util/strencodings.h> +#include <test/util/setup_common.h> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_SUITE(script_parse_tests) +BOOST_AUTO_TEST_CASE(parse_script) +{ + const std::vector<std::pair<std::string,std::string>> IN_OUT{ + // {IN: script string , OUT: hex string } + {"", ""}, + {"0", "00"}, + {"1", "51"}, + {"2", "52"}, + {"3", "53"}, + {"4", "54"}, + {"5", "55"}, + {"6", "56"}, + {"7", "57"}, + {"8", "58"}, + {"9", "59"}, + {"10", "5a"}, + {"11", "5b"}, + {"12", "5c"}, + {"13", "5d"}, + {"14", "5e"}, + {"15", "5f"}, + {"16", "60"}, + {"17", "0111"}, + {"-9", "0189"}, + {"0x17", "17"}, + {"'17'", "023137"}, + {"ELSE", "67"}, + {"NOP10", "b9"}, + {"11111111111111111111", "00"}, + }; + std::string all_in; + std::string all_out; + for (const auto& [in, out] : IN_OUT) { + BOOST_CHECK_EQUAL(HexStr(ParseScript(in)), out); + all_in += " " + in + " "; + all_out += out; + } + BOOST_CHECK_EQUAL(HexStr(ParseScript(all_in)), all_out); + + BOOST_CHECK_EXCEPTION(ParseScript("11111111111"), std::runtime_error, HasReason("script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF")); + BOOST_CHECK_EXCEPTION(ParseScript("OP_CHECKSIGADD"), std::runtime_error, HasReason("script parse error: unknown opcode")); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 51707310a2..b5088d3c33 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1239,6 +1239,11 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney) BOOST_AUTO_TEST_CASE(util_ParseMoney) { BOOST_CHECK_EQUAL(ParseMoney("0.0").value(), 0); + BOOST_CHECK_EQUAL(ParseMoney(".").value(), 0); + BOOST_CHECK_EQUAL(ParseMoney("0.").value(), 0); + BOOST_CHECK_EQUAL(ParseMoney(".0").value(), 0); + BOOST_CHECK_EQUAL(ParseMoney(".6789").value(), 6789'0000); + BOOST_CHECK_EQUAL(ParseMoney("12345.").value(), COIN * 12345); BOOST_CHECK_EQUAL(ParseMoney("12345.6789").value(), (COIN/10000)*123456789); @@ -1276,11 +1281,18 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_CHECK(!ParseMoney(" ")); // Parsing two numbers should fail + BOOST_CHECK(!ParseMoney("..")); + BOOST_CHECK(!ParseMoney("0..0")); BOOST_CHECK(!ParseMoney("1 2")); BOOST_CHECK(!ParseMoney(" 1 2 ")); BOOST_CHECK(!ParseMoney(" 1.2 3 ")); BOOST_CHECK(!ParseMoney(" 1 2.3 ")); + // Embedded whitespace should fail + BOOST_CHECK(!ParseMoney(" -1 .2 ")); + BOOST_CHECK(!ParseMoney(" 1 .2 ")); + BOOST_CHECK(!ParseMoney(" +1 .2 ")); + // Attempted 63 bit overflow should fail BOOST_CHECK(!ParseMoney("92233720368.54775808")); diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp index 746feb0835..7e76ecbf3a 100644 --- a/src/util/syscall_sandbox.cpp +++ b/src/util/syscall_sandbox.cpp @@ -58,6 +58,10 @@ bool g_syscall_sandbox_log_violation_before_terminating{false}; #define __NR_membarrier 324 #endif +#ifndef __NR_copy_file_range +#define __NR_copy_file_range 326 +#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. @@ -268,15 +272,23 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{ {__NR_pipe, "pipe"}, {__NR_pipe2, "pipe2"}, {__NR_pivot_root, "pivot_root"}, +#ifdef __NR_pkey_alloc {__NR_pkey_alloc, "pkey_alloc"}, +#endif +#ifdef __NR_pkey_free {__NR_pkey_free, "pkey_free"}, +#endif +#ifdef __NR_pkey_mprotect {__NR_pkey_mprotect, "pkey_mprotect"}, +#endif {__NR_poll, "poll"}, {__NR_ppoll, "ppoll"}, {__NR_prctl, "prctl"}, {__NR_pread64, "pread64"}, {__NR_preadv, "preadv"}, +#ifdef __NR_preadv2 {__NR_preadv2, "preadv2"}, +#endif {__NR_prlimit64, "prlimit64"}, {__NR_process_vm_readv, "process_vm_readv"}, {__NR_process_vm_writev, "process_vm_writev"}, @@ -285,7 +297,9 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{ {__NR_putpmsg, "putpmsg"}, {__NR_pwrite64, "pwrite64"}, {__NR_pwritev, "pwritev"}, +#ifdef __NR_pwritev2 {__NR_pwritev2, "pwritev2"}, +#endif {__NR_query_module, "query_module"}, {__NR_quotactl, "quotactl"}, {__NR_read, "read"}, diff --git a/src/validation.cpp b/src/validation.cpp index 880a01eb7d..14dcd2c24b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -474,7 +474,6 @@ private: std::unique_ptr<CTxMemPoolEntry> m_entry; std::list<CTransactionRef> m_replaced_transactions; - bool m_replacement_transaction; CAmount m_base_fees; CAmount m_modified_fees; /** Total modified fees of all transactions being replaced. */ @@ -556,7 +555,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting; CTxMemPool::setEntries& setAncestors = ws.m_ancestors; std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry; - bool& fReplacementTransaction = ws.m_replacement_transaction; CAmount& nModifiedFees = ws.m_modified_fees; CAmount& nConflictingFees = ws.m_conflicting_fees; size_t& nConflictingSize = ws.m_conflicting_size; @@ -779,8 +777,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) } - fReplacementTransaction = setConflicts.size(); - if (fReplacementTransaction) { + if (!setConflicts.empty()) { CFeeRate newFeeRate(nModifiedFees, nSize); // It's possible that the replacement pays more fees than its direct conflicts but not more // than all conflicts (i.e. the direct conflicts have high-fee descendants). However, if the @@ -885,7 +882,6 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) const CAmount& nModifiedFees = ws.m_modified_fees; const CAmount& nConflictingFees = ws.m_conflicting_fees; const size_t& nConflictingSize = ws.m_conflicting_size; - const bool fReplacementTransaction = ws.m_replacement_transaction; std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry; // Remove conflicting transactions from the mempool @@ -901,11 +897,10 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED); // This transaction should only count for fee estimation if: - // - it isn't a BIP 125 replacement transaction (may not be widely supported) // - it's not being re-added during a reorg which bypasses typical mempool fee limits // - the node is not behind // - the transaction is not dependent on any other transactions in the mempool - bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx); + bool validForFeeEstimation = !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx); // Store transaction in memory m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation); diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index c989512d3e..edd81e590f 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -93,7 +93,7 @@ public: setSelected.insert(output); } - void Select(const COutPoint& outpoint, const CTxOut& txout) + void SelectExternal(const COutPoint& outpoint, const CTxOut& txout) { setSelected.insert(outpoint); m_external_txouts.emplace(outpoint, txout); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8ca8f87bca..8b481bc29c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3320,7 +3320,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, } if (options.exists("solving_data")) { - UniValue solving_data = options["solving_data"].get_obj(); + const UniValue solving_data = options["solving_data"].get_obj(); if (solving_data.exists("pubkeys")) { for (const UniValue& pk_univ : solving_data["pubkeys"].get_array().getValues()) { const std::string& pk_str = pk_univ.get_str(); @@ -3328,7 +3328,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", pk_str)); } const std::vector<unsigned char> data(ParseHex(pk_str)); - CPubKey pubkey(data.begin(), data.end()); + const CPubKey pubkey(data.begin(), data.end()); if (!pubkey.IsFullyValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not a valid public key", pk_str)); } @@ -3393,7 +3393,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, wallet.chain().findCoins(coins); for (const auto& coin : coins) { if (!coin.second.out.IsNull()) { - coinControl.Select(coin.first, coin.second.out); + coinControl.SelectExternal(coin.first, coin.second.out); } } diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 5bed09e067..5470177440 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -475,7 +475,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo CInputCoin coin(outpoint, txout, input_bytes); nValueFromPresetInputs += coin.txout.nValue; - if (coin.m_input_bytes <= 0) { + if (coin.m_input_bytes == -1) { return false; // Not solvable, can't estimate size for fee } coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes); @@ -814,7 +814,7 @@ static bool CreateTransactionInternal( // Calculate the transaction fee TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control); int nBytes = tx_sizes.vsize; - if (nBytes < 0) { + if (nBytes == -1) { error = _("Missing solving data for estimating transaction size"); return false; } |