Skip to content

Commit d088262

Browse files
committed
SigOp counting in witnesses
1 parent b0aa377 commit d088262

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
@@ -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

@@ -940,6 +953,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
940953

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

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

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

src/script/interpreter.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,3 +1373,50 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
13731373

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

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)