Skip to content

Commit 3f75cf7

Browse files
committed
SigOp counting in witnesses
1 parent 770c917 commit 3f75cf7

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

src/main.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,19 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
738738
return nSigOps;
739739
}
740740

741+
unsigned int GetWitnessSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
742+
{
743+
if (tx.IsCoinBase())
744+
return 0;
745+
746+
unsigned int nSigOps = 0;
747+
for (unsigned int i = 0; i < tx.vin.size(); i++)
748+
{
749+
const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
750+
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, i < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[i].scriptWitness : NULL, flags);
751+
}
752+
return nSigOps;
753+
}
741754

742755

743756

@@ -941,6 +954,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
941954

942955
unsigned int nSigOps = GetLegacySigOpCount(tx);
943956
nSigOps += GetP2SHSigOpCount(tx, view);
957+
nSigOps += (GetWitnessSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS) + 3) / 4;
958+
959+
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
960+
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
961+
strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS));
944962

945963
CAmount nValueOut = tx.GetValueOut();
946964
CAmount nFees = nValueIn-nValueOut;
@@ -2080,6 +2098,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
20802098
CAmount nFees = 0;
20812099
int nInputs = 0;
20822100
unsigned int nSigOps = 0;
2101+
unsigned int nWitSigOps = 0;
20832102
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
20842103
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
20852104
vPos.reserve(block.vtx.size());
@@ -2100,13 +2119,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
21002119
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
21012120
REJECT_INVALID, "bad-txns-inputs-missingorspent");
21022121

2122+
nWitSigOps += GetWitnessSigOpCount(tx, view, flags);
2123+
21032124
if (fStrictPayToScriptHash)
21042125
{
21052126
// Add in sigops done by pay-to-script-hash inputs;
21062127
// this is to prevent a "rogue miner" from creating
21072128
// an incredibly-expensive-to-validate block.
21082129
nSigOps += GetP2SHSigOpCount(tx, view);
2109-
if (nSigOps > MAX_BLOCK_SIGOPS)
2130+
if (nSigOps + (nWitSigOps + 3) / 4 > MAX_BLOCK_SIGOPS)
21102131
return state.DoS(100, error("ConnectBlock(): too many sigops"),
21112132
REJECT_INVALID, "bad-blk-sigops");
21122133
}

src/script/interpreter.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -1369,3 +1369,50 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
13691369

13701370
return set_success(serror);
13711371
}
1372+
1373+
size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness, int flags)
1374+
{
1375+
if (witversion == 0) {
1376+
CScript script(witprogram.begin(), witprogram.end());
1377+
return script.GetSigOpCount(true);
1378+
}
1379+
1380+
if (witversion == 1 && witness.stack.size() > 0) {
1381+
CScript subscript(witness.stack.back().begin(), witness.stack.back().end());
1382+
return subscript.GetSigOpCount(true);
1383+
}
1384+
1385+
// Future flags may be implemented here.
1386+
return 0;
1387+
}
1388+
1389+
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
1390+
{
1391+
static const CScriptWitness witnessEmpty;
1392+
1393+
if ((flags & SCRIPT_VERIFY_WITNESS) == 0) {
1394+
return 0;
1395+
}
1396+
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
1397+
1398+
int witnessversion;
1399+
std::vector<unsigned char> witnessprogram;
1400+
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
1401+
return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
1402+
}
1403+
1404+
if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {
1405+
CScript::const_iterator pc = scriptSig.begin();
1406+
vector<unsigned char> data;
1407+
while (pc < scriptSig.end()) {
1408+
opcodetype opcode;
1409+
scriptSig.GetOp(pc, opcode, data);
1410+
}
1411+
CScript subscript(data.begin(), data.end());
1412+
if (subscript.IsWitnessProgram(witnessversion, witnessprogram)) {
1413+
return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
1414+
}
1415+
}
1416+
1417+
return 0;
1418+
}

src/script/interpreter.h

+2
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,6 @@ class MutableTransactionSignatureChecker : public TransactionSignatureChecker
139139
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, int sigversion, ScriptError* error = NULL);
140140
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL);
141141

142+
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
143+
142144
#endif // BITCOIN_SCRIPT_INTERPRETER_H

0 commit comments

Comments
 (0)