diff --git a/src/script.cpp b/src/script.cpp index 44eed93..6d4fb34 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -51,6 +51,7 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI vector vfExec; vector stack; vector altstack; + unsigned int nOpCount = 0; if (pvStackRet) pvStackRet->clear(); @@ -85,6 +86,13 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) return false; + // Counted outside fExec for the same reason: the cost of a script must + // not depend on which branch a signature happens to take. Pushes are + // exempt because their cost is already bounded by the script's own + // length and by MAX_SCRIPT_ELEMENT_SIZE. + if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) + return false; + if (fExec && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) @@ -824,6 +832,11 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI default: return false; } + + // Both stacks together, because OP_TOALTSTACK would otherwise move the + // problem rather than solve it. + if (stack.size() + altstack.size() > MAX_STACK_SIZE) + return false; } diff --git a/src/script.h b/src/script.h index 26bb65a..d36a317 100644 --- a/src/script.h +++ b/src/script.h @@ -8,6 +8,15 @@ class CTransaction; // script evaluation allocates whatever the transaction asks it to. static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; +// Bounds on what one script may do while being evaluated. The element cap +// above limits how big a single item is; these limit how many there can be and +// how much work producing them costs. Without them, a script pays for itself +// once, in bytes, and then multiplies: 520 bytes per stack entry means a +// script of N bytes made almost entirely of OP_DUP occupies roughly 520N in +// memory, and every node that validates it pays. +static const unsigned int MAX_OPS_PER_SCRIPT = 201; +static const unsigned int MAX_STACK_SIZE = 1000; + enum { SIGHASH_ALL = 1,