diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -98,6 +98,34 @@ return false; } +namespace { +/** + * A data type to abstract out the condition stack during script execution. + * + * Conceptually it acts like a vector of booleans, one for each level of nested + * IF/THEN/ELSE, indicating whether we're in the active or inactive branch of + * each. + * + * The elements on the stack cannot be observed individually; we only need to + * expose whether the stack is empty and whether or not any false values are + * present at all. To implement OP_ELSE, a toggle_top modifier is added, which + * flips the last value without returning it. + */ +class ConditionStack { +private: + std::vector m_flags; + +public: + bool empty() { return m_flags.empty(); } + bool all_true() { + return !std::count(m_flags.begin(), m_flags.end(), false); + } + void push_back(bool f) { m_flags.push_back(f); } + void pop_back() { m_flags.pop_back(); } + void toggle_top() { m_flags.back() = !m_flags.back(); } +}; +} // namespace + bool EvalScript(std::vector &stack, const CScript &script, uint32_t flags, const BaseSignatureChecker &checker, ScriptExecutionMetrics &metrics, ScriptError *serror) { @@ -111,7 +139,7 @@ CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; - std::vector vfExec; + ConditionStack vfExec; std::vector altstack; set_error(serror, ScriptError::UNKNOWN); if (script.size() > MAX_SCRIPT_SIZE) { @@ -122,7 +150,7 @@ try { while (pc < pend) { - bool fExec = !count(vfExec.begin(), vfExec.end(), false); + bool fExec = vfExec.all_true(); // // Read instruction @@ -324,7 +352,7 @@ return set_error( serror, ScriptError::UNBALANCED_CONDITIONAL); } - vfExec.back() = !vfExec.back(); + vfExec.toggle_top(); } break; case OP_ENDIF: {