Skip to content

Commit 6b8b63a

Browse files
committed
Generic TransactionSignatureCreator works with both CTransaction and CMutableTransaction
Templated version so that no copying of CMutableTransaction into a CTransaction is necessary. This speeds up the test case transaction_tests/test_big_witness_transaction from 7.9 seconds to 3.1 seconds on my machine.
1 parent d792e47 commit 6b8b63a

File tree

5 files changed

+55
-46
lines changed

5 files changed

+55
-46
lines changed

src/script/interpreter.cpp

+35-13
Original file line numberDiff line numberDiff line change
@@ -1089,17 +1089,19 @@ namespace {
10891089
* Wrapper that serializes like CTransaction, but with the modifications
10901090
* required for the signature hash done in-place
10911091
*/
1092-
class CTransactionSignatureSerializer {
1092+
template <class T>
1093+
class CTransactionSignatureSerializer
1094+
{
10931095
private:
1094-
const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized)
1096+
const T& txTo; //!< reference to the spending transaction (the one being serialized)
10951097
const CScript& scriptCode; //!< output script being consumed
10961098
const unsigned int nIn; //!< input index of txTo being signed
10971099
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
10981100
const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
10991101
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
11001102

11011103
public:
1102-
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
1104+
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
11031105
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
11041106
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
11051107
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
@@ -1180,23 +1182,29 @@ class CTransactionSignatureSerializer {
11801182
}
11811183
};
11821184

1183-
uint256 GetPrevoutHash(const CTransaction& txTo) {
1185+
template <class T>
1186+
uint256 GetPrevoutHash(const T& txTo)
1187+
{
11841188
CHashWriter ss(SER_GETHASH, 0);
11851189
for (const auto& txin : txTo.vin) {
11861190
ss << txin.prevout;
11871191
}
11881192
return ss.GetHash();
11891193
}
11901194

1191-
uint256 GetSequenceHash(const CTransaction& txTo) {
1195+
template <class T>
1196+
uint256 GetSequenceHash(const T& txTo)
1197+
{
11921198
CHashWriter ss(SER_GETHASH, 0);
11931199
for (const auto& txin : txTo.vin) {
11941200
ss << txin.nSequence;
11951201
}
11961202
return ss.GetHash();
11971203
}
11981204

1199-
uint256 GetOutputsHash(const CTransaction& txTo) {
1205+
template <class T>
1206+
uint256 GetOutputsHash(const T& txTo)
1207+
{
12001208
CHashWriter ss(SER_GETHASH, 0);
12011209
for (const auto& txout : txTo.vout) {
12021210
ss << txout;
@@ -1206,7 +1214,8 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
12061214

12071215
} // namespace
12081216

1209-
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
1217+
template <class T>
1218+
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
12101219
{
12111220
// Cache is calculated only for transactions with witness
12121221
if (txTo.HasWitness()) {
@@ -1217,7 +1226,12 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
12171226
}
12181227
}
12191228

1220-
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
1229+
// explicit instantiation
1230+
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
1231+
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
1232+
1233+
template <class T>
1234+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
12211235
{
12221236
assert(nIn < txTo.vin.size());
12231237

@@ -1278,20 +1292,22 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
12781292
}
12791293

12801294
// Wrapper to serialize only the necessary parts of the transaction being signed
1281-
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
1295+
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
12821296

12831297
// Serialize and hash
12841298
CHashWriter ss(SER_GETHASH, 0);
12851299
ss << txTmp << nHashType;
12861300
return ss.GetHash();
12871301
}
12881302

1289-
bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
1303+
template <class T>
1304+
bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
12901305
{
12911306
return pubkey.Verify(sighash, vchSig);
12921307
}
12931308

1294-
bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
1309+
template <class T>
1310+
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
12951311
{
12961312
CPubKey pubkey(vchPubKey);
12971313
if (!pubkey.IsValid())
@@ -1312,7 +1328,8 @@ bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vch
13121328
return true;
13131329
}
13141330

1315-
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
1331+
template <class T>
1332+
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
13161333
{
13171334
// There are two kinds of nLockTime: lock-by-blockheight
13181335
// and lock-by-blocktime, distinguished by whether
@@ -1348,7 +1365,8 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
13481365
return true;
13491366
}
13501367

1351-
bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
1368+
template <class T>
1369+
bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSequence) const
13521370
{
13531371
// Relative lock times are supported by comparing the passed
13541372
// in operand to the sequence number of the input.
@@ -1394,6 +1412,10 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
13941412
return true;
13951413
}
13961414

1415+
// explicit instantiation
1416+
template class GenericTransactionSignatureChecker<CTransaction>;
1417+
template class GenericTransactionSignatureChecker<CMutableTransaction>;
1418+
13971419
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
13981420
{
13991421
std::vector<std::vector<unsigned char> > stack;

src/script/interpreter.h

+11-14
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ struct PrecomputedTransactionData
124124
uint256 hashPrevouts, hashSequence, hashOutputs;
125125
bool ready = false;
126126

127-
explicit PrecomputedTransactionData(const CTransaction& tx);
127+
template <class T>
128+
explicit PrecomputedTransactionData(const T& tx);
128129
};
129130

130131
enum class SigVersion
@@ -137,7 +138,8 @@ enum class SigVersion
137138
static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32;
138139
static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20;
139140

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

142144
class BaseSignatureChecker
143145
{
@@ -160,10 +162,11 @@ class BaseSignatureChecker
160162
virtual ~BaseSignatureChecker() {}
161163
};
162164

163-
class TransactionSignatureChecker : public BaseSignatureChecker
165+
template <class T>
166+
class GenericTransactionSignatureChecker : public BaseSignatureChecker
164167
{
165168
private:
166-
const CTransaction* txTo;
169+
const T* txTo;
167170
unsigned int nIn;
168171
const CAmount amount;
169172
const PrecomputedTransactionData* txdata;
@@ -172,21 +175,15 @@ class TransactionSignatureChecker : public BaseSignatureChecker
172175
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
173176

174177
public:
175-
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
176-
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
178+
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
179+
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
177180
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
178181
bool CheckLockTime(const CScriptNum& nLockTime) const override;
179182
bool CheckSequence(const CScriptNum& nSequence) const override;
180183
};
181184

182-
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
183-
{
184-
private:
185-
const CTransaction txTo;
186-
187-
public:
188-
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : TransactionSignatureChecker(&txTo, nInIn, amountIn), txTo(*txToIn) {}
189-
};
185+
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
186+
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
190187

191188
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
192189
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);

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))
@@ -209,8 +209,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
209209
{
210210
assert(nIn < txTo.vin.size());
211211

212-
CTransaction txToConst(txTo);
213-
TransactionSignatureCreator creator(&txToConst, nIn, amount, nHashType);
212+
MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType);
214213

