Skip to content

Commit 87c9b5c

Browse files
laanwjUdjinM6
authored andcommitted
Merge bitcoin#13309: Directly operate with CMutableTransaction in SignSignature
6b8b63a Generic TransactionSignatureCreator works with both CTransaction and CMutableTransaction (Martin Ankerl) Pull request description: Refactored `TransactionSignatureCreator` into a templated `GenericTransactionSignatureCreator` that works with both `CMutableTransaction` and `CTransaction`. The advantage is that now in `SignSignature`, the `MutableTransactionSignatureCreator` can now operate directly with the `CMutableTransaction` without the need to copy the data into a `CTransaction`. Running all unit tests brings a very noticable speedup on my machine: 48.4 sec before this change 36.4 sec with this change -------- 12.0 seconds saved running only `--run_test=transaction_tests/test_big_witness_transaction`: 16.7 sec before this change 5.9 sec with this change -------- 10.8 seconds saved This relates to my first attempt with the const_cast hack bitcoin#13202, and to the slow unit test issue bitcoin#10026. Also see bitcoin#13050 which modifies the tests but not the production code (like this PR) to get a speedup. Tree-SHA512: 2cff0e9699f484f26120a40e431a24c8bc8f9e780fd89cb0ecf20c5be3eab6c43f9c359cde244abd9f3620d06c7c354e3b9dd3da41fa2ca1ac1e09386fea25fb
1 parent faddce8 commit 87c9b5c

File tree

5 files changed

+61
-52
lines changed

5 files changed

+61
-52
lines changed

src/script/interpreter.cpp

+36-14
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
10321032
CSHA256()
10331033
.Write(vchMessage.data(), vchMessage.size())
10341034
.Finalize(vchHash.data());
1035-
fSuccess = checker.VerifySignature(vchSig, CPubKey(vchPubKey), uint256(vchHash));
1035+
fSuccess = CPubKey(vchPubKey).Verify(uint256(vchHash), vchSig);
10361036
}
10371037

