Merge #13011: Cache witness hash in CTransaction

fac1223a56 Cache witness hash in CTransaction (MarcoFalke)
faab55fbb1 Make CMutableTransaction constructor explicit (MarcoFalke)

Pull request description:

  This speeds up:
  * compactblocks (v2)
  * ATMP
  * validation and miner (via `BlockWitnessMerkleRoot`)
  * sigcache (see also unrelated #13204)
  * rpc and rest (nice, but irrelevant)

  This presumably slows down rescan, which uses a `CTransaction` and its `GetHash`, but never uses the `GetWitnessHash`. The slow down is proportional to the number of witness transactions in the rescan window. I.e. early in the chain there should be no measurable slow down. Later in the chain, there should be a slow down, but acceptable given the speedups in the modules mentioned above.

Tree-SHA512: 443e86acfcceb5af2163e68840c581d44159af3fd1fce266cab3504b29fcd74c50812b69a00d41582e7e1c5ea292f420ce5e892cdfab691da9c24ed1c44536c7
This commit is contained in:
Wladimir J. van der Laan 2018-05-23 19:04:25 +02:00
commit 3c2a41a9fc
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
8 changed files with 21 additions and 23 deletions

View file

@ -546,7 +546,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// mergedTx will end up with all the signatures; it // mergedTx will end up with all the signatures; it
// starts as a clone of the raw tx: // starts as a clone of the raw tx:
CMutableTransaction mergedTx{tx}; CMutableTransaction mergedTx{tx};
const CTransaction txv{tx}; const CMutableTransaction txv{tx};
CCoinsView viewDummy; CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy); CCoinsViewCache view(&viewDummy);

View file

@ -67,18 +67,18 @@ uint256 CTransaction::ComputeHash() const
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS); return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
} }
uint256 CTransaction::GetWitnessHash() const uint256 CTransaction::ComputeWitnessHash() const
{ {
if (!HasWitness()) { if (!HasWitness()) {
return GetHash(); return hash;
} }
return SerializeHash(*this, SER_GETHASH, 0); return SerializeHash(*this, SER_GETHASH, 0);
} }
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ /* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash() {} CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{} {}
CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {} CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {} CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
CAmount CTransaction::GetValueOut() const CAmount CTransaction::GetValueOut() const
{ {

View file

@ -286,8 +286,10 @@ public:
private: private:
/** Memory only. */ /** Memory only. */
const uint256 hash; const uint256 hash;
const uint256 m_witness_hash;
uint256 ComputeHash() const; uint256 ComputeHash() const;
uint256 ComputeWitnessHash() const;
public: public:
/** Construct a CTransaction that qualifies as IsNull() */ /** Construct a CTransaction that qualifies as IsNull() */
@ -311,12 +313,8 @@ public:
return vin.empty() && vout.empty(); return vin.empty() && vout.empty();
} }
const uint256& GetHash() const { const uint256& GetHash() const { return hash; }
return hash; const uint256& GetWitnessHash() const { return m_witness_hash; };
}
// Compute a hash that includes both transaction and witness data
uint256 GetWitnessHash() const;
// Return sum of txouts. // Return sum of txouts.
CAmount GetValueOut() const; CAmount GetValueOut() const;
@ -367,7 +365,7 @@ struct CMutableTransaction
uint32_t nLockTime; uint32_t nLockTime;
CMutableTransaction(); CMutableTransaction();
CMutableTransaction(const CTransaction& tx); explicit CMutableTransaction(const CTransaction& tx);
template <typename Stream> template <typename Stream>
inline void Serialize(Stream& s) const { inline void Serialize(Stream& s) const {

View file

@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
if (InsecureRandRange(10) == 0 && coinbase_coins.size()) { if (InsecureRandRange(10) == 0 && coinbase_coins.size()) {
auto utxod = FindRandomFrom(coinbase_coins); auto utxod = FindRandomFrom(coinbase_coins);
// Reuse the exact same coinbase // Reuse the exact same coinbase
tx = std::get<0>(utxod->second); tx = CMutableTransaction{std::get<0>(utxod->second)};
// shouldn't be available for reconnection if it's been duplicated // shouldn't be available for reconnection if it's been duplicated
disconnected_coins.erase(utxod->first); disconnected_coins.erase(utxod->first);
@ -331,7 +331,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// 1/20 times reconnect a previously disconnected tx // 1/20 times reconnect a previously disconnected tx
if (randiter % 20 == 2 && disconnected_coins.size()) { if (randiter % 20 == 2 && disconnected_coins.size()) {
auto utxod = FindRandomFrom(disconnected_coins); auto utxod = FindRandomFrom(disconnected_coins);
tx = std::get<0>(utxod->second); tx = CMutableTransaction{std::get<0>(utxod->second)};
prevout = tx.vin[0].prevout; prevout = tx.vin[0].prevout;
if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) { if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
disconnected_coins.erase(utxod->first); disconnected_coins.erase(utxod->first);

View file

@ -137,7 +137,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int n
return txCredit; return txCredit;
} }
CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CMutableTransaction& txCredit) CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit)
{ {
CMutableTransaction txSpend; CMutableTransaction txSpend;
txSpend.nVersion = 1; txSpend.nVersion = 1;
@ -163,7 +163,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
flags |= SCRIPT_VERIFY_WITNESS; flags |= SCRIPT_VERIFY_WITNESS;
} }
ScriptError err; ScriptError err;
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue); const CTransaction txCredit{BuildCreditingTransaction(scriptPubKey, nValue)};
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, scriptWitness, txCredit); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, scriptWitness, txCredit);
CMutableTransaction tx2 = tx; CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
@ -1073,7 +1073,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12; CScript scriptPubKey12;
scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); const CTransaction txFrom12{BuildCreditingTransaction(scriptPubKey12)};
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
@ -1104,7 +1104,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23; CScript scriptPubKey23;
scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23); const CTransaction txFrom23{BuildCreditingTransaction(scriptPubKey23)};
CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom23); CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom23);
std::vector<CKey> keys; std::vector<CKey> keys;

View file

@ -24,7 +24,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests) BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
static bool static bool
ToMemPool(CMutableTransaction& tx) ToMemPool(const CMutableTransaction& tx)
{ {
LOCK(cs_main); LOCK(cs_main);

View file

@ -185,7 +185,7 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
// If the output is not large enough to pay the fee, fail. // If the output is not large enough to pay the fee, fail.
CAmount nDelta = new_fee - old_fee; CAmount nDelta = new_fee - old_fee;
assert(nDelta > 0); assert(nDelta > 0);
mtx = *wtx.tx; mtx = CMutableTransaction{*wtx.tx};
CTxOut* poutput = &(mtx.vout[nOutput]); CTxOut* poutput = &(mtx.vout[nOutput]);
if (poutput->nValue < nDelta) { if (poutput->nValue < nDelta) {
errors.push_back("Change output is too small to bump the fee"); errors.push_back("Change output is too small to bump the fee");

View file

@ -2075,8 +2075,8 @@ bool CWalletTx::IsTrusted() const
bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{ {
CMutableTransaction tx1 = *this->tx; CMutableTransaction tx1 {*this->tx};
CMutableTransaction tx2 = *_tx.tx; CMutableTransaction tx2 {*_tx.tx};
for (auto& txin : tx1.vin) txin.scriptSig = CScript(); for (auto& txin : tx1.vin) txin.scriptSig = CScript();
for (auto& txin : tx2.vin) txin.scriptSig = CScript(); for (auto& txin : tx2.vin) txin.scriptSig = CScript();
return CTransaction(tx1) == CTransaction(tx2); return CTransaction(tx1) == CTransaction(tx2);