mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Merge 67dfd18f44 into merged_master (Bitcoin PR #16902)
This commit is contained in:
commit
ed5795f10a
2 changed files with 90 additions and 3 deletions
|
|
@ -286,6 +286,70 @@ int FindAndDelete(CScript& script, const CScript& b)
|
|||
return nFound;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* This uses an optimized implementation that does not materialize the
|
||||
* actual stack. Instead, it just stores the size of the would-be stack,
|
||||
* and the position of the first false value in it.
|
||||
*/
|
||||
class ConditionStack {
|
||||
private:
|
||||
//! A constant for m_first_false_pos to indicate there are no falses.
|
||||
static constexpr uint32_t NO_FALSE = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
//! The size of the implied stack.
|
||||
uint32_t m_stack_size = 0;
|
||||
//! The position of the first false value on the implied stack, or NO_FALSE if all true.
|
||||
uint32_t m_first_false_pos = NO_FALSE;
|
||||
|
||||
public:
|
||||
bool empty() { return m_stack_size == 0; }
|
||||
bool all_true() { return m_first_false_pos == NO_FALSE; }
|
||||
void push_back(bool f)
|
||||
{
|
||||
if (m_first_false_pos == NO_FALSE && !f) {
|
||||
// The stack consists of all true values, and a false is added.
|
||||
// The first false value will appear at the current size.
|
||||
m_first_false_pos = m_stack_size;
|
||||
}
|
||||
++m_stack_size;
|
||||
}
|
||||
void pop_back()
|
||||
{
|
||||
assert(m_stack_size > 0);
|
||||
--m_stack_size;
|
||||
if (m_first_false_pos == m_stack_size) {
|
||||
// When popping off the first false value, everything becomes true.
|
||||
m_first_false_pos = NO_FALSE;
|
||||
}
|
||||
}
|
||||
void toggle_top()
|
||||
{
|
||||
assert(m_stack_size > 0);
|
||||
if (m_first_false_pos == NO_FALSE) {
|
||||
// The current stack is all true values; the first false will be the top.
|
||||
m_first_false_pos = m_stack_size - 1;
|
||||
} else if (m_first_false_pos == m_stack_size - 1) {
|
||||
// The top is the first false value; toggling it will make everything true.
|
||||
m_first_false_pos = NO_FALSE;
|
||||
} else {
|
||||
// There is a false value, but not on top. No action is needed as toggling
|
||||
// anything but the first false value is unobservable.
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||
{
|
||||
static const CScriptNum bnZero(0);
|
||||
|
|
@ -301,7 +365,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
CScript::const_iterator pbegincodehash = script.begin();
|
||||
opcodetype opcode;
|
||||
valtype vchPushValue;
|
||||
std::vector<bool> vfExec;
|
||||
ConditionStack vfExec;
|
||||
std::vector<valtype> altstack;
|
||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
if (script.size() > MAX_SCRIPT_SIZE)
|
||||
|
|
@ -313,7 +377,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
{
|
||||
while (pc < pend)
|
||||
{
|
||||
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
||||
bool fExec = vfExec.all_true();
|
||||
|
||||
//
|
||||
// Read instruction
|
||||
|
|
@ -506,7 +570,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
{
|
||||
if (vfExec.empty())
|
||||
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
||||
vfExec.back() = !vfExec.back();
|
||||
vfExec.toggle_top();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue