Skip to content

Commit 8f3aba0

Browse files
committed
SigOp counting in witnesses
1 parent b0f8ee9 commit 8f3aba0

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

src/main.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,19 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
739739
return nSigOps;
740740
}
741741

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

743756

744757

@@ -945,6 +958,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
945958

946959
unsigned int nSigOps = GetLegacySigOpCount(tx);
947960
nSigOps += GetP2SHSigOpCount(tx, view);
961+
nSigOps += (GetWitnessSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS) + 3) / 4;
962+
963+
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
964+
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
965+
strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS));
948966

949967
CAmount nValueOut = tx.GetValueOut();
950968
CAmount nFees = nValueIn-nValueOut;
@@ -2084,6 +2102,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
20842102
CAmount nFees = 0;
20852103
int nInputs = 0;
20862104
unsigned int nSigOps = 0;
2105+
unsigned int nWitSigOps = 0;
20872106
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
20882107
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
20892108
vPos.reserve(block.vtx.size());
@@ -2104,13 +2123,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
21042123
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
21052124
REJECT_INVALID, "bad-txns-inputs-missingorspent");
21062125

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

src/script/interpreter.cpp

Lines changed: 47 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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)