Fulcrum/bitcoin/script.cpp
Calin Culianu 195551dfe7 Imported more bitcoin code: transaction class and serialization/deser
We will need this in the future to verify tx's and compose tx's

The Tx class is pretty usable as-is.. just manipulates a byte stream.
2019-05-01 00:40:29 +03:00

500 lines
14 KiB
C++

// 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 "script_flags.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include <algorithm>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
namespace bitcoin {
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_SPLIT:
return "OP_SPLIT";
case OP_NUM2BIN:
return "OP_NUM2BIN";
case OP_BIN2NUM:
return "OP_BIN2NUM";
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_CHECKDATASIG:
return "OP_CHECKDATASIG";
case OP_CHECKDATASIGVERIFY:
return "OP_CHECKDATASIGVERIFY";
// expansion
case OP_NOP1:
return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY:
return "OP_CHECKLOCKTIMEVERIFY";
case OP_CHECKSEQUENCEVERIFY:
return "OP_CHECKSEQUENCEVERIFY";
case OP_NOP4:
return "OP_NOP4";
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";
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";
}
}
bool CScriptNum::IsMinimallyEncoded(const std::vector<uint8_t> &vch,
const size_t nMaxNumSize) {
if (vch.size() > nMaxNumSize) {
return false;
}
if (vch.size() > 0) {
// Check that the number is encoded with the minimum possible number
// of bytes.
//
// If the most-significant-byte - excluding the sign bit - is zero
// then we're not minimal. Note how this test also rejects the
// negative-zero encoding, 0x80.
if ((vch.back() & 0x7f) == 0) {
// One exception: if there's more than one byte and the most
// significant bit of the second-most-significant-byte is set it
// would conflict with the sign bit. An example of this case is
// +-255, which encode to 0xff00 and 0xff80 respectively.
// (big-endian).
if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
return false;
}
}
}
return true;
}
bool CScriptNum::MinimallyEncode(std::vector<uint8_t> &data) {
if (data.size() == 0) {
return false;
}
// If the last byte is not 0x00 or 0x80, we are minimally encoded.
uint8_t last = data.back();
if (last & 0x7f) {
return false;
}
// If the script is one byte long, then we have a zero, which encodes as an
// empty array.
if (data.size() == 1) {
data = {};
return true;
}
// If the next byte has it sign bit set, then we are minimaly encoded.
if (data[data.size() - 2] & 0x80) {
return false;
}
// We are not minimally encoded, we need to figure out how much to trim.
for (size_t i = data.size() - 1; i > 0; i--) {
// We found a non zero byte, time to encode.
if (data[i - 1] != 0) {
if (data[i - 1] & 0x80) {
// We found a byte with it sign bit set so we need one more
// byte.
data[i++] = last;
} else {
// the sign bit is clear, we can use it.
data[i - 1] |= last;
}
data.resize(i);
return true;
}
}
// If we the whole thing is zeros, then we have a zero.
data = {};
return true;
}
uint32_t CScript::GetSigOpCount(uint32_t flags, bool fAccurate) const {
uint32_t n = 0;
const_iterator pc = begin();
opcodetype lastOpcode = OP_INVALIDOPCODE;
while (pc < end()) {
opcodetype opcode;
if (!GetOp(pc, opcode)) {
break;
}
switch (opcode) {
case OP_CHECKSIG:
case OP_CHECKSIGVERIFY:
n++;
break;
case OP_CHECKDATASIG:
case OP_CHECKDATASIGVERIFY:
if (flags & SCRIPT_ENABLE_CHECKDATASIG) {
n++;
}
break;
case OP_CHECKMULTISIG:
case OP_CHECKMULTISIGVERIFY:
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16) {
n += DecodeOP_N(lastOpcode);
} else {
n += MAX_PUBKEYS_PER_MULTISIG;
}
break;
default:
break;
}
lastOpcode = opcode;
}
return n;
}
uint32_t CScript::GetSigOpCount(uint32_t flags,
const CScript &scriptSig) const {
if ((flags & SCRIPT_VERIFY_P2SH) == 0 || !IsPayToScriptHash()) {
return GetSigOpCount(flags, 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();
std::vector<uint8_t> vData;
while (pc < scriptSig.end()) {
opcodetype opcode;
if (!scriptSig.GetOp(pc, opcode, vData)) {
return 0;
}
if (opcode > OP_16) {
return 0;
}
}
/// ... and return its opcount:
CScript subscript(vData.begin(), vData.end());
return subscript.GetSigOpCount(flags, true);
}
bool CScript::IsPayToScriptHash() const {
// Extra-fast test for pay-to-script-hash CScripts:
return (this->size() == 23 && (*this)[0] == OP_HASH160 &&
(*this)[1] == 0x14 && (*this)[22] == OP_EQUAL);
}
bool CScript::IsCommitment(const std::vector<uint8_t> &data) const {
// To ensure we have an immediate push, we limit the commitment size to 64
// bytes. In addition to the data themselves, we have 2 extra bytes:
// OP_RETURN and the push opcode itself.
if (data.size() > 64 || this->size() != data.size() + 2) {
return false;
}
if ((*this)[0] != OP_RETURN || (*this)[1] != data.size()) {
return false;
}
for (size_t i = 0; i < data.size(); i++) {
if ((*this)[i + 2] != data[i]) {
return false;
}
}
return true;
}
// 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<uint8_t> &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<uint8_t>(this->begin() + 2, this->end());
return true;
}
return false;
}
// Wrapper returning only the predicate
bool CScript::IsWitnessProgram() const {
int version;
std::vector<uint8_t> program;
return IsWitnessProgram(version, program);
}
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());
}
} // end namespace bitcoin
#ifdef __clang__
#pragma clang diagnostic pop
#endif