Skip to content

Commit

Permalink
SigOp counting in witnesses
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Jan 11, 2016
1 parent ef0b9ab commit 0f9efb0
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,19 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps;
}

unsigned int GetWitnessSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
{
if (tx.IsCoinBase())
return 0;

unsigned int nSigOps = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, i < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[i].scriptWitness : NULL, flags);
}
return nSigOps;
}



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

unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
nSigOps += (GetWitnessSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS) + 3) / 4;

if (nSigOps > MAX_STANDARD_TX_SIGOPS)
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS));

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

nWitSigOps += GetWitnessSigOpCount(tx, view, flags);

if (fStrictPayToScriptHash)
{
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS)
if (nSigOps + (nWitSigOps + 3) / 4 > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
}
Expand Down
47 changes: 47 additions & 0 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,3 +1369,50 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C

return set_success(serror);
}

size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness, int flags)
{
if (witversion == 0) {
CScript script(witprogram.begin(), witprogram.end());
return script.GetSigOpCount(true);
}

if (witversion == 1 && witness.stack.size() > 0) {
CScript subscript(witness.stack.back().begin(), witness.stack.back().end());
return subscript.GetSigOpCount(true);
}

// Future flags may be implemented here.
return 0;
}

size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
{
static const CScriptWitness witnessEmpty;

if ((flags & SCRIPT_VERIFY_WITNESS) == 0) {
return 0;
}
assert((flags & SCRIPT_VERIFY_P2SH) != 0);

int witnessversion;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
}

if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {
CScript::const_iterator pc = scriptSig.begin();
vector<unsigned char> data;
while (pc < scriptSig.end()) {
opcodetype opcode;
scriptSig.GetOp(pc, opcode, data);
}
CScript subscript(data.begin(), data.end());
if (subscript.IsWitnessProgram(witnessversion, witnessprogram)) {
return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
}
}

return 0;
}
2 changes: 2 additions & 0 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,6 @@ class MutableTransactionSignatureChecker : public TransactionSignatureChecker
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, int sigversion, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL);

size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);

#endif // BITCOIN_SCRIPT_INTERPRETER_H

0 comments on commit 0f9efb0

Please sign in to comment.