diff --git a/src/script/script.cpp b/src/script/script.cpp index d650db9a0d..619716bb8e 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -303,6 +303,53 @@ bool CScript::HasValidOps() const return true; } +size_t CScript::DummyScriptBytes() const +{ + size_t counted{0}; + opcodetype opcode, last_opcode{OP_INVALIDOPCODE}; + std::vector push_data; + unsigned int inside_noop{0}, inside_conditional{0}; + CScript::const_iterator opcode_it = begin(), data_began = begin(); + for (CScript::const_iterator it = begin(); it < end(); last_opcode = opcode) { + opcode_it = it; + if (!GetOp(it, opcode, push_data)) { + // Invalid scripts are necessarily all data + return size(); + } + + if (opcode == OP_IF || opcode == OP_NOTIF) { + ++inside_conditional; + } else if (opcode == OP_ENDIF) { + if (!inside_conditional) return size(); // invalid + --inside_conditional; + } + + // Match OP_FALSE OP_IF + if (inside_noop) { + switch (opcode) { + case OP_IF: case OP_NOTIF: + ++inside_noop; + break; + case OP_ENDIF: + if (0 == --inside_noop) { + counted += it - data_began + 1; + } + break; + default: /* do nothing */; + } + } else if (opcode == OP_IF && last_opcode == OP_FALSE) { + inside_noop = 1; + data_began = opcode_it; + // Match OP_DROP + } else if (opcode <= OP_PUSHDATA4) { + data_began = opcode_it; + } else if (opcode == OP_DROP && last_opcode <= OP_PUSHDATA4) { + counted += it - data_began; + } + } + return counted; +} + bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector* pvchRet) { opcodeRet = OP_INVALIDOPCODE; diff --git a/src/script/script.h b/src/script/script.h index f457984980..72fd6a483a 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -573,6 +573,8 @@ public: return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE); } + size_t DummyScriptBytes() const; + void clear() { // The default prevector::clear() does not release memory