215214
SignatureData sigdata;
216215
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& amountIn, int nHashTypeIn) : TransactionSignatureCreator(&tx, nInIn, amountIn, 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

+2-4
Original file line numberDiff line numberDiff line change
@@ -2608,7 +2608,6 @@ bool CWallet::SignTransaction(CMutableTransaction &tx)
26082608
AssertLockHeld(cs_wallet); // mapWallet
26092609

26102610
// sign the new tx
2611-
CTransaction txNewConst(tx);
26122611
int nIn = 0;
26132612
for (const auto& input : tx.vin) {
26142613
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(input.prevout.hash);
@@ -2618,7 +2617,7 @@ bool CWallet::SignTransaction(CMutableTransaction &tx)
26182617
const CScript& scriptPubKey = mi->second.tx->vout[input.prevout.n].scriptPubKey;
26192618
const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue;
26202619
SignatureData sigdata;
2621-
if (!ProduceSignature(*this, TransactionSignatureCreator(&txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
2620+
if (!ProduceSignature(*this, MutableTransactionSignatureCreator(&tx, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
26222621
return false;
26232622
}
26242623
UpdateTransaction(tx, nIn, sigdata);
@@ -3040,14 +3039,13 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
30403039

30413040
if (sign)
30423041
{
3043-
CTransaction txNewConst(txNew);
30443042
int nIn = 0;
30453043
for (const auto& coin : selected_coins)
30463044
{
30473045
const CScript& scriptPubKey = coin.txout.scriptPubKey;
30483046
SignatureData sigdata;
30493047

3050-
if (!ProduceSignature(*this, TransactionSignatureCreator(&txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
3048+
if (!ProduceSignature(*this, MutableTransactionSignatureCreator(&txNew, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
30513049
{
30523050
strFailReason = _("Signing transaction failed");
30533051
return false;

0 commit comments

Comments
 (0)