10381038
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) {
@@ -1308,17 +1308,19 @@ namespace {
13081308
* Wrapper that serializes like CTransaction, but with the modifications
13091309
* required for the signature hash done in-place
13101310
*/
1311-
class CTransactionSignatureSerializer {
1311+
template <class T>
1312+
class CTransactionSignatureSerializer
1313+
{
13121314
private:
1313-
const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized)
1315+
const T& txTo; //!< reference to the spending transaction (the one being serialized)
13141316
const CScript& scriptCode; //!< output script being consumed
13151317
const unsigned int nIn; //!< input index of txTo being signed
13161318
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
13171319
const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
13181320
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
13191321

13201322
public:
1321-
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
1323+
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
13221324
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
13231325
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
13241326
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
@@ -1402,23 +1404,29 @@ class CTransactionSignatureSerializer {
14021404
}
14031405
};
14041406

1405-
uint256 GetPrevoutHash(const CTransaction& txTo) {
1407+
template <class T>
1408+
uint256 GetPrevoutHash(const T& txTo)
1409+
{
14061410
CHashWriter ss(SER_GETHASH, 0);
14071411
for (const auto& txin : txTo.vin) {
14081412
ss << txin.prevout;
14091413
}
14101414
return ss.GetHash();
14111415
}
14121416

1413-
uint256 GetSequenceHash(const CTransaction& txTo) {
1417+
template <class T>
1418+
uint256 GetSequenceHash(const T& txTo)
1419+
{
14141420
CHashWriter ss(SER_GETHASH, 0);
14151421
for (const auto& txin : txTo.vin) {
14161422
ss << txin.nSequence;
14171423
}
14181424
return ss.GetHash();
14191425
}
14201426

1421-
uint256 GetOutputsHash(const CTransaction& txTo) {
1427+
template <class T>
1428+
uint256 GetOutputsHash(const T& txTo)
1429+
{
14221430
CHashWriter ss(SER_GETHASH, 0);
14231431
for (const auto& txout : txTo.vout) {
14241432
ss << txout;
@@ -1428,14 +1436,20 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
14281436

14291437
} // namespace
14301438

1431-
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
1439+
template <class T>
1440+
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
14321441
{
14331442
hashPrevouts = GetPrevoutHash(txTo);
14341443
hashSequence = GetSequenceHash(txTo);
14351444
hashOutputs = GetOutputsHash(txTo);
14361445
}
14371446

1438-
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
1447+
// explicit instantiation
1448+
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
1449+
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
1450+
1451+
template <class T>
1452+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
14391453
{
14401454
assert(nIn < txTo.vin.size());
14411455

@@ -1450,20 +1464,22 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
14501464
}
14511465

14521466
// Wrapper to serialize only the necessary parts of the transaction being signed
1453-
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
1467+
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
14541468

14551469
// Serialize and hash
14561470
CHashWriter ss(SER_GETHASH, 0);
14571471
ss << txTmp << nHashType;
14581472
return ss.GetHash();
14591473
}
14601474

1461-
bool BaseSignatureChecker::VerifySignature(const std::vector<uint8_t>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
1475+
template <class T>
1476+
bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
14621477
{
14631478
return pubkey.Verify(sighash, vchSig);
14641479
}
14651480

1466-
bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
1481+
template <class T>
1482+
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
14671483
{
14681484
CPubKey pubkey(vchPubKey);
14691485
if (!pubkey.IsValid())
@@ -1484,7 +1500,8 @@ bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vch
14841500
return true;
14851501
}
14861502

1487-
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
1503+
template <class T>
1504+
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
14881505
{
14891506
// There are two kinds of nLockTime: lock-by-blockheight
14901507
// and lock-by-blocktime, distinguished by whether
@@ -1520,7 +1537,8 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
15201537
return true;
15211538
}
15221539

1523-
bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
1540+
template <class T>
1541+
bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSequence) const
15241542
{
15251543
// Relative lock times are supported by comparing the passed
15261544
// in operand to the sequence number of the input.
@@ -1566,6 +1584,10 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
15661584
return true;
15671585
}
15681586

1587+
// explicit instantiation
1588+
template class GenericTransactionSignatureChecker<CTransaction>;
1589+
template class GenericTransactionSignatureChecker<CMutableTransaction>;
1590+
15691591
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
15701592
{
15711593
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);

src/script/interpreter.h

+17-21
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,21 @@ struct PrecomputedTransactionData
110110
{
111111
uint256 hashPrevouts, hashSequence, hashOutputs;
112112

113-
explicit PrecomputedTransactionData(const CTransaction& tx);
113+
template <class T>
114+
explicit PrecomputedTransactionData(const T& tx);
114115
};
115116

116117
enum class SigVersion
117118
{
118119
BASE = 0,
119120
};
120121

121-
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
122+
template <class T>
123+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
122124

123125
class BaseSignatureChecker
124126
{
125127
public:
126-
virtual bool VerifySignature(const std::vector<uint8_t>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
127-
128128
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
129129
{
130130
return false;
@@ -143,33 +143,29 @@ class BaseSignatureChecker
143143
virtual ~BaseSignatureChecker() {}
144144
};
145145

146-
class TransactionSignatureChecker : public BaseSignatureChecker
146+
template <class T>
147+
class GenericTransactionSignatureChecker : public BaseSignatureChecker
147148
{
148149
private:
149-
const CTransaction* txTo;
150+
const T* txTo;
150151
unsigned int nIn;
151152
const CAmount amount;
152153
const PrecomputedTransactionData* txdata;
153154

154-
public:
155-
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
156-
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
157-
158-
// The overriden functions are now final.
159-
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const final;
160-
bool CheckLockTime(const CScriptNum& nLockTime) const final;
161-
bool CheckSequence(const CScriptNum& nSequence) const final;
162-
};
163-
164-
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
165-
{
166-
private:
167-
const CTransaction txTo;
155+
protected:
156+
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
168157

169158
public:
170-
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
159+
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
160+
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
161+
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
162+
bool CheckLockTime(const CScriptNum& nLockTime) const override;
163+
bool CheckSequence(const CScriptNum& nSequence) const override;
171164
};
172165

166+
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
167+
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
168+
173169
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
174170
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
175171

src/script/sign.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
typedef std::vector<unsigned char> valtype;
1616

17-
TransactionSignatureCreator::TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
17+
MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
1818

19-
bool TransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
19+
bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
2020
{
2121
CKey key;
2222
if (!provider.GetKey(address, key))
@@ -170,8 +170,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
170170
{
171171
assert(nIn < txTo.vin.size());
172172

173-
CTransaction txToConst(txTo);
174-
TransactionSignatureCreator creator(&txToConst, nIn, amount, nHashType);
173+
MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType);
175174

176175
SignatureData sigdata;
177176
bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);

src/script/sign.h

+4-11
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,19 @@ class BaseSignatureCreator {
3737
};
3838

3939
/** A signature creator for transactions. */
40-
class TransactionSignatureCreator : public BaseSignatureCreator {
41-
const CTransaction* txTo;
40+
class MutableTransactionSignatureCreator : public BaseSignatureCreator {
41+
const CMutableTransaction* txTo;
4242
unsigned int nIn;
4343
int nHashType;
4444
CAmount amount;
45-
const TransactionSignatureChecker checker;
45+
const MutableTransactionSignatureChecker checker;
4646

4747
public:
48-
TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
48+
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn = SIGHASH_ALL);
4949
const BaseSignatureChecker& Checker() const override{ return checker; }
5050
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
5151
};
5252

53-
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
54-
CTransaction tx;
55-
56-
public:
57-
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(&tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
58-
};
59-
6053
/** A signature creator that just produces 72-byte empty signatures. */
6154
extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
6255

src/wallet/wallet.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -3888,14 +3888,13 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
38883888

38893889
if (sign)
38903890
{
3891-
CTransaction txNewConst(txNew);
38923891
int nIn = 0;
38933892
for(const auto& coin : vecCoins)
38943893
{
38953894
const CScript& scriptPubKey = coin.txout.scriptPubKey;
38963895
SignatureData sigdata;
38973896

3898-
if (!ProduceSignature(*this, TransactionSignatureCreator(&txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
3897+
if (!ProduceSignature(*this, MutableTransactionSignatureCreator(&txNew, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
38993898
{
39003899
strFailReason = _("Signing transaction failed");
39013900
return false;

0 commit comments

Comments
 (0)