Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | switch (opcode) { | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
return false; | 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<bool> 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<valtype> &stack, const CScript &script, | bool EvalScript(std::vector<valtype> &stack, const CScript &script, | ||||
uint32_t flags, const BaseSignatureChecker &checker, | uint32_t flags, const BaseSignatureChecker &checker, | ||||
ScriptExecutionMetrics &metrics, ScriptError *serror) { | ScriptExecutionMetrics &metrics, ScriptError *serror) { | ||||
static const CScriptNum bnZero(0); | static const CScriptNum bnZero(0); | ||||
static const CScriptNum bnOne(1); | static const CScriptNum bnOne(1); | ||||
static const valtype vchFalse(0); | static const valtype vchFalse(0); | ||||
static const valtype vchTrue(1, 1); | static const valtype vchTrue(1, 1); | ||||
CScript::const_iterator pc = script.begin(); | CScript::const_iterator pc = script.begin(); | ||||
CScript::const_iterator pend = script.end(); | CScript::const_iterator pend = script.end(); | ||||
CScript::const_iterator pbegincodehash = script.begin(); | CScript::const_iterator pbegincodehash = script.begin(); | ||||
opcodetype opcode; | opcodetype opcode; | ||||
valtype vchPushValue; | valtype vchPushValue; | ||||
std::vector<bool> vfExec; | ConditionStack vfExec; | ||||
std::vector<valtype> altstack; | std::vector<valtype> altstack; | ||||
set_error(serror, ScriptError::UNKNOWN); | set_error(serror, ScriptError::UNKNOWN); | ||||
if (script.size() > MAX_SCRIPT_SIZE) { | if (script.size() > MAX_SCRIPT_SIZE) { | ||||
return set_error(serror, ScriptError::SCRIPT_SIZE); | return set_error(serror, ScriptError::SCRIPT_SIZE); | ||||
} | } | ||||
int nOpCount = 0; | int nOpCount = 0; | ||||
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; | bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; | ||||
try { | try { | ||||
while (pc < pend) { | while (pc < pend) { | ||||
bool fExec = !count(vfExec.begin(), vfExec.end(), false); | bool fExec = vfExec.all_true(); | ||||
// | // | ||||
// Read instruction | // Read instruction | ||||
// | // | ||||
if (!script.GetOp(pc, opcode, vchPushValue)) { | if (!script.GetOp(pc, opcode, vchPushValue)) { | ||||
return set_error(serror, ScriptError::BAD_OPCODE); | return set_error(serror, ScriptError::BAD_OPCODE); | ||||
} | } | ||||
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { | if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | try { | ||||
vfExec.push_back(fValue); | vfExec.push_back(fValue); | ||||
} break; | } break; | ||||
case OP_ELSE: { | case OP_ELSE: { | ||||
if (vfExec.empty()) { | if (vfExec.empty()) { | ||||
return set_error( | return set_error( | ||||
serror, ScriptError::UNBALANCED_CONDITIONAL); | serror, ScriptError::UNBALANCED_CONDITIONAL); | ||||
} | } | ||||
vfExec.back() = !vfExec.back(); | vfExec.toggle_top(); | ||||
} break; | } break; | ||||
case OP_ENDIF: { | case OP_ENDIF: { | ||||
if (vfExec.empty()) { | if (vfExec.empty()) { | ||||
return set_error( | return set_error( | ||||
serror, ScriptError::UNBALANCED_CONDITIONAL); | serror, ScriptError::UNBALANCED_CONDITIONAL); | ||||
} | } | ||||
vfExec.pop_back(); | vfExec.pop_back(); | ||||
▲ Show 20 Lines • Show All 1,482 Lines • Show Last 20 Lines |