mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Re-enable several disabled opcodes
Re-enabled opcodes are: - OP_CAT - OP_SUBSTR - OP_LEFT - OP_RIGHT - OP_INVERT - OP_AND - OP_OR - OP_XOR - OP_LSHIFT - OP_RSHIFT
This commit is contained in:
parent
4ec1d91298
commit
13e1103abe
2 changed files with 257 additions and 27 deletions
|
|
@ -293,7 +293,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
// static const CScriptNum bnFalse(0);
|
||||
// static const CScriptNum bnTrue(1);
|
||||
static const valtype vchFalse(0);
|
||||
// static const valtype vchZero(0);
|
||||
static const valtype vchZero(0);
|
||||
static const valtype vchTrue(1, 1);
|
||||
|
||||
CScript::const_iterator pc = script.begin();
|
||||
|
|
@ -327,22 +327,26 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
|
||||
return set_error(serror, SCRIPT_ERR_OP_COUNT);
|
||||
|
||||
if (opcode == OP_CAT ||
|
||||
opcode == OP_SUBSTR ||
|
||||
opcode == OP_LEFT ||
|
||||
opcode == OP_RIGHT ||
|
||||
opcode == OP_INVERT ||
|
||||
opcode == OP_AND ||
|
||||
opcode == OP_OR ||
|
||||
opcode == OP_XOR ||
|
||||
// ELEMENTS:
|
||||
// commented out opcodes are re-enabled in Elements
|
||||
if (//opcode == OP_CAT ||
|
||||
//opcode == OP_SUBSTR ||
|
||||
//opcode == OP_LEFT ||
|
||||
//opcode == OP_RIGHT ||
|
||||
//opcode == OP_INVERT ||
|
||||
//opcode == OP_AND ||
|
||||
//opcode == OP_OR ||
|
||||
//opcode == OP_XOR ||
|
||||
//opcode == OP_LSHIFT ||
|
||||
//opcode == OP_RSHIFT ||
|
||||
opcode == OP_2MUL ||
|
||||
opcode == OP_2DIV ||
|
||||
opcode == OP_MUL ||
|
||||
opcode == OP_DIV ||
|
||||
opcode == OP_MOD ||
|
||||
opcode == OP_LSHIFT ||
|
||||
opcode == OP_RSHIFT)
|
||||
opcode == OP_MOD
|
||||
) {
|
||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
|
||||
}
|
||||
|
||||
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch
|
||||
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
|
|
@ -733,6 +737,26 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
}
|
||||
break;
|
||||
|
||||
case OP_CAT:
|
||||
{
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype vch1 = stacktop(-2);
|
||||
valtype vch2 = stacktop(-1);
|
||||
|
||||
if (vch1.size() + vch2.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch3;
|
||||
vch3.reserve(vch1.size() + vch2.size());
|
||||
vch3.insert(vch3.end(), vch1.begin(), vch1.end());
|
||||
vch3.insert(vch3.end(), vch2.begin(), vch2.end());
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch3);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SIZE:
|
||||
{
|
||||
|
|
@ -745,9 +769,230 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
break;
|
||||
|
||||
|
||||
//
|
||||
// String operators
|
||||
//
|
||||
case OP_LEFT:
|
||||
case OP_RIGHT:
|
||||
{
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch1 = stacktop(-2);
|
||||
CScriptNum start(stacktop(-1), fRequireMinimal);
|
||||
|
||||
if (start < 0)
|
||||
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
|
||||
valtype vch2;
|
||||
switch (opcode) {
|
||||
case OP_RIGHT:
|
||||
{
|
||||
if (start >= vch1.size())
|
||||
vch2 = vchZero;
|
||||
else
|
||||
vch2.insert(vch2.begin(), vch1.begin() + start.getint(), vch1.end());
|
||||
break;
|
||||
}
|
||||
case OP_LEFT:
|
||||
{
|
||||
if (start >= vch1.size())
|
||||
vch2 = vch1;
|
||||
else
|
||||
vch2.insert(vch2.begin(), vch1.begin(), vch1.begin() + start.getint());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
assert(!"invalid opcode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch2);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SUBSTR:
|
||||
{
|
||||
if (stack.size() < 3)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch1 = stacktop(-3);
|
||||
CScriptNum start(stacktop(-2), fRequireMinimal);
|
||||
CScriptNum length(stacktop(-1), fRequireMinimal);
|
||||
|
||||
if (length < 0 || start < 0)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if (start >= vch1.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if (length > vch1.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if ((start + length) > vch1.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch2;
|
||||
vch2.insert(vch2.begin(), vch1.begin() + start.getint(), vch1.begin() + (start + length).getint());
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch2);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//
|
||||
// Bitwise logic
|
||||
//
|
||||
case OP_RSHIFT:
|
||||
{
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype vch1 = stacktop(-2);
|
||||
CScriptNum bn(stacktop(-1), fRequireMinimal);
|
||||
|
||||
if (bn < 0)
|
||||
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
|
||||
unsigned int full_bytes = bn.getint() / 8;
|
||||
unsigned int bits = bn.getint() % 8;
|
||||
|
||||
if (full_bytes >= vch1.size()) {
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vchZero);
|
||||
break;
|
||||
}
|
||||
|
||||
valtype vch2;
|
||||
vch2.insert(vch2.begin(), vch1.begin() + full_bytes, vch1.end());
|
||||
|
||||
uint16_t temp = 0;
|
||||
for (int i=(vch2.size()-1);i>=0;--i) {
|
||||
temp = (vch2[i] << (8 - bits)) | ((temp << 8) & 0xff00);
|
||||
vch2[i] = (temp & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
// 0x0fff >> 4 == 0x00ff or 0xff, reduce to minimal representation
|
||||
while (!vch2.empty() && vch2.back() == 0)
|
||||
vch2.pop_back();
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch2);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_LSHIFT:
|
||||
{
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype vch1 = stacktop(-2);
|
||||
CScriptNum bn(stacktop(-1), fRequireMinimal);
|
||||
|
||||
if (bn < 0)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
unsigned int full_bytes = bn.getint() / 8;
|
||||
unsigned int bits = bn.getint() % 8;
|
||||
|
||||
if (vch1.size() + full_bytes + (bits ? 1 : 0) > MAX_SCRIPT_ELEMENT_SIZE)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch2;
|
||||
vch2.reserve(vch1.size() + full_bytes + 1);
|
||||
vch2.insert(vch2.end(), full_bytes, 0);
|
||||
vch2.insert(vch2.end(), vch1.begin(), vch1.end());
|
||||
vch2.insert(vch2.end(), 1, 0);
|
||||
|
||||
uint16_t temp = 0;
|
||||
for (size_t i=0;i<vch2.size();++i) {
|
||||
temp = (vch2[i] << bits) | (temp >> 8);
|
||||
vch2[i] = temp & 0xff;
|
||||
}
|
||||
|
||||
// reduce to minimal representation
|
||||
while (!vch2.empty() && vch2.back() == 0)
|
||||
vch2.pop_back();
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch2);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_INVERT:
|
||||
{
|
||||
if (stack.size() < 1)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype& vch1 = stacktop(-1);
|
||||
for (size_t i = 0; i < vch1.size(); ++i)
|
||||
vch1[i] = ~vch1[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_AND:
|
||||
{
|
||||
// (x1 x2 -- x1 & x2)
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype& vch1 = stacktop(-1);
|
||||
valtype& vch2 = stacktop(-2);
|
||||
if (vch1.size() != vch2.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch3(vch1);
|
||||
for (size_t i = 0; i < vch1.size(); i++)
|
||||
vch3[i] &= vch2[i];
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch3);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_OR:
|
||||
{
|
||||
// (x1 x2 -- x1 | x2)
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype& vch1 = stacktop(-1);
|
||||
valtype& vch2 = stacktop(-2);
|
||||
if (vch1.size() != vch2.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch3(vch1);
|
||||
for (size_t i = 0; i < vch1.size(); i++)
|
||||
vch3[i] |= vch2[i];
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch3);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_XOR:
|
||||
{
|
||||
// (x1 x2 -- x1 ^ x2)
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype& vch1 = stacktop(-1);
|
||||
valtype& vch2 = stacktop(-2);
|
||||
if (vch1.size() != vch2.size())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vch3(vch1);
|
||||
for (size_t i = 0; i < vch1.size(); i++)
|
||||
vch3[i] ^= vch2[i];
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(vch3);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_EQUAL:
|
||||
case OP_EQUALVERIFY:
|
||||
//case OP_NOTEQUAL: // use OP_NUMNOTEQUAL
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue