diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/addrman.cpp | 10 | ||||
-rw-r--r-- | src/hash.h | 10 | ||||
-rw-r--r-- | src/test/addrman_tests.cpp | 2 | ||||
-rw-r--r-- | src/uint256.h | 11 | ||||
-rw-r--r-- | src/validation.h | 6 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 44 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 11 | ||||
-rw-r--r-- | src/wallet/wallet.h | 3 |
8 files changed, 76 insertions, 21 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp index 093b263ab3..44328c3056 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -11,22 +11,22 @@ int CAddrInfo::GetTriedBucket(const uint256& nKey) const { - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash(); - uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash(); + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash(); + uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash(); return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; } int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const { std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(); - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetHash().GetCheapHash(); - uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash(); + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetCheapHash(); + uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash(); return hash2 % ADDRMAN_NEW_BUCKET_COUNT; } int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const { - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash(); + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetCheapHash(); return hash1 % ADDRMAN_BUCKET_SIZE; } diff --git a/src/hash.h b/src/hash.h index 6acab0b161..c295568a3e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_HASH_H #define BITCOIN_HASH_H +#include <crypto/common.h> #include <crypto/ripemd160.h> #include <crypto/sha256.h> #include <prevector.h> @@ -138,6 +139,15 @@ public: return result; } + /** + * Returns the first 64 bits from the resulting hash. + */ + inline uint64_t GetCheapHash() { + unsigned char result[CHash256::OUTPUT_SIZE]; + ctx.Finalize(result); + return ReadLE64(result); + } + template<typename T> CHashWriter& operator<<(const T& obj) { // Serialize to this stream diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 8c2873d916..55fe19cebe 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -34,7 +34,7 @@ public: int RandomInt(int nMax) override { - state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash(); + state = (CHashWriter(SER_GETHASH, 0) << state).GetCheapHash(); return (unsigned int)(state % nMax); } diff --git a/src/uint256.h b/src/uint256.h index 26a3331d92..97e0cfa015 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -12,7 +12,6 @@ #include <stdint.h> #include <string> #include <vector> -#include <crypto/common.h> /** Template base class for fixed-sized opaque blobs. */ template<unsigned int BITS> @@ -123,16 +122,6 @@ class uint256 : public base_blob<256> { public: uint256() {} explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {} - - /** A cheap hash function that just returns 64 bits from the result, it can be - * used when the contents are considered uniformly random. It is not appropriate - * when the value can easily be influenced from outside as e.g. a network adversary could - * provide values to trigger worst-case behavior. - */ - uint64_t GetCheapHash() const - { - return ReadLE64(data); - } }; /* uint256 from const char *. diff --git a/src/validation.h b/src/validation.h index 3e98ebc866..b5548a9293 100644 --- a/src/validation.h +++ b/src/validation.h @@ -12,6 +12,7 @@ #include <amount.h> #include <coins.h> +#include <crypto/common.h> // for ReadLE64 #include <fs.h> #include <protocol.h> // For CMessageHeader::MessageStartChars #include <policy/feerate.h> @@ -138,7 +139,10 @@ static const int DEFAULT_STOPATHEIGHT = 0; struct BlockHasher { - size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } + // this used to call `GetCheapHash()` in uint256, which was later moved; the + // cheap hash function simply calls ReadLE64() however, so the end result is + // identical + size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } }; extern CScript COINBASE_FLAGS; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index c6aac8aad5..623c5c39a2 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -17,6 +17,7 @@ #include <validation.h> #include <wallet/coincontrol.h> #include <wallet/test/wallet_test_fixture.h> +#include <policy/policy.h> #include <boost/test/unit_test.hpp> #include <univalue.h> @@ -394,4 +395,47 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false)); } +// Explicit calculation which is used to test the wallet constant +// We get the same virtual size due to rounding(weight/4) for both use_max_sig values +static size_t CalculateNestedKeyhashInputSize(bool use_max_sig) +{ + // Generate ephemeral valid pubkey + CKey key; + key.MakeNewKey(true); + CPubKey pubkey = key.GetPubKey(); + + // Generate pubkey hash + uint160 key_hash(Hash160(pubkey.begin(), pubkey.end())); + + // Create inner-script to enter into keystore. Key hash can't be 0... + CScript inner_script = CScript() << OP_0 << std::vector<unsigned char>(key_hash.begin(), key_hash.end()); + + // Create outer P2SH script for the output + uint160 script_id(Hash160(inner_script.begin(), inner_script.end())); + CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL; + + // Add inner-script to key store and key to watchonly + CBasicKeyStore keystore; + keystore.AddCScript(inner_script); + keystore.AddKeyPubKey(key, pubkey); + + // Fill in dummy signatures for fee calculation. + SignatureData sig_data; + + if (!ProduceSignature(keystore, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, script_pubkey, sig_data)) { + // We're hand-feeding it correct arguments; shouldn't happen + assert(false); + } + + CTxIn tx_in; + UpdateInput(tx_in, sig_data); + return (size_t)GetVirtualTransactionInputSize(tx_in); +} + +BOOST_FIXTURE_TEST_CASE(dummy_input_size_test, TestChain100Setup) +{ + BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(false), DUMMY_NESTED_P2WPKH_INPUT_SIZE); + BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(true), DUMMY_NESTED_P2WPKH_INPUT_SIZE); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 360d0f177c..d7798e005f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1530,8 +1530,6 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, CMutableTransaction txn; txn.vin.push_back(CTxIn(COutPoint())); if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) { - // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) - // implies that we can sign for every input. return -1; } return GetVirtualTransactionInputSize(txn.vin[0]); @@ -2755,7 +2753,14 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std if (pick_new_inputs) { nValueIn = 0; setCoins.clear(); - coin_selection_params.change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, this); + int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, this); + // If the wallet doesn't know how to sign change output, assume p2sh-p2wpkh + // as lower-bound to allow BnB to do it's thing + if (change_spend_size == -1) { + coin_selection_params.change_spend_size = DUMMY_NESTED_P2WPKH_INPUT_SIZE; + } else { + coin_selection_params.change_spend_size = (size_t)change_spend_size; + } coin_selection_params.effective_fee = nFeeRateNeeded; if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coin_control, coin_selection_params, bnb_used)) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f96798201f..4291163bea 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -85,6 +85,9 @@ static const bool DEFAULT_WALLET_RBF = false; static const bool DEFAULT_WALLETBROADCAST = true; static const bool DEFAULT_DISABLE_WALLET = false; +//! Pre-calculated constants for input size estimation in *virtual size* +static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91; + class CBlockIndex; class CCoinControl; class COutput; |