elements/src/script/script.cpp

426 lines
15 KiB
C++
Raw Normal View History

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "script.h"
#include <list>
#include "hash.h"
#include "primitives/transaction.h"
#include "streams.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "version.h"
using namespace std;
const char* GetOpName(opcodetype opcode)
{
switch (opcode)
{
// push value
case OP_0 : return "0";
case OP_PUSHDATA1 : return "OP_PUSHDATA1";
case OP_PUSHDATA2 : return "OP_PUSHDATA2";
case OP_PUSHDATA4 : return "OP_PUSHDATA4";
case OP_1NEGATE : return "-1";
case OP_RESERVED : return "OP_RESERVED";
case OP_1 : return "1";
case OP_2 : return "2";
case OP_3 : return "3";
case OP_4 : return "4";
case OP_5 : return "5";
case OP_6 : return "6";
case OP_7 : return "7";
case OP_8 : return "8";
case OP_9 : return "9";
case OP_10 : return "10";
case OP_11 : return "11";
case OP_12 : return "12";
case OP_13 : return "13";
case OP_14 : return "14";
case OP_15 : return "15";
case OP_16 : return "16";
// control
case OP_NOP : return "OP_NOP";
case OP_VER : return "OP_VER";
case OP_IF : return "OP_IF";
case OP_NOTIF : return "OP_NOTIF";
case OP_VERIF : return "OP_VERIF";
case OP_VERNOTIF : return "OP_VERNOTIF";
case OP_ELSE : return "OP_ELSE";
case OP_ENDIF : return "OP_ENDIF";
case OP_VERIFY : return "OP_VERIFY";
case OP_RETURN : return "OP_RETURN";
// stack ops
case OP_TOALTSTACK : return "OP_TOALTSTACK";
case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
case OP_2DROP : return "OP_2DROP";
case OP_2DUP : return "OP_2DUP";
case OP_3DUP : return "OP_3DUP";
case OP_2OVER : return "OP_2OVER";
case OP_2ROT : return "OP_2ROT";
case OP_2SWAP : return "OP_2SWAP";
case OP_IFDUP : return "OP_IFDUP";
case OP_DEPTH : return "OP_DEPTH";
case OP_DROP : return "OP_DROP";
case OP_DUP : return "OP_DUP";
case OP_NIP : return "OP_NIP";
case OP_OVER : return "OP_OVER";
case OP_PICK : return "OP_PICK";
case OP_ROLL : return "OP_ROLL";
case OP_ROT : return "OP_ROT";
case OP_SWAP : return "OP_SWAP";
case OP_TUCK : return "OP_TUCK";
// splice ops
case OP_CAT : return "OP_CAT";
case OP_SUBSTR : return "OP_SUBSTR";
case OP_SUBSTR_LAZY : return "OP_SUBSTR_LAZY";
case OP_LEFT : return "OP_LEFT";
case OP_RIGHT : return "OP_RIGHT";
case OP_SIZE : return "OP_SIZE";
// bit logic
case OP_INVERT : return "OP_INVERT";
case OP_AND : return "OP_AND";
case OP_OR : return "OP_OR";
case OP_XOR : return "OP_XOR";
case OP_EQUAL : return "OP_EQUAL";
case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
case OP_RESERVED1 : return "OP_RESERVED1";
case OP_RESERVED2 : return "OP_RESERVED2";
// numeric
case OP_1ADD : return "OP_1ADD";
case OP_1SUB : return "OP_1SUB";
case OP_2MUL : return "OP_2MUL";
case OP_2DIV : return "OP_2DIV";
case OP_NEGATE : return "OP_NEGATE";
case OP_ABS : return "OP_ABS";
case OP_NOT : return "OP_NOT";
case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
case OP_ADD : return "OP_ADD";
case OP_SUB : return "OP_SUB";
case OP_MUL : return "OP_MUL";
case OP_DIV : return "OP_DIV";
case OP_MOD : return "OP_MOD";
case OP_LSHIFT : return "OP_LSHIFT";
case OP_RSHIFT : return "OP_RSHIFT";
case OP_BOOLAND : return "OP_BOOLAND";
case OP_BOOLOR : return "OP_BOOLOR";
case OP_NUMEQUAL : return "OP_NUMEQUAL";
case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
case OP_LESSTHAN : return "OP_LESSTHAN";
case OP_GREATERTHAN : return "OP_GREATERTHAN";
case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
case OP_MIN : return "OP_MIN";
case OP_MAX : return "OP_MAX";
case OP_WITHIN : return "OP_WITHIN";
// crypto
case OP_RIPEMD160 : return "OP_RIPEMD160";
case OP_SHA1 : return "OP_SHA1";
case OP_SHA256 : return "OP_SHA256";
case OP_HASH160 : return "OP_HASH160";
case OP_HASH256 : return "OP_HASH256";
case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
case OP_CHECKSIG : return "OP_CHECKSIG";
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
case OP_DETERMINISTICRANDOM : return "OP_DETERMINISTICRANDOM";
case OP_CHECKSIGFROMSTACK : return "OP_CHECKSIGFROMSTACK";
case OP_CHECKSIGFROMSTACKVERIFY: return "OP_CHECKSIGFROMSTACKVERIFY";
2017-01-18 16:15:37 +01:00
// expansion
case OP_NOP1 : return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
case OP_NOP5 : return "OP_NOP5";
case OP_NOP6 : return "OP_NOP6";
case OP_NOP7 : return "OP_NOP7";
case OP_NOP8 : return "OP_NOP8";
case OP_NOP9 : return "OP_NOP9";
case OP_NOP10 : return "OP_NOP10";
// sidechains/withdraw-proofs
case OP_WITHDRAWPROOFVERIFY : return "OP_WITHDRAWPROOFVERIFY";
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
// Note:
// The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
// Script, just let the default: case deal with them.
default:
return "OP_UNKNOWN";
}
}
unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
unsigned int n = 0;
const_iterator pc = begin();
opcodetype lastOpcode = OP_INVALIDOPCODE;
while (pc < end())
{
opcodetype opcode;
if (!GetOp(pc, opcode))
break;
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY ||
opcode == OP_CHECKSIGFROMSTACK || opcode == OP_CHECKSIGFROMSTACKVERIFY)
n++;
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
{
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
n += DecodeOP_N(lastOpcode);
else
n += MAX_PUBKEYS_PER_MULTISIG;
}
lastOpcode = opcode;
}
return n;
}
unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
{
if (!IsPayToScriptHash())
return GetSigOpCount(true);
// This is a pay-to-script-hash scriptPubKey;
// get the last item that the scriptSig
// pushes onto the stack:
const_iterator pc = scriptSig.begin();
vector<unsigned char> data;
while (pc < scriptSig.end())
{
opcodetype opcode;
if (!scriptSig.GetOp(pc, opcode, data))
return 0;
if (opcode > OP_16)
return 0;
}
/// ... and return its opcount:
CScript subscript(data.begin(), data.end());
return subscript.GetSigOpCount(true);
}
bool CScript::IsWithdrawProof() const
{
// Format is <contract> <merkleBlock>xN <N> <locking tx>xM <M> <output index>
// for at least 6 total pushes
// Here we simply check that the script is push-only and has at least 6 pushes.
// The output must be P2SH to the appropriate script
const_iterator pc = begin();
opcodetype opcode;
uint32_t push_count = 0;
while (pc < end())
{
if (!GetOp(pc, opcode))
return false;
if (opcode > OP_16 || opcode == OP_RESERVED)
return false;
push_count++;
}
return push_count >= 6;
}
bool CScript::IsWithdrawLock() const
{
// Locks look like [<chaindest> OP_DROP] <genesishash> OP_WITHDRAWPROOFVERIFY
// This function must return true for an OP_WITHDRAWPROOFVERIFY opcode to execute.
// We require all pushes be in their minimal form, to make inspection of
// withdraw locks a purely byte-matching affair.
const_iterator pc = begin();
vector<unsigned char> data;
opcodetype opcode;
if (!GetOp(pc, opcode, data))
return false;
if (opcode == 24 && data.size() == 24) { // 4 byte type + 20 byte destination is suggested
if (!GetOp(pc, opcode, data) || opcode != OP_DROP || data.size() != 0)
return false;
if (!GetOp(pc, opcode, data))
return false;
}
if (opcode != 32 || data.size() != 32)
return false;
if (!GetOp(pc, opcode, data) || opcode != OP_WITHDRAWPROOFVERIFY || data.size() != 0)
return false;
if (GetOp(pc, opcode))
return false;
return true;
}
uint256 CScript::GetWithdrawLockGenesisHash() const
{
assert(IsWithdrawLock());
const_iterator pc = begin();
opcodetype opcode;
vector<unsigned char> vchgenesishash;
assert(GetOp(pc, opcode, vchgenesishash));
if (vchgenesishash.size() != 32) {
assert(GetOp(pc, opcode) && opcode == OP_DROP);
assert(GetOp(pc, opcode, vchgenesishash));
}
assert(vchgenesishash.size() == 32);
return uint256(vchgenesishash);
}
static bool PopWithdrawPush(vector<vector<unsigned char> >& pushes, vector<unsigned char> *read=NULL) {
if (pushes.empty())
return false;
int pushCount = CScriptNum(pushes.back(), false).getint();
pushes.pop_back();
if (pushCount < 0 || pushCount > 2000 || pushes.size() < size_t(pushCount))
return false;
for (int i = pushCount; i > 0; i--) {
if (i != 1 && pushes[pushes.size() - i].size() != 520)
return false;
if (read != NULL) {
const vector<unsigned char> &push = pushes[pushes.size() - i];
read->insert(read->end(), push.begin(), push.end());
}
}
for (int i = 0; i < pushCount; i++)
pushes.pop_back();
return true;
}
COutPoint CScript::GetWithdrawSpent() const
{
assert(IsWithdrawProof());
try {
const_iterator pc = begin();
opcodetype opcode;
// We have to read the script from back-to-front, so we stack-ize it
vector<vector<unsigned char> > pushes;
pushes.reserve(6);
while (pc < end()) {
pushes.push_back(vector<unsigned char>());
assert(GetOp(pc, opcode, pushes.back()));
if (opcode <= OP_16 && opcode >= OP_1)
pushes.back().push_back(opcode - OP_1 + 1);
else if (opcode == OP_1NEGATE)
pushes.back().push_back(0x81);
}
int ntxOut = CScriptNum(pushes.back(), false).getint();
pushes.pop_back();
vector<unsigned char> vTx;
if (!PopWithdrawPush(pushes, &vTx))
return COutPoint();
CTransactionRef tx;
CDataStream(vTx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_BITCOIN_BLOCK_OR_TX) >> tx;
if (ntxOut < 0 || (unsigned int)ntxOut >= tx->vout.size())
return COutPoint();
return COutPoint(tx->GetHash(), ntxOut);
} catch (std::exception& e) {
return COutPoint();
}
}
2016-02-21 17:52:08 +08:00
void CScript::PushWithdraw(const vector<unsigned char> push) {
int64_t pushCount = 0;
for (vector<unsigned char>::const_iterator it = push.begin(); it < push.end(); pushCount++) {
if (push.end() - it < 520) {
*this << vector<unsigned char>(it, push.end());
it = push.end();
} else {
*this << vector<unsigned char>(it, it + 520);
it += 520;
}
}
*this << pushCount;
}
bool CScript::IsPayToScriptHash() const
{
// Extra-fast test for pay-to-script-hash CScripts:
return (this->size() == 23 &&
2015-10-29 07:11:24 +01:00
(*this)[0] == OP_HASH160 &&
(*this)[1] == 0x14 &&
(*this)[22] == OP_EQUAL);
}
bool CScript::IsPayToWitnessScriptHash() const
{
// Extra-fast test for pay-to-witness-script-hash CScripts:
return (this->size() == 34 &&
(*this)[0] == OP_0 &&
(*this)[1] == 0x20);
}
2015-11-08 01:16:45 +01:00
// A witness program is any valid CScript that consists of a 1-byte push opcode
// followed by a data push between 2 and 40 bytes.
bool CScript::IsWitnessProgram(int& version, std::vector<unsigned char>& program) const
{
if (this->size() < 4 || this->size() > 42) {
return false;
}
if ((*this)[0] != OP_0 && ((*this)[0] < OP_1 || (*this)[0] > OP_16)) {
return false;
}
if ((size_t)((*this)[1] + 2) == this->size()) {
version = DecodeOP_N((opcodetype)(*this)[0]);
program = std::vector<unsigned char>(this->begin() + 2, this->end());
return true;
}
return false;
}
bool CScript::IsPushOnly(const_iterator pc) const
{
while (pc < end())
{
opcodetype opcode;
if (!GetOp(pc, opcode))
return false;
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
// push-type opcode, however execution of OP_RESERVED fails, so
// it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
// the P2SH special validation code being executed.
if (opcode > OP_16)
return false;
}
return true;
}
bool CScript::IsPushOnly() const
{
return this->IsPushOnly(begin());
}
std::string CScriptWitness::ToString() const
{
std::string ret = "CScriptWitness(";
for (unsigned int i = 0; i < stack.size(); i++) {
if (i) {
ret += ", ";
}
ret += HexStr(stack[i]);
}
return ret + ")";
}