diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bench/ccoins_caching.cpp | 42 | ||||
-rw-r--r-- | src/net.cpp | 24 | ||||
-rw-r--r-- | src/net.h | 15 | ||||
-rw-r--r-- | src/randomenv.cpp | 19 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 45 | ||||
-rw-r--r-- | src/test/util/transaction_utils.cpp | 32 | ||||
-rw-r--r-- | src/test/util/transaction_utils.h | 10 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 6 | ||||
-rw-r--r-- | src/util/moneystr.cpp | 10 | ||||
-rw-r--r-- | src/util/moneystr.h | 2 | ||||
-rw-r--r-- | src/wallet/test/coinselector_tests.cpp | 13 |
11 files changed, 107 insertions, 111 deletions
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index c313029ea8..e9dd40293f 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -6,47 +6,10 @@ #include <coins.h> #include <policy/policy.h> #include <script/signingprovider.h> +#include <test/util/transaction_utils.h> #include <vector> -// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp. -// -// Helper: create two dummy transactions, each with -// two outputs. The first has 11 and 50 COIN outputs -// paid to a TX_PUBKEY, the second 21 and 22 COIN outputs -// paid to a TX_PUBKEYHASH. -// -static std::vector<CMutableTransaction> -SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet) -{ - std::vector<CMutableTransaction> dummyTransactions; - dummyTransactions.resize(2); - - // Add some keys to the keystore: - CKey key[4]; - for (int i = 0; i < 4; i++) { - key[i].MakeNewKey(i % 2); - keystoreRet.AddKey(key[i]); - } - - // Create some dummy input transactions - dummyTransactions[0].vout.resize(2); - dummyTransactions[0].vout[0].nValue = 11 * COIN; - dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - dummyTransactions[0].vout[1].nValue = 50 * COIN; - dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; - AddCoins(coinsRet, CTransaction(dummyTransactions[0]), 0); - - dummyTransactions[1].vout.resize(2); - dummyTransactions[1].vout[0].nValue = 21 * COIN; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); - dummyTransactions[1].vout[1].nValue = 22 * COIN; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); - AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); - - return dummyTransactions; -} - // Microbenchmark for simple accesses to a CCoinsViewCache database. Note from // laanwj, "replicating the actual usage patterns of the client is hard though, // many times micro-benchmarks of the database showed completely different @@ -58,7 +21,8 @@ static void CCoinsCaching(benchmark::State& state) FillableSigningProvider keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); - std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); + std::vector<CMutableTransaction> dummyTransactions = + SetupDummyInputs(keystore, coins, {11 * COIN, 50 * COIN, 21 * COIN, 22 * COIN}); CMutableTransaction t1; t1.vin.resize(3); diff --git a/src/net.cpp b/src/net.cpp index 18fe95e675..cb4067e825 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -718,6 +718,19 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta return msg; } +void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) { + // create dbl-sha256 checksum + uint256 hash = Hash(msg.data.begin(), msg.data.end()); + + // create header + CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), msg.data.size()); + memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); + + // serialize header + header.reserve(CMessageHeader::HEADER_SIZE); + CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, header, 0, hdr}; +} + size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pnode->cs_vSend) { auto it = pnode->vSendMsg.begin(); @@ -2705,6 +2718,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn } m_deserializer = MakeUnique<V1TransportDeserializer>(V1TransportDeserializer(Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION)); + m_serializer = MakeUnique<V1TransportSerializer>(V1TransportSerializer()); } CNode::~CNode() @@ -2720,16 +2734,12 @@ bool CConnman::NodeFullyConnected(const CNode* pnode) void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) { size_t nMessageSize = msg.data.size(); - size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE; LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command), nMessageSize, pnode->GetId()); + // make sure we use the appropriate network transport format std::vector<unsigned char> serializedHeader; - serializedHeader.reserve(CMessageHeader::HEADER_SIZE); - uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize); - CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize); - memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); - - CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr}; + pnode->m_serializer->prepareForTransport(msg, serializedHeader); + size_t nTotalSize = nMessageSize + serializedHeader.size(); size_t nBytesSent = 0; { @@ -703,12 +703,27 @@ public: CNetMessage GetMessage(const CMessageHeader::MessageStartChars& message_start, int64_t time) override; }; +/** The TransportSerializer prepares messages for the network transport + */ +class TransportSerializer { +public: + // prepare message for transport (header construction, error-correction computation, payload encryption, etc.) + virtual void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) = 0; + virtual ~TransportSerializer() {} +}; + +class V1TransportSerializer : public TransportSerializer { +public: + void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) override; +}; + /** Information about a peer */ class CNode { friend class CConnman; public: std::unique_ptr<TransportDeserializer> m_deserializer; + std::unique_ptr<TransportSerializer> m_serializer; // socket std::atomic<ServiceFlags> nServices{NODE_NONE}; diff --git a/src/randomenv.cpp b/src/randomenv.cpp index 6992c720ff..8b3d478529 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -38,11 +38,6 @@ #include <sys/utsname.h> #include <unistd.h> #endif -#ifdef __MACH__ -#include <mach/clock.h> -#include <mach/mach.h> -#include <mach/mach_time.h> -#endif #if HAVE_DECL_GETIFADDRS #include <ifaddrs.h> #endif @@ -237,8 +232,6 @@ void RandAddDynamicEnv(CSHA512& hasher) GetSystemTimeAsFileTime(&ftime); hasher << ftime; #else -# ifndef __MACH__ - // On non-MacOS systems, use various clock_gettime() calls. struct timespec ts = {}; # ifdef CLOCK_MONOTONIC clock_gettime(CLOCK_MONOTONIC, &ts); @@ -252,18 +245,6 @@ void RandAddDynamicEnv(CSHA512& hasher) clock_gettime(CLOCK_BOOTTIME, &ts); hasher << ts; # endif -# else - // On MacOS use mach_absolute_time (number of CPU ticks since boot) as a replacement for CLOCK_MONOTONIC, - // and clock_get_time for CALENDAR_CLOCK as a replacement for CLOCK_REALTIME. - hasher << mach_absolute_time(); - // From https://gist.github.com/jbenet/1087739 - clock_serv_t cclock; - mach_timespec_t mts = {}; - if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock) == KERN_SUCCESS && clock_get_time(cclock, &mts) == KERN_SUCCESS) { - hasher << mts; - mach_port_deallocate(mach_task_self(), cclock); - } -# endif // gettimeofday is available on all UNIX systems, but only has microsecond precision. struct timeval tv = {}; gettimeofday(&tv, nullptr); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index bcf4033fe4..44d4e0890a 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -22,6 +22,7 @@ #include <script/standard.h> #include <streams.h> #include <util/strencodings.h> +#include <test/util/transaction_utils.h> #include <map> #include <string> @@ -280,50 +281,13 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) BOOST_CHECK_MESSAGE(!CheckTransaction(CTransaction(tx), state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); } -// -// Helper: create two dummy transactions, each with -// two outputs. The first has 11 and 50 CENT outputs -// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs -// paid to a TX_PUBKEYHASH. -// -static std::vector<CMutableTransaction> -SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet) -{ - std::vector<CMutableTransaction> dummyTransactions; - dummyTransactions.resize(2); - - // Add some keys to the keystore: - CKey key[4]; - for (int i = 0; i < 4; i++) - { - key[i].MakeNewKey(i % 2); - keystoreRet.AddKey(key[i]); - } - - // Create some dummy input transactions - dummyTransactions[0].vout.resize(2); - dummyTransactions[0].vout[0].nValue = 11*CENT; - dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - dummyTransactions[0].vout[1].nValue = 50*CENT; - dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; - AddCoins(coinsRet, CTransaction(dummyTransactions[0]), 0); - - dummyTransactions[1].vout.resize(2); - dummyTransactions[1].vout[0].nValue = 21*CENT; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); - dummyTransactions[1].vout[1].nValue = 22*CENT; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); - AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); - - return dummyTransactions; -} - BOOST_AUTO_TEST_CASE(test_Get) { FillableSigningProvider keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); - std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); + std::vector<CMutableTransaction> dummyTransactions = + SetupDummyInputs(keystore, coins, {11*CENT, 50*CENT, 21*CENT, 22*CENT}); CMutableTransaction t1; t1.vin.resize(3); @@ -683,7 +647,8 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) FillableSigningProvider keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); - std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); + std::vector<CMutableTransaction> dummyTransactions = + SetupDummyInputs(keystore, coins, {11*CENT, 50*CENT, 21*CENT, 22*CENT}); CMutableTransaction t; t.vin.resize(1); diff --git a/src/test/util/transaction_utils.cpp b/src/test/util/transaction_utils.cpp index 90b78effb0..999b803a8d 100644 --- a/src/test/util/transaction_utils.cpp +++ b/src/test/util/transaction_utils.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <test/util/transaction_utils.h> +#include <coins.h> +#include <script/signingprovider.h> CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int nValue) { @@ -37,3 +39,33 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSc return txSpend; } + +std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues) +{ + std::vector<CMutableTransaction> dummyTransactions; + dummyTransactions.resize(2); + + // Add some keys to the keystore: + CKey key[4]; + for (int i = 0; i < 4; i++) { + key[i].MakeNewKey(i % 2); + keystoreRet.AddKey(key[i]); + } + + // Create some dummy input transactions + dummyTransactions[0].vout.resize(2); + dummyTransactions[0].vout[0].nValue = nValues[0]; + dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; + dummyTransactions[0].vout[1].nValue = nValues[1]; + dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; + AddCoins(coinsRet, CTransaction(dummyTransactions[0]), 0); + + dummyTransactions[1].vout.resize(2); + dummyTransactions[1].vout[0].nValue = nValues[2]; + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); + dummyTransactions[1].vout[1].nValue = nValues[3]; + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); + AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); + + return dummyTransactions; +} diff --git a/src/test/util/transaction_utils.h b/src/test/util/transaction_utils.h index 57604646e7..f843928a5f 100644 --- a/src/test/util/transaction_utils.h +++ b/src/test/util/transaction_utils.h @@ -7,6 +7,11 @@ #include <primitives/transaction.h> +#include <array> + +class FillableSigningProvider; +class CCoinsViewCache; + // create crediting transaction // [1 coinbase input => 1 output with given scriptPubkey and value] CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int nValue = 0); @@ -16,4 +21,9 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int n // 1 output with empty scriptPubKey, full value of referenced transaction] CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit); +// Helper: create two dummy transactions, each with two outputs. +// The first has nValues[0] and nValues[1] outputs paid to a TX_PUBKEY, +// the second nValues[2] and nValues[3] outputs paid to a TX_PUBKEYHASH. +std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues); + #endif // BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index f86e713676..536ff3ba25 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1199,6 +1199,12 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_CHECK(ParseMoney("0.00000001", ret)); BOOST_CHECK_EQUAL(ret, COIN/100000000); + // Parsing amount that can not be represented in ret should fail + BOOST_CHECK(!ParseMoney("0.000000001", ret)); + + // Parsing empty string should fail + BOOST_CHECK(!ParseMoney("", ret)); + // Attempted 63 bit overflow should fail BOOST_CHECK(!ParseMoney("92233720368.54775808", ret)); diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp index 2797f450ca..40d8918dfc 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -36,14 +36,14 @@ bool ParseMoney(const std::string& str, CAmount& nRet) if (!ValidAsCString(str)) { return false; } - return ParseMoney(str.c_str(), nRet); -} -bool ParseMoney(const char* pszIn, CAmount& nRet) -{ + if (str.empty()) { + return false; + } + std::string strWhole; int64_t nUnits = 0; - const char* p = pszIn; + const char* p = str.c_str(); while (IsSpace(*p)) p++; for (; *p; p++) diff --git a/src/util/moneystr.h b/src/util/moneystr.h index 027c7e2e53..d8b08adc24 100644 --- a/src/util/moneystr.h +++ b/src/util/moneystr.h @@ -18,7 +18,7 @@ * JSON but use AmountFromValue and ValueFromAmount for that. */ std::string FormatMoney(const CAmount& n); +/** Parse an amount denoted in full coins. E.g. "0.0034" supplied on the command line. **/ NODISCARD bool ParseMoney(const std::string& str, CAmount& nRet); -NODISCARD bool ParseMoney(const char* pszIn, CAmount& nRet); #endif // BITCOIN_UTIL_MONEYSTR_H diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index d65a0e9075..21d57cb898 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -189,6 +189,19 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) actual_selection.clear(); selection.clear(); + // Cost of change is greater than the difference between target value and utxo sum + add_coin(1 * CENT, 1, actual_selection); + BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 0.9 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); + BOOST_CHECK_EQUAL(value_ret, 1 * CENT); + BOOST_CHECK(equal_sets(selection, actual_selection)); + actual_selection.clear(); + selection.clear(); + + // Cost of change is less than the difference between target value and utxo sum + BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 0.9 * CENT, 0, selection, value_ret, not_input_fees)); + actual_selection.clear(); + selection.clear(); + // Select 10 Cent add_coin(5 * CENT, 5, utxo_pool); add_coin(4 * CENT, 4, actual_selection); |