diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 1576537a0..cf3ea4087 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -1,168 +1,167 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include namespace { /** * Fill the edit address dialog box with data, submit it, and ensure that * the resulting message meets expectations. */ void EditAddressAndSubmit(EditAddressDialog *dialog, const QString &label, const QString &address, QString expected_msg) { QString warning_text; dialog->findChild("labelEdit")->setText(label); dialog->findChild("addressEdit")->setText(address); ConfirmMessage(&warning_text, 5); dialog->accept(); QCOMPARE(warning_text, expected_msg); } /** * Test adding various send addresses to the address book. * * There are three cases tested: * * - new_address: a new address which should add as a send address * successfully. * - existing_s_address: an existing sending address which won't add * successfully. * - existing_r_address: an existing receiving address which won't add * successfully. * * In each case, verify the resulting state of the address book and optionally * the warning message presented to the user. */ void TestAddAddressesToSendBook() { TestChain100Setup test; auto chain = interfaces::MakeChain(); std::shared_ptr wallet = std::make_shared( Params(), *chain, WalletLocation(), WalletDatabase::CreateMock()); bool firstRun; wallet->LoadWallet(firstRun); auto build_address = [&wallet]() { CKey key; key.MakeNewKey(true); CTxDestination dest(GetDestinationForKey( key.GetPubKey(), wallet->m_default_address_type)); return std::make_pair( dest, QString::fromStdString(EncodeCashAddr(dest, Params()))); }; CTxDestination r_key_dest, s_key_dest; // Add a preexisting "receive" entry in the address book. QString preexisting_r_address; QString r_label("already here (r)"); // Add a preexisting "send" entry in the address book. QString preexisting_s_address; QString s_label("already here (s)"); // Define a new address (which should add to the address book successfully). QString new_address; std::tie(r_key_dest, preexisting_r_address) = build_address(); std::tie(s_key_dest, preexisting_s_address) = build_address(); std::tie(std::ignore, new_address) = build_address(); { LOCK(wallet->cs_wallet); wallet->SetAddressBook(r_key_dest, r_label.toStdString(), "receive"); wallet->SetAddressBook(s_key_dest, s_label.toStdString(), "send"); } auto check_addbook_size = [&wallet](int expected_size) { QCOMPARE(static_cast(wallet->mapAddressBook.size()), expected_size); }; // We should start with the two addresses we added earlier and nothing else. check_addbook_size(2); // Initialize relevant QT models. std::unique_ptr platformStyle( PlatformStyle::instantiate("other")); auto node = interfaces::MakeNode(); OptionsModel optionsModel(*node); AddWallet(wallet); WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel); RemoveWallet(wallet); EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress); editAddressDialog.setModel(walletModel.getAddressTableModel()); EditAddressAndSubmit( &editAddressDialog, QString("uhoh"), preexisting_r_address, QString( "Address \"%1\" already exists as a receiving address with label " "\"%2\" and so cannot be added as a sending address.") .arg(preexisting_r_address) .arg(r_label)); check_addbook_size(2); EditAddressAndSubmit( &editAddressDialog, QString("uhoh, different"), preexisting_s_address, QString( "The entered address \"%1\" is already in the address book with " "label \"%2\".") .arg(preexisting_s_address) .arg(s_label)); check_addbook_size(2); // Submit a new address which should add successfully - we expect the // warning message to be blank. EditAddressAndSubmit(&editAddressDialog, QString("new"), new_address, QString("")); check_addbook_size(3); } } // namespace void AddressBookTests::addressBookTests() { #ifdef Q_OS_MAC if (QApplication::platformName() == "minimal") { // Disable for mac on "minimal" platform to avoid crashes inside the Qt // framework when it tries to look up unimplemented cocoa functions, // and fails to handle returned nulls // (https://bugreports.qt.io/browse/QTBUG-49686). QWARN( "Skipping AddressBookTests on mac build with 'minimal' platform " "set due to Qt bugs. To run AppTests, invoke with 'test_bitcoin-qt " "-platform cocoa' on mac, or else use a linux or windows build."); return; } #endif TestAddAddressesToSendBook(); } diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index dc41bc09e..f645b366f 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -1,150 +1,149 @@ // Copyright (c) 2018 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 #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_CONFIG_H) #include #endif #ifdef ENABLE_WALLET #include #endif #include #include #include #include #include #include #include #include /* * FIXME: requires QT_WIDGETS_LIB to be defined prior * inclusion to export the QtTest::keyClicks symbol. * On some older Qt versions the definition end up being set by the inclusion of * . * This only occurs when building with autotools, as QMake and CMake define * QT_WIDGETS_LIB on the command line. As a workaround for autotools, * should be included before . * Also prevent the linter from sorting the includes. */ // clang-format off #include #include // clang-format on #include -#include #include namespace { //! Call getblockchaininfo RPC and check first field of JSON output. void TestRpcCommand(RPCConsole *console) { QEventLoop loop; QTextEdit *messagesWidget = console->findChild("messagesWidget"); QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit); QLineEdit *lineEdit = console->findChild("lineEdit"); QTest::keyClicks(lineEdit, "getblockchaininfo"); QTest::keyClick(lineEdit, Qt::Key_Return); loop.exec(); QString output = messagesWidget->toPlainText(); UniValue value; value.read( output .right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1) .toStdString()); QCOMPARE(value["chain"].get_str(), std::string("regtest")); } } // namespace //! Entry point for BitcoinApplication tests. void AppTests::appTests() { #ifdef Q_OS_MAC if (QApplication::platformName() == "minimal") { // Disable for mac on "minimal" platform to avoid crashes inside the Qt // framework when it tries to look up unimplemented cocoa functions, // and fails to handle returned nulls // (https://bugreports.qt.io/browse/QTBUG-49686). QWARN("Skipping AppTests on mac build with 'minimal' platform set due " "to Qt bugs. To run AppTests, invoke " "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a " "linux or windows build."); return; } #endif Config &config = const_cast(GetConfig()); // Create a temp data directory to backup the gui settings to BasicTestingSetup test{CBaseChainParams::REGTEST}; // Already started by the common test setup, so stop it to avoid // interference ECC_Stop(); LogInstance().DisconnectTestLogger(); m_app.parameterSetup(); m_app.createOptionsModel(true /* reset settings */); QScopedPointer style(NetworkStyle::instantiate( QString::fromStdString(Params().NetworkIDString()))); m_app.setupPlatformStyle(); m_app.createWindow(&config, style.data()); connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests); expectCallback("guiTests"); m_app.baseInitialize(config); RPCServer rpcServer; HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer); m_app.requestInitialize(config, rpcServer, httpRPCRequestProcessor); m_app.exec(); m_app.requestShutdown(config); m_app.exec(); // Reset global state to avoid interfering with later tests. AbortShutdown(); UnloadBlockIndex(); } //! Entry point for BitcoinGUI tests. void AppTests::guiTests(BitcoinGUI *window) { HandleCallback callback{"guiTests", *this}; connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests); expectCallback("consoleTests"); QAction *action = window->findChild("openRPCConsoleAction"); action->activate(QAction::Trigger); } //! Entry point for RPCConsole tests. void AppTests::consoleTests(RPCConsole *console) { HandleCallback callback{"consoleTests", *this}; TestRpcCommand(console); } //! Destructor to shut down after the last expected callback completes. AppTests::HandleCallback::~HandleCallback() { auto &callbacks = m_app_tests.m_callbacks; auto it = callbacks.find(m_callback); assert(it != callbacks.end()); callbacks.erase(it); if (callbacks.empty()) { m_app_tests.m_app.quit(); } } diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index e85eab5f4..280584205 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -1,197 +1,196 @@ // Copyright (c) 2016 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 #include #include #include -#include #include #include #include #include #include #include #include #include #include #include static UniValue rpcNestedTest_rpc(const Config &config, const JSONRPCRequest &request) { if (request.fHelp) { return "help message"; } return request.params.write(0, 0); } static const ContextFreeRPCCommand vRPCCommands[] = { {"test", "rpcNestedTest", &rpcNestedTest_rpc, {}}, }; void RPCNestedTests::rpcNestedTests() { // do some test setup // could be moved to a more generic place when we add more tests on QT level tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); // mempool.setSanityCheck(1.0); TestingSetup test; std::string result; std::string result2; std::string filtered; auto node = interfaces::MakeNode(); // Simple result filtering with path. RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[chain]", &filtered); QVERIFY(result == "main"); QVERIFY(filtered == "getblockchaininfo()[chain]"); // Simple 2 level nesting. RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())"); RPCConsole::RPCExecuteCommandLine( *node, result, "getblock(getblock(getbestblockhash())[hash], true)"); // 4 level nesting with whitespace, filtering path and boolean parameter. RPCConsole::RPCExecuteCommandLine( *node, result, "getblock( getblock( getblock(getbestblockhash())[hash] " ")[hash], true)"); RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo"); QVERIFY(result.substr(0, 1) == "{"); RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()"); QVERIFY(result.substr(0, 1) == "{"); // Whitespace at the end will be tolerated. RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo "); QVERIFY(result.substr(0, 1) == "{"); // Quote path identifier are allowed, but look after a child containing the // quotes in the key. (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[\"chain\"]")); QVERIFY(result == "null"); // parameter not in brackets are allowed. (RPCConsole::RPCExecuteCommandLine(*node, result, "createrawtransaction [] {} 0")); // Parameter in brackets are allowed. (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction([],{},0)")); QVERIFY(result == result2); // Whitespace between parameters is allowed. (RPCConsole::RPCExecuteCommandLine( *node, result2, "createrawtransaction( [], {} , 0 )")); QVERIFY(result == result2); RPCConsole::RPCExecuteCommandLine( *node, result, "getblock(getbestblockhash())[tx][0]", &filtered); QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]"); RPCConsole::RPCParseCommandLine(nullptr, result, "importprivkey", false, &filtered); QVERIFY(filtered == "importprivkey(…)"); RPCConsole::RPCParseCommandLine( nullptr, result, "signmessagewithprivkey abc", false, &filtered); QVERIFY(filtered == "signmessagewithprivkey(…)"); RPCConsole::RPCParseCommandLine( nullptr, result, "signmessagewithprivkey abc,def", false, &filtered); QVERIFY(filtered == "signmessagewithprivkey(…)"); RPCConsole::RPCParseCommandLine( nullptr, result, "signrawtransactionwithkey(abc)", false, &filtered); QVERIFY(filtered == "signrawtransactionwithkey(…)"); RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrase(help())", false, &filtered); QVERIFY(filtered == "walletpassphrase(…)"); RPCConsole::RPCParseCommandLine( nullptr, result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered); QVERIFY(filtered == "walletpassphrasechange(…)"); RPCConsole::RPCParseCommandLine( nullptr, result, "help(encryptwallet(abc, def))", false, &filtered); QVERIFY(filtered == "help(encryptwallet(…))"); RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey())", false, &filtered); QVERIFY(filtered == "help(importprivkey(…))"); RPCConsole::RPCParseCommandLine( nullptr, result, "help(importprivkey(help()))", false, &filtered); QVERIFY(filtered == "help(importprivkey(…))"); RPCConsole::RPCParseCommandLine( nullptr, result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered); QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest"); QVERIFY(result == "[]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest ''"); QVERIFY(result == "[\"\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest \"\""); QVERIFY(result == "[\"\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest '' abc"); QVERIFY(result == "[\"\",\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc '' abc"); QVERIFY(result == "[\"abc\",\"\",\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc abc"); QVERIFY(result == "[\"abc\",\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc\t\tabc"); QVERIFY(result == "[\"abc\",\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc )"); QVERIFY(result == "[\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc )"); QVERIFY(result == "[\"abc\"]"); RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc , cba )"); QVERIFY(result == "[\"abc\",\"cba\"]"); // invalid syntax QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "getblockchaininfo() .\n"), std::runtime_error); // invalid syntax QVERIFY_EXCEPTION_THROWN( RPCConsole::RPCExecuteCommandLine( *node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); // tolerate non closing brackets if we have no arguments. (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(")); // tolerate non command brackts (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()()()")); // invalid argument QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "getblockchaininfo(True)"), UniValue); // method not found QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "a(getblockchaininfo(True))"), UniValue); // don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "rpcNestedTest abc,,abc"), std::runtime_error); // don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); // don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine( *node, result, "rpcNestedTest(abc,,)"), std::runtime_error); } diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h index a7496ef90..b0ba3044e 100644 --- a/src/qt/test/rpcnestedtests.h +++ b/src/qt/test/rpcnestedtests.h @@ -1,21 +1,18 @@ // Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_QT_TEST_RPCNESTEDTESTS_H #define BITCOIN_QT_TEST_RPCNESTEDTESTS_H -#include -#include - #include #include class RPCNestedTests : public QObject { Q_OBJECT private Q_SLOTS: void rpcNestedTests(); }; #endif // BITCOIN_QT_TEST_RPCNESTEDTESTS_H diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 464cea4b9..6fbf91794 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,125 +1,124 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) #include #endif -#include #include #include #include #include #include #include #include #include #include #include #ifdef ENABLE_WALLET #include #ifdef ENABLE_BIP70 #include #endif // ENABLE_BIP70 #include #endif // ENABLE_WALLET #include #include #include #include #ifdef ENABLE_BIP70 #include #endif #if defined(QT_STATICPLUGIN) #include #if defined(QT_QPA_PLATFORM_MINIMAL) Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); #endif #if defined(QT_QPA_PLATFORM_XCB) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_WINDOWS) Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif #endif // This is all you need to run all the tests int main(int argc, char *argv[]) { // Initialize persistent globals with the testing setup state for sanity. // E.g. -datadir in gArgs is set to a temp directory dummy value (instead // of defaulting to the default datadir), or globalChainParams is set to // regtest params. // // All tests must use their own testing setup (if needed). { BasicTestingSetup dummy{CBaseChainParams::REGTEST}; } auto node = interfaces::MakeNode(); 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. setenv("QT_QPA_PLATFORM", "minimal", 0); // Don't remove this, it's needed to access // QApplication:: and QCoreApplication:: in the tests BitcoinApplication app(*node, argc, argv); app.setApplicationName("BitcoinABC-Qt-test"); #ifdef ENABLE_BIP70 // This is necessary to initialize openssl on the test framework // (at least on Darwin). SSL_library_init(); #endif AppTests app_tests(app); if (QTest::qExec(&app_tests) != 0) { fInvalid = true; } URITests test1; if (QTest::qExec(&test1) != 0) { fInvalid = true; } #if defined(ENABLE_WALLET) && defined(ENABLE_BIP70) PaymentServerTests test2; if (QTest::qExec(&test2) != 0) { fInvalid = true; } #endif RPCNestedTests test3; if (QTest::qExec(&test3) != 0) { fInvalid = true; } CompatTests test4; if (QTest::qExec(&test4) != 0) { fInvalid = true; } GUIUtilTests test5; if (QTest::qExec(&test5) != 0) { fInvalid = true; } BitcoinAddressValidatorTests test6; if (QTest::qExec(&test6) != 0) { fInvalid = true; } #ifdef ENABLE_WALLET WalletTests test7; if (QTest::qExec(&test7) != 0) { fInvalid = true; } AddressBookTests test8; if (QTest::qExec(&test8) != 0) { fInvalid = true; } #endif return fInvalid; } diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 6d2eacdf3..3837da182 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -1,244 +1,243 @@ // Copyright (c) 2012-2019 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 #include #include #include #include BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(arena_tests) { // Fake memory base address for testing // without actually using memory. void *synth_base = reinterpret_cast(0x08000000); const size_t synth_size = 1024 * 1024; Arena b(synth_base, synth_size, 16); void *chunk = b.alloc(1000); #ifdef ARENA_DEBUG b.walk(); #endif BOOST_CHECK(chunk != nullptr); // Aligned to 16 BOOST_CHECK(b.stats().used == 1008); // Nothing has disappeared? BOOST_CHECK(b.stats().total == synth_size); b.free(chunk); #ifdef ARENA_DEBUG b.walk(); #endif BOOST_CHECK(b.stats().used == 0); BOOST_CHECK(b.stats().free == synth_size); try { // Test exception on double-free b.free(chunk); BOOST_CHECK(0); } catch (std::runtime_error &) { } void *a0 = b.alloc(128); void *a1 = b.alloc(256); void *a2 = b.alloc(512); BOOST_CHECK(b.stats().used == 896); BOOST_CHECK(b.stats().total == synth_size); #ifdef ARENA_DEBUG b.walk(); #endif b.free(a0); #ifdef ARENA_DEBUG b.walk(); #endif BOOST_CHECK(b.stats().used == 768); b.free(a1); BOOST_CHECK(b.stats().used == 512); void *a3 = b.alloc(128); #ifdef ARENA_DEBUG b.walk(); #endif BOOST_CHECK(b.stats().used == 640); b.free(a2); BOOST_CHECK(b.stats().used == 128); b.free(a3); BOOST_CHECK(b.stats().used == 0); BOOST_CHECK_EQUAL(b.stats().chunks_used, 0U); BOOST_CHECK(b.stats().total == synth_size); BOOST_CHECK(b.stats().free == synth_size); BOOST_CHECK_EQUAL(b.stats().chunks_free, 1U); std::vector addr; // allocating 0 always returns nullptr BOOST_CHECK(b.alloc(0) == nullptr); #ifdef ARENA_DEBUG b.walk(); #endif // Sweeping allocate all memory for (int x = 0; x < 1024; ++x) { addr.push_back(b.alloc(1024)); } BOOST_CHECK(b.stats().free == 0); // memory is full, this must return nullptr BOOST_CHECK(b.alloc(1024) == nullptr); BOOST_CHECK(b.alloc(0) == nullptr); for (int x = 0; x < 1024; ++x) { b.free(addr[x]); } addr.clear(); BOOST_CHECK(b.stats().total == synth_size); BOOST_CHECK(b.stats().free == synth_size); // Now in the other direction... for (int x = 0; x < 1024; ++x) { addr.push_back(b.alloc(1024)); } for (int x = 0; x < 1024; ++x) { b.free(addr[1023 - x]); } addr.clear(); // Now allocate in smaller unequal chunks, then deallocate haphazardly // Not all the chunks will succeed allocating, but freeing nullptr is // allowed so that is no problem. for (int x = 0; x < 2048; ++x) { addr.push_back(b.alloc(x + 1)); } for (int x = 0; x < 2048; ++x) { b.free(addr[((x * 23) % 2048) ^ 242]); } addr.clear(); // Go entirely wild: free and alloc interleaved, generate targets and sizes // using pseudo-randomness. for (int x = 0; x < 2048; ++x) { addr.push_back(nullptr); } uint32_t s = 0x12345678; for (int x = 0; x < 5000; ++x) { int idx = s & (addr.size() - 1); if (s & 0x80000000) { b.free(addr[idx]); addr[idx] = nullptr; } else if (!addr[idx]) { addr[idx] = b.alloc((s >> 16) & 2047); } bool lsb = s & 1; s >>= 1; // LFSR period 0xf7ffffe0 if (lsb) { s ^= 0xf00f00f0; } } for (void *ptr : addr) { b.free(ptr); } addr.clear(); BOOST_CHECK(b.stats().total == synth_size); BOOST_CHECK(b.stats().free == synth_size); } /** Mock LockedPageAllocator for testing */ class TestLockedPageAllocator : public LockedPageAllocator { public: TestLockedPageAllocator(int count_in, int lockedcount_in) : count(count_in), lockedcount(lockedcount_in) {} void *AllocateLocked(size_t len, bool *lockingSuccess) override { *lockingSuccess = false; if (count > 0) { --count; if (lockedcount > 0) { --lockedcount; *lockingSuccess = true; } // Fake address, do not actually use this memory return reinterpret_cast(0x08000000 + (count << 24)); } return nullptr; } void FreeLocked(void *addr, size_t len) override {} size_t GetLimit() override { return std::numeric_limits::max(); } private: int count; int lockedcount; }; BOOST_AUTO_TEST_CASE(lockedpool_tests_mock) { // Test over three virtual arenas, of which one will succeed being locked auto x = std::make_unique(3, 1); LockedPool pool(std::move(x)); BOOST_CHECK(pool.stats().total == 0); BOOST_CHECK(pool.stats().locked == 0); // Ensure unreasonable requests are refused without allocating anything void *invalid_toosmall = pool.alloc(0); BOOST_CHECK(invalid_toosmall == nullptr); BOOST_CHECK(pool.stats().used == 0); BOOST_CHECK(pool.stats().free == 0); void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE + 1); BOOST_CHECK(invalid_toobig == nullptr); BOOST_CHECK(pool.stats().used == 0); BOOST_CHECK(pool.stats().free == 0); void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a0); BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE); void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a1); void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a2); void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a3); void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a4); void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2); BOOST_CHECK(a5); // We've passed a count of three arenas, so this allocation should fail void *a6 = pool.alloc(16); BOOST_CHECK(!a6); pool.free(a0); pool.free(a2); pool.free(a4); pool.free(a1); pool.free(a3); pool.free(a5); BOOST_CHECK(pool.stats().total == 3 * LockedPool::ARENA_SIZE); BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE); BOOST_CHECK(pool.stats().used == 0); } // These tests used the live LockedPoolManager object, this is also used by // other tests so the conditions are somewhat less controllable and thus the // tests are somewhat more error-prone. BOOST_AUTO_TEST_CASE(lockedpool_tests_live) { LockedPoolManager &pool = LockedPoolManager::Instance(); LockedPool::Stats initial = pool.stats(); void *a0 = pool.alloc(16); BOOST_CHECK(a0); // Test reading and writing the allocated memory *((uint32_t *)a0) = 0x1234; BOOST_CHECK(*((uint32_t *)a0) == 0x1234); pool.free(a0); try { // Test exception on double-free pool.free(a0); BOOST_CHECK(0); } catch (std::runtime_error &) { } // If more than one new arena was allocated for the above tests, something // is wrong BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE)); // Usage must be back to where it started BOOST_CHECK(pool.stats().used == initial.used); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 456d59db6..7d54f87d1 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -1,670 +1,669 @@ // Copyright (c) 2011-2019 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 #include -#include #include #include #include #include #include #include #include #include BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) /// Convert vector to arith_uint256, via uint256 blob static inline arith_uint256 arith_uint256V(const std::vector &vch) { return UintToArith256(uint256(vch)); } const uint8_t R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; // R1L equals roughly R1Ldouble * 2^256 const double R1Ldouble = 0.4887374590559308955; const arith_uint256 R1L = arith_uint256V(std::vector(R1Array, R1Array + 32)); const uint64_t R1LLow64 = 0x121156cfdb4a529cULL; const uint8_t R2Array[] = "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; const arith_uint256 R2L = arith_uint256V(std::vector(R2Array, R2Array + 32)); const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; const uint8_t ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const arith_uint256 ZeroL = arith_uint256V(std::vector(ZeroArray, ZeroArray + 32)); const uint8_t OneArray[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const arith_uint256 OneL = arith_uint256V(std::vector(OneArray, OneArray + 32)); const uint8_t MaxArray[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; const arith_uint256 MaxL = arith_uint256V(std::vector(MaxArray, MaxArray + 32)); const arith_uint256 HalfL = (OneL << 255); static std::string ArrayToString(const uint8_t A[], unsigned int width) { std::stringstream Stream; Stream << std::hex; for (unsigned int i = 0; i < width; ++i) { Stream << std::setw(2) << std::setfill('0') << (unsigned int)A[width - i - 1]; } return Stream.str(); } // constructors, equality, inequality BOOST_AUTO_TEST_CASE(basics) { BOOST_CHECK(1 == 0 + 1); // constructor arith_uint256(vector): BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array, 32)); BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array, 32)); BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray, 32)); BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray, 32)); BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray, 32)); BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray, 32)); // == and != BOOST_CHECK(R1L != R2L); BOOST_CHECK(ZeroL != OneL); BOOST_CHECK(OneL != ZeroL); BOOST_CHECK(MaxL != ZeroL); BOOST_CHECK(~MaxL == ZeroL); BOOST_CHECK(((R1L ^ R2L) ^ R1L) == R2L); uint64_t Tmp64 = 0xc4dab720d9c7acaaULL; for (unsigned int i = 0; i < 256; ++i) { BOOST_CHECK(ZeroL != (OneL << i)); BOOST_CHECK((OneL << i) != ZeroL); BOOST_CHECK(R1L != (R1L ^ (OneL << i))); BOOST_CHECK(((arith_uint256(Tmp64) ^ (OneL << i)) != Tmp64)); } BOOST_CHECK(ZeroL == (OneL << 256)); // String Constructor and Copy Constructor BOOST_CHECK(arith_uint256("0x" + R1L.ToString()) == R1L); BOOST_CHECK(arith_uint256("0x" + R2L.ToString()) == R2L); BOOST_CHECK(arith_uint256("0x" + ZeroL.ToString()) == ZeroL); BOOST_CHECK(arith_uint256("0x" + OneL.ToString()) == OneL); BOOST_CHECK(arith_uint256("0x" + MaxL.ToString()) == MaxL); BOOST_CHECK(arith_uint256(R1L.ToString()) == R1L); BOOST_CHECK(arith_uint256(" 0x" + R1L.ToString() + " ") == R1L); BOOST_CHECK(arith_uint256("") == ZeroL); BOOST_CHECK(R1L == arith_uint256(R1ArrayHex)); BOOST_CHECK(arith_uint256(R1L) == R1L); BOOST_CHECK((arith_uint256(R1L ^ R2L) ^ R2L) == R1L); BOOST_CHECK(arith_uint256(ZeroL) == ZeroL); BOOST_CHECK(arith_uint256(OneL) == OneL); // uint64_t constructor BOOST_CHECK((R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64)); BOOST_CHECK(ZeroL == arith_uint256(0)); BOOST_CHECK(OneL == arith_uint256(1)); BOOST_CHECK(arith_uint256("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL)); // Assignment (from base_uint) arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL); tmpL = ~OneL; BOOST_CHECK(tmpL == ~OneL); tmpL = ~R1L; BOOST_CHECK(tmpL == ~R1L); tmpL = ~R2L; BOOST_CHECK(tmpL == ~R2L); tmpL = ~MaxL; BOOST_CHECK(tmpL == ~MaxL); } static void shiftArrayRight(uint8_t *to, const uint8_t *from, unsigned int arrayLength, unsigned int bitsToShift) { for (unsigned int T = 0; T < arrayLength; ++T) { unsigned int F = (T + bitsToShift / 8); if (F < arrayLength) { to[T] = from[F] >> (bitsToShift % 8); } else { to[T] = 0; } if (F + 1 < arrayLength) { to[T] |= from[(F + 1)] << (8 - bitsToShift % 8); } } } static void shiftArrayLeft(uint8_t *to, const uint8_t *from, unsigned int arrayLength, unsigned int bitsToShift) { for (unsigned int T = 0; T < arrayLength; ++T) { if (T >= bitsToShift / 8) { unsigned int F = T - bitsToShift / 8; to[T] = from[F] << (bitsToShift % 8); if (T >= bitsToShift / 8 + 1) { to[T] |= from[F - 1] >> (8 - bitsToShift % 8); } } else { to[T] = 0; } } } // "<<" ">>" "<<=" ">>=" BOOST_AUTO_TEST_CASE(shifts) { uint8_t TmpArray[32]; arith_uint256 TmpL; for (unsigned int i = 0; i < 256; ++i) { shiftArrayLeft(TmpArray, OneArray, 32, i); BOOST_CHECK(arith_uint256V(std::vector( TmpArray, TmpArray + 32)) == (OneL << i)); TmpL = OneL; TmpL <<= i; BOOST_CHECK(TmpL == (OneL << i)); BOOST_CHECK((HalfL >> (255 - i)) == (OneL << i)); TmpL = HalfL; TmpL >>= (255 - i); BOOST_CHECK(TmpL == (OneL << i)); shiftArrayLeft(TmpArray, R1Array, 32, i); BOOST_CHECK(arith_uint256V(std::vector( TmpArray, TmpArray + 32)) == (R1L << i)); TmpL = R1L; TmpL <<= i; BOOST_CHECK(TmpL == (R1L << i)); shiftArrayRight(TmpArray, R1Array, 32, i); BOOST_CHECK(arith_uint256V(std::vector( TmpArray, TmpArray + 32)) == (R1L >> i)); TmpL = R1L; TmpL >>= i; BOOST_CHECK(TmpL == (R1L >> i)); shiftArrayLeft(TmpArray, MaxArray, 32, i); BOOST_CHECK(arith_uint256V(std::vector( TmpArray, TmpArray + 32)) == (MaxL << i)); TmpL = MaxL; TmpL <<= i; BOOST_CHECK(TmpL == (MaxL << i)); shiftArrayRight(TmpArray, MaxArray, 32, i); BOOST_CHECK(arith_uint256V(std::vector( TmpArray, TmpArray + 32)) == (MaxL >> i)); TmpL = MaxL; TmpL >>= i; BOOST_CHECK(TmpL == (MaxL >> i)); } arith_uint256 c1L = arith_uint256(0x0123456789abcdefULL); arith_uint256 c2L = c1L << 128; for (unsigned int i = 0; i < 128; ++i) { BOOST_CHECK((c1L << i) == (c2L >> (128 - i))); } for (unsigned int i = 128; i < 256; ++i) { BOOST_CHECK((c1L << i) == (c2L << (i - 128))); } } // ! ~ - BOOST_AUTO_TEST_CASE(unaryOperators) { BOOST_CHECK(~ZeroL == MaxL); uint8_t TmpArray[32]; for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = ~R1Array[i]; } BOOST_CHECK(arith_uint256V(std::vector(TmpArray, TmpArray + 32)) == (~R1L)); BOOST_CHECK(-ZeroL == ZeroL); BOOST_CHECK(-R1L == (~R1L) + 1); for (unsigned int i = 0; i < 256; ++i) { BOOST_CHECK(-(OneL << i) == (MaxL << i)); } } // Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each // element of Aarray and Barray, and then converting the result into an // arith_uint256. #define CHECKBITWISEOPERATOR(_A_, _B_, _OP_) \ for (unsigned int i = 0; i < 32; ++i) { \ TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; \ } \ BOOST_CHECK(arith_uint256V(std::vector( \ TmpArray, TmpArray + 32)) == (_A_##L _OP_ _B_##L)); #define CHECKASSIGNMENTOPERATOR(_A_, _B_, _OP_) \ TmpL = _A_##L; \ TmpL _OP_## = _B_##L; \ BOOST_CHECK(TmpL == (_A_##L _OP_ _B_##L)); BOOST_AUTO_TEST_CASE(bitwiseOperators) { uint8_t TmpArray[32]; CHECKBITWISEOPERATOR(R1, R2, |) CHECKBITWISEOPERATOR(R1, R2, ^) CHECKBITWISEOPERATOR(R1, R2, &) CHECKBITWISEOPERATOR(R1, Zero, |) CHECKBITWISEOPERATOR(R1, Zero, ^) CHECKBITWISEOPERATOR(R1, Zero, &) CHECKBITWISEOPERATOR(R1, Max, |) CHECKBITWISEOPERATOR(R1, Max, ^) CHECKBITWISEOPERATOR(R1, Max, &) CHECKBITWISEOPERATOR(Zero, R1, |) CHECKBITWISEOPERATOR(Zero, R1, ^) CHECKBITWISEOPERATOR(Zero, R1, &) CHECKBITWISEOPERATOR(Max, R1, |) CHECKBITWISEOPERATOR(Max, R1, ^) CHECKBITWISEOPERATOR(Max, R1, &) arith_uint256 TmpL; CHECKASSIGNMENTOPERATOR(R1, R2, |) CHECKASSIGNMENTOPERATOR(R1, R2, ^) CHECKASSIGNMENTOPERATOR(R1, R2, &) CHECKASSIGNMENTOPERATOR(R1, Zero, |) CHECKASSIGNMENTOPERATOR(R1, Zero, ^) CHECKASSIGNMENTOPERATOR(R1, Zero, &) CHECKASSIGNMENTOPERATOR(R1, Max, |) CHECKASSIGNMENTOPERATOR(R1, Max, ^) CHECKASSIGNMENTOPERATOR(R1, Max, &) CHECKASSIGNMENTOPERATOR(Zero, R1, |) CHECKASSIGNMENTOPERATOR(Zero, R1, ^) CHECKASSIGNMENTOPERATOR(Zero, R1, &) CHECKASSIGNMENTOPERATOR(Max, R1, |) CHECKASSIGNMENTOPERATOR(Max, R1, ^) CHECKASSIGNMENTOPERATOR(Max, R1, &) uint64_t Tmp64 = 0xe1db685c9a0b47a2ULL; TmpL = R1L; TmpL |= Tmp64; BOOST_CHECK(TmpL == (R1L | arith_uint256(Tmp64))); TmpL = R1L; TmpL |= 0; BOOST_CHECK(TmpL == R1L); TmpL ^= 0; BOOST_CHECK(TmpL == R1L); TmpL ^= Tmp64; BOOST_CHECK(TmpL == (R1L ^ arith_uint256(Tmp64))); } // <= >= < > BOOST_AUTO_TEST_CASE(comparison) { arith_uint256 TmpL; for (unsigned int i = 0; i < 256; ++i) { TmpL = OneL << i; BOOST_CHECK(TmpL >= ZeroL && TmpL > ZeroL && ZeroL < TmpL && ZeroL <= TmpL); BOOST_CHECK(TmpL >= 0 && TmpL > 0 && 0 < TmpL && 0 <= TmpL); TmpL |= R1L; BOOST_CHECK(TmpL >= R1L); BOOST_CHECK((TmpL == R1L) != (TmpL > R1L)); BOOST_CHECK((TmpL == R1L) || !(TmpL <= R1L)); BOOST_CHECK(R1L <= TmpL); BOOST_CHECK((R1L == TmpL) != (R1L < TmpL)); BOOST_CHECK((TmpL == R1L) || !(R1L >= TmpL)); BOOST_CHECK(!(TmpL < R1L)); BOOST_CHECK(!(R1L > TmpL)); } } BOOST_AUTO_TEST_CASE(plusMinus) { arith_uint256 TmpL = 0; BOOST_CHECK(R1L + R2L == arith_uint256(R1LplusR2L)); TmpL += R1L; BOOST_CHECK(TmpL == R1L); TmpL += R2L; BOOST_CHECK(TmpL == R1L + R2L); BOOST_CHECK(OneL + MaxL == ZeroL); BOOST_CHECK(MaxL + OneL == ZeroL); for (unsigned int i = 1; i < 256; ++i) { BOOST_CHECK((MaxL >> i) + OneL == (HalfL >> (i - 1))); BOOST_CHECK(OneL + (MaxL >> i) == (HalfL >> (i - 1))); TmpL = (MaxL >> i); TmpL += OneL; BOOST_CHECK(TmpL == (HalfL >> (i - 1))); TmpL = (MaxL >> i); TmpL += 1; BOOST_CHECK(TmpL == (HalfL >> (i - 1))); TmpL = (MaxL >> i); BOOST_CHECK(TmpL++ == (MaxL >> i)); BOOST_CHECK(TmpL == (HalfL >> (i - 1))); } BOOST_CHECK(arith_uint256(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL)); TmpL = arith_uint256(0xbedc77e27940a7ULL); TmpL += 0xee8d836fce66fbULL; BOOST_CHECK(TmpL == arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL)); TmpL -= 0xee8d836fce66fbULL; BOOST_CHECK(TmpL == 0xbedc77e27940a7ULL); TmpL = R1L; BOOST_CHECK(++TmpL == R1L + 1); BOOST_CHECK(R1L - (-R2L) == R1L + R2L); BOOST_CHECK(R1L - (-OneL) == R1L + OneL); BOOST_CHECK(R1L - OneL == R1L + (-OneL)); for (unsigned int i = 1; i < 256; ++i) { BOOST_CHECK((MaxL >> i) - (-OneL) == (HalfL >> (i - 1))); BOOST_CHECK((HalfL >> (i - 1)) - OneL == (MaxL >> i)); TmpL = (HalfL >> (i - 1)); BOOST_CHECK(TmpL-- == (HalfL >> (i - 1))); BOOST_CHECK(TmpL == (MaxL >> i)); TmpL = (HalfL >> (i - 1)); BOOST_CHECK(--TmpL == (MaxL >> i)); } TmpL = R1L; BOOST_CHECK(--TmpL == R1L - 1); } BOOST_AUTO_TEST_CASE(multiply) { BOOST_CHECK( (R1L * R1L).ToString() == "62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10"); BOOST_CHECK( (R1L * R2L).ToString() == "de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40"); BOOST_CHECK((R1L * ZeroL) == ZeroL); BOOST_CHECK((R1L * OneL) == R1L); BOOST_CHECK((R1L * MaxL) == -R1L); BOOST_CHECK((R2L * R1L) == (R1L * R2L)); BOOST_CHECK( (R2L * R2L).ToString() == "ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100"); BOOST_CHECK((R2L * ZeroL) == ZeroL); BOOST_CHECK((R2L * OneL) == R2L); BOOST_CHECK((R2L * MaxL) == -R2L); BOOST_CHECK(MaxL * MaxL == OneL); BOOST_CHECK((R1L * 0) == 0); BOOST_CHECK((R1L * 1) == R1L); BOOST_CHECK( (R1L * 3).ToString() == "7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4"); BOOST_CHECK( (R2L * 0x87654321UL).ToString() == "23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070"); } BOOST_AUTO_TEST_CASE(divide) { arith_uint256 D1L("AD7133AC1977FA2B7"); arith_uint256 D2L("ECD751716"); BOOST_CHECK( (R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); BOOST_CHECK( (R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); BOOST_CHECK(R1L / OneL == R1L); BOOST_CHECK(R1L / MaxL == ZeroL); BOOST_CHECK(MaxL / R1L == 2); BOOST_CHECK_THROW(R1L / ZeroL, uint_error); BOOST_CHECK( (R2L / D1L).ToString() == "000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5"); BOOST_CHECK( (R2L / D2L).ToString() == "000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4"); BOOST_CHECK(R2L / OneL == R2L); BOOST_CHECK(R2L / MaxL == ZeroL); BOOST_CHECK(MaxL / R2L == 1); BOOST_CHECK_THROW(R2L / ZeroL, uint_error); } static bool almostEqual(double d1, double d2) { return fabs(d1 - d2) <= 4 * fabs(d1) * std::numeric_limits::epsilon(); } // GetHex SetHex size() GetLow64 GetSerializeSize, Serialize, Unserialize BOOST_AUTO_TEST_CASE(methods) { BOOST_CHECK(R1L.GetHex() == R1L.ToString()); BOOST_CHECK(R2L.GetHex() == R2L.ToString()); BOOST_CHECK(OneL.GetHex() == OneL.ToString()); BOOST_CHECK(MaxL.GetHex() == MaxL.ToString()); arith_uint256 TmpL(R1L); BOOST_CHECK(TmpL == R1L); TmpL.SetHex(R2L.ToString()); BOOST_CHECK(TmpL == R2L); TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == 0); TmpL.SetHex(HalfL.ToString()); BOOST_CHECK(TmpL == HalfL); TmpL.SetHex(R1L.ToString()); BOOST_CHECK(R1L.size() == 32); BOOST_CHECK(R2L.size() == 32); BOOST_CHECK(ZeroL.size() == 32); BOOST_CHECK(MaxL.size() == 32); BOOST_CHECK(R1L.GetLow64() == R1LLow64); BOOST_CHECK(HalfL.GetLow64() == 0x0000000000000000ULL); BOOST_CHECK(OneL.GetLow64() == 0x0000000000000001ULL); for (unsigned int i = 0; i < 255; ++i) { BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0, i)); } BOOST_CHECK(ZeroL.getdouble() == 0.0); for (int i = 256; i > 53; --i) { BOOST_CHECK( almostEqual((R1L >> (256 - i)).getdouble(), ldexp(R1Ldouble, i))); } uint64_t R1L64part = (R1L >> 192).GetLow64(); for (int i = 53; i > 0; --i) // doubles can store all integers in {0,...,2^54-1} exactly { BOOST_CHECK((R1L >> (256 - i)).getdouble() == (double)(R1L64part >> (64 - i))); } } BOOST_AUTO_TEST_CASE(bignum_SetCompact) { arith_uint256 num; bool fNegative; bool fOverflow; num.SetCompact(0, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x00123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x01003456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x02000056, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x03000000, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x04000000, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x00923456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x01803456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x02800056, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x03800000, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x04800000, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x01123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000012"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); // Make sure that we don't generate compacts with the 0x00800000 bit set num = 0x80; BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); num.SetCompact(0x01fedcba, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "000000000000000000000000000000000000000000000000000000000000007e"); BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U); BOOST_CHECK_EQUAL(fNegative, true); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x02123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000001234"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x03123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000000123456"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x04123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x04923456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U); BOOST_CHECK_EQUAL(fNegative, true); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x05009234, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "0000000000000000000000000000000000000000000000000000000092340000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0x20123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL( num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, false); num.SetCompact(0xff123456, &fNegative, &fOverflow); BOOST_CHECK_EQUAL(fNegative, false); BOOST_CHECK_EQUAL(fOverflow, true); } // some more tests just to get 100% coverage BOOST_AUTO_TEST_CASE(getmaxcoverage) { // ~R1L give a base_uint<256> BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); BOOST_CHECK((~~R1L << 10) == (R1L << 10)); BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L); BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L); BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); uint8_t TmpArray[32]; CHECKBITWISEOPERATOR(~R1, R2, |) CHECKBITWISEOPERATOR(~R1, R2, ^) CHECKBITWISEOPERATOR(~R1, R2, &) CHECKBITWISEOPERATOR(R1, ~R2, |) CHECKBITWISEOPERATOR(R1, ~R2, ^) CHECKBITWISEOPERATOR(R1, ~R2, &) } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 51790fa34..c7617c54f 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -1,300 +1,299 @@ // Copyright (c) 2013-2019 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 #include #include #include -#include #include #include #include #include #include #include struct TestDerivation { std::string pub; std::string prv; unsigned int nChild; }; struct TestVector { std::string strHexMaster; std::vector vDerive; explicit TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {} TestVector &operator()(std::string pub, std::string prv, unsigned int nChild) { vDerive.push_back(TestDerivation()); TestDerivation &der = vDerive.back(); der.pub = pub; der.prv = prv; der.nChild = nChild; return *this; } }; // clang-format off TestVector test1 = TestVector("000102030405060708090a0b0c0d0e0f") ("xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", 0x80000000) ("xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw", "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", 1) ("xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ", "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", 0x80000002) ("xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5", "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", 2) ("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV", "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", 1000000000) ("xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy", "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", 0); TestVector test2 = TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542") ("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", 0) ("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH", "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", 0xFFFFFFFF) ("xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a", "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", 1) ("xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon", "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", 0xFFFFFFFE) ("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL", "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", 2) ("xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt", "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", 0); TestVector test3 = TestVector("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be") ("xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", 0x80000000) ("xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y", "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", 0); // clang-format on static void RunTest(const TestVector &test) { std::vector seed = ParseHex(test.strHexMaster); CExtKey key; CExtPubKey pubkey; key.SetSeed(seed.data(), seed.size()); pubkey = key.Neuter(); for (const TestDerivation &derive : test.vDerive) { uint8_t data[74]; key.Encode(data); pubkey.Encode(data); // Test private key BOOST_CHECK(EncodeExtKey(key) == derive.prv); // Ensure a base58 decoded key also matches BOOST_CHECK(DecodeExtKey(derive.prv) == key); // Test public key BOOST_CHECK(EncodeExtPubKey(pubkey) == derive.pub); // Ensure a base58 decoded pubkey also matches BOOST_CHECK(DecodeExtPubKey(derive.pub) == pubkey); // Derive new keys CExtKey keyNew; BOOST_CHECK(key.Derive(keyNew, derive.nChild)); CExtPubKey pubkeyNew = keyNew.Neuter(); if (!(derive.nChild & 0x80000000)) { // Compare with public derivation CExtPubKey pubkeyNew2; BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild)); BOOST_CHECK(pubkeyNew == pubkeyNew2); } key = keyNew; pubkey = pubkeyNew; CDataStream ssPub(SER_DISK, CLIENT_VERSION); ssPub << pubkeyNew; BOOST_CHECK(ssPub.size() == 75); CDataStream ssPriv(SER_DISK, CLIENT_VERSION); ssPriv << keyNew; BOOST_CHECK(ssPriv.size() == 75); CExtPubKey pubCheck; CExtKey privCheck; ssPub >> pubCheck; ssPriv >> privCheck; BOOST_CHECK(pubCheck == pubkeyNew); BOOST_CHECK(privCheck == keyNew); } } BOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bip32_test1) { RunTest(test1); } BOOST_AUTO_TEST_CASE(bip32_test2) { RunTest(test2); } BOOST_AUTO_TEST_CASE(bip32_test3) { RunTest(test3); } bool check_key_size_message(const std::runtime_error &e) { BOOST_CHECK_EQUAL(e.what(), "Invalid extended key size\n"); return true; } BOOST_AUTO_TEST_CASE(bip32_serialization) { std::vector pubkeys{ "013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad1628" "2c7ae6236141035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c70" "6cfccc56", "025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578" "e9b6adb37c1903501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bed" "b3cd711c", "03bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3" "ff6ec7b1503f0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a78" "96ee8dc2", "04ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac12" "75ac822a3edd02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e358045" "60741d29", "05d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548" "a8b078e65e9e022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5" "a48f7011", "06d69aa10200000000739379b40b549fdb7f2439c028dac3192d4706deec3f0fef6816" "ea36c8fc3fda028817473b2e81a20b60a24fc7a0d7869368ebc36740cfe08a18a19a9d" "dafae67c", "01bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7" "412f232f7c9c02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22" "a98d12ea", "025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b3854" "7f585c9a37d903c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666a" "bc0a5c3b", "03d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c92" "7eb246fb38cb03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e78" "1a7df5b9", "0478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06" "cc29a65a0e2902d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806ca" "fb0301f0", "0531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58" "eedf394ed271024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c" "7afe1f9c", "0626132fdb0000000005bcc50a4c1bbfa6d982ae1f410f88ddcbacad781b11b8790c86" "f49cdf9e77b0031c0517fff3d483f06ca769bd2326bf30aca1c4de278e676e6ef760c3" "301244c6", "0141d63b5080000000e5fea12a97b927fc9dc3d2cb0d1ea1cf50aa5a1fdc1f933e8906" "bb38df3377bd026557fdda1d5d43d79611f784780471f086d58e8126b8c40acb82272a" "7712e7f2", "02c61368bb000000007c63ec0429a7324b76014ad222a32b7fdd3ae8755d0d2b2e3dfb" "5ede9787af990379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3d" "f8d4a9e3", }; for (const std::string &hex : pubkeys) { CDataStream ss(SER_DISK, CLIENT_VERSION); ss << ParseHex(hex); BOOST_CHECK(ss.size() == 75); CExtPubKey pubkey; BOOST_CHECK_NO_THROW(ss >> pubkey); ss << ParseHex(hex + "00"); BOOST_CHECK(ss.size() == 76); BOOST_CHECK_EXCEPTION(ss >> pubkey, std::runtime_error, check_key_size_message); ss.clear(); ss << ParseHex(hex.substr(0, hex.size() - 1)); BOOST_CHECK(ss.size() == 74); BOOST_CHECK_EXCEPTION(ss >> pubkey, std::runtime_error, check_key_size_message); } std::vector privkeys{ "013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad1628" "2c7ae623614100edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d9" "11a0afea", "025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578" "e9b6adb37c19003c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de931" "9dc93368", "03bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3" "ff6ec7b1503f00cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59" "fa424dca", "04ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac12" "75ac822a3edd000f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a" "2a764ef4", "05d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548" "a8b078e65e9e00471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6" "c3e6e7c8", "06d69aa10200000000739379b40b549fdb7f2439c028dac3192d4706deec3f0fef6816" "ea36c8fc3fda00996cbe292e59ce1c8ee257522ce969b9faa413f7e9aa4a8785b8f574" "e0e2f061", "01bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7" "412f232f7c9c00abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f" "15ac7e1e", "025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b3854" "7f585c9a37d900877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18f" "d52e6e93", "03d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c92" "7eb246fb38cb00704addf544a06e5ee4bea37098463c23613da32020d604506da8c051" "8e1da4b7", "0478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06" "cc29a65a0e2900f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b" "247d6a2d", "0531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58" "eedf394ed27100bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a484" "2125ac23", "0626132fdb0000000005bcc50a4c1bbfa6d982ae1f410f88ddcbacad781b11b8790c86" "f49cdf9e77b0004b7e8b1aa263519f7fbed001d5b0c4a5fdac81db8abe14c327e2f534" "92e55fa7", "0141d63b5080000000e5fea12a97b927fc9dc3d2cb0d1ea1cf50aa5a1fdc1f933e8906" "bb38df3377bd00491f7a2eebc7b57028e0d3faa0acda02e75c33b03c48fb288c41e2ea" "44e1daef", "02c61368bb000000007c63ec0429a7324b76014ad222a32b7fdd3ae8755d0d2b2e3dfb" "5ede9787af9900129ee831061c31be7d636fc0402fd2299855f40015a2c60b2e5755c5" "7270460d", }; for (const std::string &hex : privkeys) { CDataStream ss(SER_DISK, CLIENT_VERSION); ss << ParseHex(hex); BOOST_CHECK(ss.size() == 75); CExtKey privkey; BOOST_CHECK_NO_THROW(ss >> privkey); ss << ParseHex(hex + "00"); BOOST_CHECK(ss.size() == 76); BOOST_CHECK_EXCEPTION(ss >> privkey, std::runtime_error, check_key_size_message); ss.clear(); ss << ParseHex(hex.substr(0, hex.size() - 1)); BOOST_CHECK(ss.size() == 74); BOOST_CHECK_EXCEPTION(ss >> privkey, std::runtime_error, check_key_size_message); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 3f45d09e9..540b7b1c5 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -1,489 +1,488 @@ // Copyright (c) 2011-2019 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 #include #include #include #include -#include #include #include #include #include static std::vector> extra_txn; struct RegtestingSetup : public TestingSetup { RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {} }; BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegtestingSetup) static COutPoint InsecureRandOutPoint() { return COutPoint(TxId(InsecureRand256()), 0); } static CBlock BuildBlockTestCase() { CBlock block; CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig.resize(10); tx.vout.resize(1); tx.vout[0].nValue = 42 * SATOSHI; block.vtx.resize(3); block.vtx[0] = MakeTransactionRef(tx); block.nVersion = 42; block.hashPrevBlock = BlockHash(InsecureRand256()); block.nBits = 0x207fffff; tx.vin[0].prevout = InsecureRandOutPoint(); block.vtx[1] = MakeTransactionRef(tx); tx.vin.resize(10); for (size_t i = 0; i < tx.vin.size(); i++) { tx.vin[i].prevout = InsecureRandOutPoint(); } block.vtx[2] = MakeTransactionRef(tx); bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); GlobalConfig config; const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) { ++block.nNonce; } return block; } // BOOST_CHECK_EXCEPTION predicates to check the exception message class HasReason { public: HasReason(const std::string &reason) : m_reason(reason) {} bool operator()(const std::exception &e) const { return std::string(e.what()).find(m_reason) != std::string::npos; }; private: const std::string m_reason; }; // Number of shared use_counts we expect for a tx we haven't touched // (block + mempool + our copy from the GetSharedTx call) constexpr long SHARED_TX_OFFSET{3}; BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) { CTxMemPool pool; TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); // Do a simple ShortTxIDs RT { CBlockHeaderAndShortTxIDs shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); BOOST_CHECK(!partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); size_t poolSize = pool.size(); pool.removeRecursive(*block.vtx[2]); BOOST_CHECK_EQUAL(pool.size(), poolSize - 1); CBlock block2; { // No transactions. PartiallyDownloadedBlock tmp = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); partialBlock = tmp; } // Wrong transaction { // Current implementation doesn't check txn here, but don't require // that. PartiallyDownloadedBlock tmp = partialBlock; partialBlock.FillBlock(block2, {block.vtx[2]}); partialBlock = tmp; } bool mutated; BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated)); CBlock block3; BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); } } class TestHeaderAndShortIDs { // Utility to encode custom CBlockHeaderAndShortTxIDs public: CBlockHeader header; uint64_t nonce; std::vector shorttxids; std::vector prefilledtxn; explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs &orig) { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << orig; stream >> *this; } explicit TestHeaderAndShortIDs(const CBlock &block) : TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {} uint64_t GetShortID(const TxHash &txhash) const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << *this; CBlockHeaderAndShortTxIDs base; stream >> base; return base.GetShortID(txhash); } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(header); READWRITE(nonce); size_t shorttxids_size = shorttxids.size(); READWRITE(VARINT(shorttxids_size)); shorttxids.resize(shorttxids_size); for (size_t i = 0; i < shorttxids.size(); i++) { uint32_t lsb = shorttxids[i] & 0xffffffff; uint16_t msb = (shorttxids[i] >> 32) & 0xffff; READWRITE(lsb); READWRITE(msb); shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); } READWRITE(prefilledtxn); } }; BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) { CTxMemPool pool; TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); TxId txid; // Test with pre-forwarding tx 1, but not coinbase { TestHeaderAndShortIDs shortIDs(block); shortIDs.prefilledtxn.resize(1); shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; shortIDs.shorttxids.resize(2); shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash()); shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(!partialBlock.IsTxAvailable(0)); BOOST_CHECK(partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); // +1 because of partialBlock BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; { // No transactions. PartiallyDownloadedBlock tmp = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); partialBlock = tmp; } // Wrong transaction { // Current implementation doesn't check txn here, but don't require // that. PartiallyDownloadedBlock tmp = partialBlock; partialBlock.FillBlock(block2, {block.vtx[1]}); partialBlock = tmp; } // +2 because of partialBlock and block2 BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 2); bool mutated; BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated)); CBlock block3; PartiallyDownloadedBlock partialBlockCopy = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); // +3 because of partialBlock and block2 and block3 BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 3); txid = block.vtx[2]->GetId(); block.vtx.clear(); block2.vtx.clear(); block3.vtx.clear(); // + 1 because of partialBlock; -1 because of block. BOOST_CHECK_EQUAL(pool.mapTx.find(txid)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); } // -1 because of block BOOST_CHECK_EQUAL(pool.mapTx.find(txid)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); } BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) { CTxMemPool pool; TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); LOCK2(cs_main, pool.cs); pool.addUnchecked(entry.FromTx(block.vtx[1])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); TxId txid; // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool { TestHeaderAndShortIDs shortIDs(block); shortIDs.prefilledtxn.resize(2); shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; // id == 1 as it is 1 after index 1 shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; shortIDs.shorttxids.resize(1); shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); BOOST_CHECK(partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; PartiallyDownloadedBlock partialBlockCopy = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); bool mutated; BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); txid = block.vtx[1]->GetId(); block.vtx.clear(); block2.vtx.clear(); // + 1 because of partialBlock; -1 because of block. BOOST_CHECK_EQUAL(pool.mapTx.find(txid)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); } // -1 because of block BOOST_CHECK_EQUAL(pool.mapTx.find(txid)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); } BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) { CTxMemPool pool; CMutableTransaction coinbase; coinbase.vin.resize(1); coinbase.vin[0].scriptSig.resize(10); coinbase.vout.resize(1); coinbase.vout[0].nValue = 42 * SATOSHI; CBlock block; block.vtx.resize(1); block.vtx[0] = MakeTransactionRef(std::move(coinbase)); block.nVersion = 42; block.hashPrevBlock = BlockHash(InsecureRand256()); block.nBits = 0x207fffff; bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); GlobalConfig config; const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) { ++block.nNonce; } // Test simple header round-trip with only coinbase { CBlockHeaderAndShortTxIDs shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); CBlock block2; std::vector vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); } } BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BlockTransactionsRequest req1; req1.blockhash = BlockHash(InsecureRand256()); req1.indices.resize(4); req1.indices[0] = 0; req1.indices[1] = 1; req1.indices[2] = 3; req1.indices[3] = 4; CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << req1; BlockTransactionsRequest req2; stream >> req2; BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString()); BOOST_CHECK_EQUAL(req1.indices.size(), req2.indices.size()); BOOST_CHECK_EQUAL(req1.indices[0], req2.indices[0]); BOOST_CHECK_EQUAL(req1.indices[1], req2.indices[1]); BOOST_CHECK_EQUAL(req1.indices[2], req2.indices[2]); BOOST_CHECK_EQUAL(req1.indices[3], req2.indices[3]); } BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { // Check that the highest legal index is decoded correctly BlockTransactionsRequest req0; req0.blockhash = BlockHash(InsecureRand256()); req0.indices.resize(1); using indiceType = decltype(req0.indices)::value_type; static_assert(MAX_SIZE < std::numeric_limits::max(), "The max payload size cannot fit into the indice type"); req0.indices[0] = MAX_SIZE; CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << req0; BlockTransactionsRequest req1; stream >> req1; BOOST_CHECK_EQUAL(req0.indices.size(), req1.indices.size()); BOOST_CHECK_EQUAL(req0.indices[0], req1.indices[0]); req0.indices[0] += 1; stream << req0; BlockTransactionsRequest req2; BOOST_CHECK_EXCEPTION(stream >> req2, std::ios_base::failure, HasReason("ReadCompactSize(): size too large")); } BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) { // Any set of index deltas that starts with N values that sum to // (0x100000000 - N) causes the edge-case overflow that was originally not // checked for. Such a request cannot be created by serializing a real // BlockTransactionsRequest due to the overflow, so here we'll serialize // from raw deltas. This can only occur if MAX_SIZE is greater than the // maximum value for that the indice type can handle. BlockTransactionsRequest req0; req0.blockhash = BlockHash(InsecureRand256()); req0.indices.resize(3); using indiceType = decltype(req0.indices)::value_type; static_assert(std::is_same::value, "This test expects the indice type to be an uint32_t"); req0.indices[0] = 0x7000; req0.indices[1] = 0x100000000 - 0x7000 - 2; req0.indices[2] = 0; CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << req0.blockhash; WriteCompactSize(stream, req0.indices.size()); WriteCompactSize(stream, req0.indices[0]); WriteCompactSize(stream, req0.indices[1]); WriteCompactSize(stream, req0.indices[2]); BlockTransactionsRequest req1; // If MAX_SIZE is the limiting factor, the deserialization should throw. // Otherwise make sure that the overflow edge-case is under control. BOOST_CHECK_EXCEPTION(stream >> req1, std::ios_base::failure, HasReason((MAX_SIZE < req0.indices[1]) ? "ReadCompactSize(): size too large" : "indices overflowed 32 bits")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 323b67b7b..d35ffe501 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -1,417 +1,416 @@ // Copyright (c) 2012-2019 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 #include #include #include #include #include #include #include #include #include #include #include -#include #include // BasicTestingSetup not sufficient because nScriptCheckThreads is not set // otherwise. BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup) static const unsigned int QUEUE_BATCH_SIZE = 128; struct FakeCheck { bool operator()() { return true; } void swap(FakeCheck &x){}; }; struct FakeCheckCheckCompletion { static std::atomic n_calls; bool operator()() { n_calls.fetch_add(1, std::memory_order_relaxed); return true; } void swap(FakeCheckCheckCompletion &x){}; }; struct FailingCheck { bool fails; FailingCheck(bool _fails) : fails(_fails){}; FailingCheck() : fails(true){}; bool operator()() { return !fails; } void swap(FailingCheck &x) { std::swap(fails, x.fails); }; }; struct UniqueCheck { static std::mutex m; static std::unordered_multiset results; size_t check_id; UniqueCheck(size_t check_id_in) : check_id(check_id_in){}; UniqueCheck() : check_id(0){}; bool operator()() { std::lock_guard l(m); results.insert(check_id); return true; } void swap(UniqueCheck &x) { std::swap(x.check_id, check_id); }; }; struct MemoryCheck { static std::atomic fake_allocated_memory; bool b{false}; bool operator()() { return true; } MemoryCheck(){}; MemoryCheck(const MemoryCheck &x) { // We have to do this to make sure that destructor calls are paired // // Really, copy constructor should be deletable, but CCheckQueue breaks // if it is deleted because of internal push_back. fake_allocated_memory.fetch_add(b, std::memory_order_relaxed); }; MemoryCheck(bool b_) : b(b_) { fake_allocated_memory.fetch_add(b, std::memory_order_relaxed); }; ~MemoryCheck() { fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed); }; void swap(MemoryCheck &x) { std::swap(b, x.b); }; }; struct FrozenCleanupCheck { static std::atomic nFrozen; static std::condition_variable cv; static std::mutex m; // Freezing can't be the default initialized behavior given how the queue // swaps in default initialized Checks. bool should_freeze{false}; bool operator()() { return true; } FrozenCleanupCheck() {} ~FrozenCleanupCheck() { if (should_freeze) { std::unique_lock l(m); nFrozen.store(1, std::memory_order_relaxed); cv.notify_one(); cv.wait( l, [] { return nFrozen.load(std::memory_order_relaxed) == 0; }); } } void swap(FrozenCleanupCheck &x) { std::swap(should_freeze, x.should_freeze); }; }; // Static Allocations std::mutex FrozenCleanupCheck::m{}; std::atomic FrozenCleanupCheck::nFrozen{0}; std::condition_variable FrozenCleanupCheck::cv{}; std::mutex UniqueCheck::m; std::unordered_multiset UniqueCheck::results; std::atomic FakeCheckCheckCompletion::n_calls{0}; std::atomic MemoryCheck::fake_allocated_memory{0}; // Queue Typedefs typedef CCheckQueue Correct_Queue; typedef CCheckQueue Standard_Queue; typedef CCheckQueue Failing_Queue; typedef CCheckQueue Unique_Queue; typedef CCheckQueue Memory_Queue; typedef CCheckQueue FrozenCleanup_Queue; /** This test case checks that the CCheckQueue works properly * with each specified size_t Checks pushed. */ static void Correct_Queue_range(std::vector range) { auto small_queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { small_queue->Thread(); }); } // Make vChecks here to save on malloc (this test can be slow...) std::vector vChecks; for (const size_t i : range) { size_t total = i; FakeCheckCheckCompletion::n_calls = 0; CCheckQueueControl control(small_queue.get()); while (total) { vChecks.resize(std::min(total, (size_t)InsecureRandRange(10))); total -= vChecks.size(); control.Add(vChecks); } BOOST_REQUIRE(control.Wait()); if (FakeCheckCheckCompletion::n_calls != i) { BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i); } } tg.interrupt_all(); tg.join_all(); } /** Test that 0 checks is correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) { std::vector range; range.push_back((size_t)0); Correct_Queue_range(range); } /** Test that 1 check is correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One) { std::vector range; range.push_back((size_t)1); Correct_Queue_range(range); } /** Test that MAX check is correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max) { std::vector range; range.push_back(100000); Correct_Queue_range(range); } /** Test that random numbers of checks are correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) { std::vector range; range.reserve(100000 / 1000); for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)InsecureRandRange(std::min( (size_t)1000, ((size_t)100000) - i)))) { range.push_back(i); } Correct_Queue_range(range); } /** Test that failing checks are caught */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) { auto fail_queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { fail_queue->Thread(); }); } for (size_t i = 0; i < 1001; ++i) { CCheckQueueControl control(fail_queue.get()); size_t remaining = i; while (remaining) { size_t r = InsecureRandRange(10); std::vector vChecks; vChecks.reserve(r); for (size_t k = 0; k < r && remaining; k++, remaining--) { vChecks.emplace_back(remaining == 1); } control.Add(vChecks); } bool success = control.Wait(); if (i > 0) { BOOST_REQUIRE(!success); } else if (i == 0) { BOOST_REQUIRE(success); } } tg.interrupt_all(); tg.join_all(); } // Test that a block validation which fails does not interfere with // future blocks, ie, the bad state is cleared. BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) { auto fail_queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { fail_queue->Thread(); }); } for (auto times = 0; times < 10; ++times) { for (const bool end_fails : {true, false}) { CCheckQueueControl control(fail_queue.get()); { std::vector vChecks; vChecks.resize(100, false); vChecks[99] = end_fails; control.Add(vChecks); } bool r = control.Wait(); BOOST_REQUIRE(r != end_fails); } } tg.interrupt_all(); tg.join_all(); } // Test that unique checks are actually all called individually, rather than // just one check being called repeatedly. Test that checks are not called // more than once as well BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) { auto queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { queue->Thread(); }); } size_t COUNT = 100000; size_t total = COUNT; { CCheckQueueControl control(queue.get()); while (total) { size_t r = InsecureRandRange(10); std::vector vChecks; for (size_t k = 0; k < r && total; k++) { vChecks.emplace_back(--total); } control.Add(vChecks); } } bool r = true; BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT); for (size_t i = 0; i < COUNT; ++i) { r = r && UniqueCheck::results.count(i) == 1; } BOOST_REQUIRE(r); tg.interrupt_all(); tg.join_all(); } // Test that blocks which might allocate lots of memory free their memory // aggressively. // // This test attempts to catch a pathological case where by lazily freeing // checks might mean leaving a check un-swapped out, and decreasing by 1 each // time could leave the data hanging across a sequence of blocks. BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) { auto queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { queue->Thread(); }); } for (size_t i = 0; i < 1000; ++i) { size_t total = i; { CCheckQueueControl control(queue.get()); while (total) { size_t r = InsecureRandRange(10); std::vector vChecks; for (size_t k = 0; k < r && total; k++) { total--; // Each iteration leaves data at the front, back, and middle // to catch any sort of deallocation failure vChecks.emplace_back(total == 0 || total == i || total == i / 2); } control.Add(vChecks); } } BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U); } tg.interrupt_all(); tg.join_all(); } // Test that a new verification cannot occur until all checks // have been destructed BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) { auto queue = std::make_unique(QUEUE_BATCH_SIZE); boost::thread_group tg; bool fails = false; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&] { queue->Thread(); }); } std::thread t0([&]() { CCheckQueueControl control(queue.get()); std::vector vChecks(1); // Freezing can't be the default initialized behavior given how the // queue // swaps in default initialized Checks (otherwise freezing destructor // would get called twice). vChecks[0].should_freeze = true; control.Add(vChecks); control.Wait(); // Hangs here }); { std::unique_lock l(FrozenCleanupCheck::m); // Wait until the queue has finished all jobs and frozen FrozenCleanupCheck::cv.wait( l, []() { return FrozenCleanupCheck::nFrozen == 1; }); } // Try to get control of the queue a bunch of times for (auto x = 0; x < 100 && !fails; ++x) { fails = queue->ControlMutex.try_lock(); } { // Unfreeze (we need lock n case of spurious wakeup) std::unique_lock l(FrozenCleanupCheck::m); FrozenCleanupCheck::nFrozen = 0; } // Awaken frozen destructor FrozenCleanupCheck::cv.notify_one(); // Wait for control to finish t0.join(); tg.interrupt_all(); tg.join_all(); BOOST_REQUIRE(!fails); } /** Test that CCheckQueueControl is threadsafe */ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) { auto queue = std::make_unique(QUEUE_BATCH_SIZE); { boost::thread_group tg; std::atomic nThreads{0}; std::atomic fails{0}; for (size_t i = 0; i < 3; ++i) { tg.create_thread([&] { CCheckQueueControl control(queue.get()); // While sleeping, no other thread should execute to this point auto observed = ++nThreads; MilliSleep(10); fails += observed != nThreads; }); } tg.join_all(); BOOST_REQUIRE_EQUAL(fails, 0); } { boost::thread_group tg; std::mutex m; std::condition_variable cv; bool has_lock{false}; bool has_tried{false}; bool done{false}; bool done_ack{false}; { std::unique_lock l(m); tg.create_thread([&] { CCheckQueueControl control(queue.get()); std::unique_lock ll(m); has_lock = true; cv.notify_one(); cv.wait(ll, [&] { return has_tried; }); done = true; cv.notify_one(); // Wait until the done is acknowledged // cv.wait(ll, [&] { return done_ack; }); }); // Wait for thread to get the lock cv.wait(l, [&]() { return has_lock; }); bool fails = false; for (auto x = 0; x < 100 && !fails; ++x) { fails = queue->ControlMutex.try_lock(); } has_tried = true; cv.notify_one(); cv.wait(l, [&]() { return done; }); // Acknowledge the done done_ack = true; cv.notify_one(); BOOST_REQUIRE(!fails); } tg.join_all(); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 77053399c..3bb2adf4f 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -1,344 +1,343 @@ // Copyright (c) 2012-2019 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 -#include #include #include #include #include // Test if a string consists entirely of null characters static bool is_null_key(const std::vector &key) { bool isnull = true; for (unsigned int i = 0; i < key.size(); i++) { isnull &= (key[i] == '\x00'); } return isnull; } BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; uint256 in = InsecureRand256(); uint256 res; // Ensure that we're doing real obfuscation when obfuscate=true BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); BOOST_CHECK(dbw.Write(key, in)); BOOST_CHECK(dbw.Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); } } // Test batch operations BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'i'; uint256 in = InsecureRand256(); char key2 = 'j'; uint256 in2 = InsecureRand256(); char key3 = 'k'; uint256 in3 = InsecureRand256(); uint256 res; CDBBatch batch(dbw); batch.Write(key, in); batch.Write(key2, in2); batch.Write(key3, in3); // Remove key3 before it's even been written batch.Erase(key3); dbw.WriteBatch(batch); BOOST_CHECK(dbw.Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); BOOST_CHECK(dbw.Read(key2, res)); BOOST_CHECK_EQUAL(res.ToString(), in2.ToString()); // key3 should've never been written BOOST_CHECK(dbw.Read(key3, res) == false); } } BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering char key = 'j'; uint256 in = InsecureRand256(); BOOST_CHECK(dbw.Write(key, in)); char key2 = 'k'; uint256 in2 = InsecureRand256(); BOOST_CHECK(dbw.Write(key2, in2)); std::unique_ptr it( const_cast(dbw).NewIterator()); // Be sure to seek past the obfuscation key (if it exists) it->Seek(key); char key_res; uint256 val_res; it->GetKey(key_res); it->GetValue(val_res); BOOST_CHECK_EQUAL(key_res, key); BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString()); it->Next(); it->GetKey(key_res); it->GetValue(val_res); BOOST_CHECK_EQUAL(key_res, key2); BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString()); it->Next(); BOOST_CHECK_EQUAL(it->Valid(), false); } } // Test that we do not obfuscation if there is existing data. BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { // We're going to share this fs::path between two wrappers fs::path ph = GetDataDir() / "existing_data_no_obfuscate"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr dbw = std::make_unique(ph, (1 << 10), false, false, false); char key = 'k'; uint256 in = InsecureRand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); BOOST_CHECK(dbw->Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); // Call the destructor to free leveldb LOCK dbw.reset(); // Now, set up another wrapper that wants to obfuscate the same directory CDBWrapper odbw(ph, (1 << 10), false, false, true); // Check that the key/val we wrote with unobfuscated wrapper exists and // is readable. uint256 res2; BOOST_CHECK(odbw.Read(key, res2)); BOOST_CHECK_EQUAL(res2.ToString(), in.ToString()); // There should be existing data BOOST_CHECK(!odbw.IsEmpty()); // The key should be an empty string BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); uint256 in2 = InsecureRand256(); uint256 res3; // Check that we can write successfully BOOST_CHECK(odbw.Write(key, in2)); BOOST_CHECK(odbw.Read(key, res3)); BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); } // Ensure that we start obfuscating during a reindex. BOOST_AUTO_TEST_CASE(existing_data_reindex) { // We're going to share this fs::path between two wrappers fs::path ph = GetDataDir() / "existing_data_reindex"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr dbw = std::make_unique(ph, (1 << 10), false, false, false); char key = 'k'; uint256 in = InsecureRand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); BOOST_CHECK(dbw->Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); // Call the destructor to free leveldb LOCK dbw.reset(); // Simulate a -reindex by wiping the existing data store CDBWrapper odbw(ph, (1 << 10), false, true, true); // Check that the key/val we wrote with unobfuscated wrapper doesn't exist uint256 res2; BOOST_CHECK(!odbw.Read(key, res2)); BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); uint256 in2 = InsecureRand256(); uint256 res3; // Check that we can write successfully BOOST_CHECK(odbw.Write(key, in2)); BOOST_CHECK(odbw.Read(key, res3)); BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); } BOOST_AUTO_TEST_CASE(iterator_ordering) { fs::path ph = GetDataDir() / "iterator_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x = 0x00; x < 256; ++x) { uint8_t key = x; uint32_t value = x * x; if (!(x & 1)) { BOOST_CHECK(dbw.Write(key, value)); } } // Check that creating an iterator creates a snapshot std::unique_ptr it( const_cast(dbw).NewIterator()); for (unsigned int x = 0x00; x < 256; ++x) { uint8_t key = x; uint32_t value = x * x; if (x & 1) { BOOST_CHECK(dbw.Write(key, value)); } } for (const int seek_start : {0x00, 0x80}) { it->Seek((uint8_t)seek_start); for (unsigned int x = seek_start; x < 255; ++x) { uint8_t key; uint32_t value; BOOST_CHECK(it->Valid()); // Avoid spurious errors about invalid iterator's key and value in // case of failure if (!it->Valid()) { break; } BOOST_CHECK(it->GetKey(key)); if (x & 1) { BOOST_CHECK_EQUAL(key, x + 1); continue; } BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key, x); BOOST_CHECK_EQUAL(value, x * x); it->Next(); } BOOST_CHECK(!it->Valid()); } } struct StringContentsSerializer { // Used to make two serialized objects the same while letting them have // different lengths. This is a terrible idea. std::string str; StringContentsSerializer() {} explicit StringContentsSerializer(const std::string &inp) : str(inp) {} StringContentsSerializer &operator+=(const std::string &s) { str += s; return *this; } StringContentsSerializer &operator+=(const StringContentsSerializer &s) { return *this += s.str; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { if (ser_action.ForRead()) { str.clear(); char c = 0; while (true) { try { READWRITE(c); str.push_back(c); } catch (const std::ios_base::failure &) { break; } } } else { for (size_t i = 0; i < str.size(); i++) { READWRITE(str[i]); } } } }; BOOST_AUTO_TEST_CASE(iterator_string_ordering) { char buf[10]; fs::path ph = GetDataDir() / "iterator_string_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x = 0x00; x < 10; ++x) { for (int y = 0; y < 10; y++) { snprintf(buf, sizeof(buf), "%d", x); StringContentsSerializer key(buf); for (int z = 0; z < y; z++) { key += key; } uint32_t value = x * x; BOOST_CHECK(dbw.Write(key, value)); } } std::unique_ptr it( const_cast(dbw).NewIterator()); for (const int seek_start : {0, 5}) { snprintf(buf, sizeof(buf), "%d", seek_start); StringContentsSerializer seek_key(buf); it->Seek(seek_key); for (unsigned int x = seek_start; x < 10; ++x) { for (int y = 0; y < 10; y++) { snprintf(buf, sizeof(buf), "%d", x); std::string exp_key(buf); for (int z = 0; z < y; z++) { exp_key += exp_key; } StringContentsSerializer key; uint32_t value; BOOST_CHECK(it->Valid()); // Avoid spurious errors about invalid iterator's key and value // in case of failure if (!it->Valid()) { break; } BOOST_CHECK(it->GetKey(key)); BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key.str, exp_key); BOOST_CHECK_EQUAL(value, x * x); it->Next(); } } BOOST_CHECK(!it->Valid()); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 6f70cdf10..9f4c570f9 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -1,481 +1,482 @@ // Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // Unit tests for denial-of-service detection/prevention code #include #include #include #include #include #include #include #include #include