Merge pull request #4754
e088d65
Separate script/sign (jtimon)9294a4b
Separate CScriptCompressor (jtimon)c4408a6
Separate script/standard (jtimon)da03e6e
Separate script/interpreter (jtimon)cbd22a5
Move CScript class and dependencies to script/script (jtimon)86dbeea
Rename script.h/.cpp to scriptutils.h/.cpp (plus remove duplicated includes) (jtimon) Rebased-by: Pieter Wuille
This commit is contained in:
commit
eecd3c0fb0
37 changed files with 1519 additions and 1393 deletions
|
@ -98,7 +98,12 @@ BITCOIN_CORE_H = \
|
|||
rpcclient.h \
|
||||
rpcprotocol.h \
|
||||
rpcserver.h \
|
||||
script.h \
|
||||
script/interpreter.h \
|
||||
script/compressor.h \
|
||||
script/script.h \
|
||||
script/sign.h \
|
||||
script/standard.h \
|
||||
scriptutils.h \
|
||||
serialize.h \
|
||||
sync.h \
|
||||
threadsafety.h \
|
||||
|
@ -206,7 +211,12 @@ libbitcoin_common_a_SOURCES = \
|
|||
keystore.cpp \
|
||||
netbase.cpp \
|
||||
protocol.cpp \
|
||||
script.cpp \
|
||||
script/interpreter.cpp \
|
||||
script/compressor.cpp \
|
||||
script/script.cpp \
|
||||
script/sign.cpp \
|
||||
script/standard.cpp \
|
||||
scriptutils.cpp \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
# util: shared between all executables.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "chainparams.h"
|
||||
#include "key.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "core.h"
|
||||
#include "main.h" // for MAX_BLOCK_SIZE
|
||||
#include "keystore.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "ui_interface.h" // for _(...)
|
||||
#include "univalue/univalue.h"
|
||||
#include "core_io.h"
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "bloom.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#ifndef BITCOIN_CORE_H
|
||||
#define BITCOIN_CORE_H
|
||||
|
||||
#include "script.h"
|
||||
#include "script/compressor.h"
|
||||
#include "script/script.h"
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "core_io.h"
|
||||
#include "core.h"
|
||||
#include "serialize.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
#include "core_io.h"
|
||||
#include "univalue/univalue.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "core.h"
|
||||
#include "serialize.h"
|
||||
#include "util.h"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "crypter.h"
|
||||
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "crypter.h"
|
||||
#include "key.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
#include "core.h"
|
||||
#include "net.h"
|
||||
#include "pow.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "sync.h"
|
||||
#include "txmempool.h"
|
||||
#include "uint256.h"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "db.h"
|
||||
#include "main.h"
|
||||
#include "paymentserver.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "transactionrecord.h"
|
||||
#include "timedata.h"
|
||||
#include "ui_interface.h"
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "main.h"
|
||||
#include "net.h"
|
||||
#include "rpcserver.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "script/sign.h"
|
||||
#include "uint256.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet.h"
|
||||
|
|
127
src/script/compressor.cpp
Normal file
127
src/script/compressor.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "compressor.h"
|
||||
|
||||
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
|
||||
{
|
||||
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
|
||||
&& script[2] == 20 && script[23] == OP_EQUALVERIFY
|
||||
&& script[24] == OP_CHECKSIG) {
|
||||
memcpy(&hash, &script[3], 20);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
|
||||
{
|
||||
if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
|
||||
&& script[22] == OP_EQUAL) {
|
||||
memcpy(&hash, &script[2], 20);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
|
||||
{
|
||||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
|
||||
&& (script[1] == 0x02 || script[1] == 0x03)) {
|
||||
pubkey.Set(&script[1], &script[34]);
|
||||
return true;
|
||||
}
|
||||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
|
||||
&& script[1] == 0x04) {
|
||||
pubkey.Set(&script[1], &script[66]);
|
||||
return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
|
||||
{
|
||||
CKeyID keyID;
|
||||
if (IsToKeyID(keyID)) {
|
||||
out.resize(21);
|
||||
out[0] = 0x00;
|
||||
memcpy(&out[1], &keyID, 20);
|
||||
return true;
|
||||
}
|
||||
CScriptID scriptID;
|
||||
if (IsToScriptID(scriptID)) {
|
||||
out.resize(21);
|
||||
out[0] = 0x01;
|
||||
memcpy(&out[1], &scriptID, 20);
|
||||
return true;
|
||||
}
|
||||
CPubKey pubkey;
|
||||
if (IsToPubKey(pubkey)) {
|
||||
out.resize(33);
|
||||
memcpy(&out[1], &pubkey[1], 32);
|
||||
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
|
||||
out[0] = pubkey[0];
|
||||
return true;
|
||||
} else if (pubkey[0] == 0x04) {
|
||||
out[0] = 0x04 | (pubkey[64] & 0x01);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
|
||||
{
|
||||
if (nSize == 0 || nSize == 1)
|
||||
return 20;
|
||||
if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
|
||||
return 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)
|
||||
{
|
||||
switch(nSize) {
|
||||
case 0x00:
|
||||
script.resize(25);
|
||||
script[0] = OP_DUP;
|
||||
script[1] = OP_HASH160;
|
||||
script[2] = 20;
|
||||
memcpy(&script[3], &in[0], 20);
|
||||
script[23] = OP_EQUALVERIFY;
|
||||
script[24] = OP_CHECKSIG;
|
||||
return true;
|
||||
case 0x01:
|
||||
script.resize(23);
|
||||
script[0] = OP_HASH160;
|
||||
script[1] = 20;
|
||||
memcpy(&script[2], &in[0], 20);
|
||||
script[22] = OP_EQUAL;
|
||||
return true;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
script.resize(35);
|
||||
script[0] = 33;
|
||||
script[1] = nSize;
|
||||
memcpy(&script[2], &in[0], 32);
|
||||
script[34] = OP_CHECKSIG;
|
||||
return true;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
unsigned char vch[33] = {};
|
||||
vch[0] = nSize - 2;
|
||||
memcpy(&vch[1], &in[0], 32);
|
||||
CPubKey pubkey(&vch[0], &vch[33]);
|
||||
if (!pubkey.Decompress())
|
||||
return false;
|
||||
assert(pubkey.size() == 65);
|
||||
script.resize(67);
|
||||
script[0] = 65;
|
||||
memcpy(&script[1], pubkey.begin(), 65);
|
||||
script[66] = OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
84
src/script/compressor.h
Normal file
84
src/script/compressor.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPT_COMPRESSOR
|
||||
#define H_BITCOIN_SCRIPT_COMPRESSOR
|
||||
|
||||
#include "script/script.h"
|
||||
|
||||
/** Compact serializer for scripts.
|
||||
*
|
||||
* It detects common cases and encodes them much more efficiently.
|
||||
* 3 special cases are defined:
|
||||
* * Pay to pubkey hash (encoded as 21 bytes)
|
||||
* * Pay to script hash (encoded as 21 bytes)
|
||||
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
|
||||
*
|
||||
* Other scripts up to 121 bytes require 1 byte + script length. Above
|
||||
* that, scripts up to 16505 bytes require 2 bytes + script length.
|
||||
*/
|
||||
class CScriptCompressor
|
||||
{
|
||||
private:
|
||||
// make this static for now (there are only 6 special scripts defined)
|
||||
// this can potentially be extended together with a new nVersion for
|
||||
// transactions, in which case this value becomes dependent on nVersion
|
||||
// and nHeight of the enclosing transaction.
|
||||
static const unsigned int nSpecialScripts = 6;
|
||||
|
||||
CScript &script;
|
||||
protected:
|
||||
// These check for scripts for which a special case with a shorter encoding is defined.
|
||||
// They are implemented separately from the CScript test, as these test for exact byte
|
||||
// sequence correspondences, and are more strict. For example, IsToPubKey also verifies
|
||||
// whether the public key is valid (as invalid ones cannot be represented in compressed
|
||||
// form).
|
||||
bool IsToKeyID(CKeyID &hash) const;
|
||||
bool IsToScriptID(CScriptID &hash) const;
|
||||
bool IsToPubKey(CPubKey &pubkey) const;
|
||||
|
||||
bool Compress(std::vector<unsigned char> &out) const;
|
||||
unsigned int GetSpecialSize(unsigned int nSize) const;
|
||||
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
|
||||
public:
|
||||
CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
|
||||
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const {
|
||||
std::vector<unsigned char> compr;
|
||||
if (Compress(compr))
|
||||
return compr.size();
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s, int nType, int nVersion) const {
|
||||
std::vector<unsigned char> compr;
|
||||
if (Compress(compr)) {
|
||||
s << CFlatData(compr);
|
||||
return;
|
||||
}
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
s << VARINT(nSize);
|
||||
s << CFlatData(script);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s, int nType, int nVersion) {
|
||||
unsigned int nSize = 0;
|
||||
s >> VARINT(nSize);
|
||||
if (nSize < nSpecialScripts) {
|
||||
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
|
||||
s >> REF(CFlatData(vch));
|
||||
Decompress(nSize, vch);
|
||||
return;
|
||||
}
|
||||
nSize -= nSpecialScripts;
|
||||
script.resize(nSize);
|
||||
s >> REF(CFlatData(script));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
45
src/script/interpreter.h
Normal file
45
src/script/interpreter.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPT_INTERPRETER
|
||||
#define H_BITCOIN_SCRIPT_INTERPRETER
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
class uint256;
|
||||
class CScript;
|
||||
class CTransaction;
|
||||
|
||||
/** Signature hash types/flags */
|
||||
enum
|
||||
{
|
||||
SIGHASH_ALL = 1,
|
||||
SIGHASH_NONE = 2,
|
||||
SIGHASH_SINGLE = 3,
|
||||
SIGHASH_ANYONECANPAY = 0x80,
|
||||
};
|
||||
|
||||
/** Script verification flags */
|
||||
enum
|
||||
{
|
||||
SCRIPT_VERIFY_NONE = 0,
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
|
||||
SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
|
||||
};
|
||||
|
||||
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
|
||||
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
|
||||
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
|
||||
|
||||
#endif
|
295
src/script/script.cpp
Normal file
295
src/script/script.cpp
Normal file
|
@ -0,0 +1,295 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
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_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";
|
||||
|
||||
// expanson
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_NOP2 : return "OP_NOP2";
|
||||
case OP_NOP3 : return "OP_NOP3";
|
||||
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_SMALLDATA/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)
|
||||
n++;
|
||||
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
|
||||
{
|
||||
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
|
||||
n += DecodeOP_N(lastOpcode);
|
||||
else
|
||||
n += 20;
|
||||
}
|
||||
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::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
return (this->size() == 23 &&
|
||||
this->at(0) == OP_HASH160 &&
|
||||
this->at(1) == 0x14 &&
|
||||
this->at(22) == OP_EQUAL);
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly() const
|
||||
{
|
||||
const_iterator pc = begin();
|
||||
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 as the scriptSig would fail prior to
|
||||
// the P2SH special validation code being executed.
|
||||
if (opcode > OP_16)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScript::HasCanonicalPushes() const
|
||||
{
|
||||
const_iterator pc = begin();
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
std::vector<unsigned char> data;
|
||||
if (!GetOp(pc, opcode, data))
|
||||
return false;
|
||||
if (opcode > OP_16)
|
||||
continue;
|
||||
if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
|
||||
// Could have used an OP_n code, rather than a 1-byte push.
|
||||
return false;
|
||||
if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
|
||||
// Could have used a normal n-byte push, rather than OP_PUSHDATA1.
|
||||
return false;
|
||||
if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
|
||||
// Could have used an OP_PUSHDATA1.
|
||||
return false;
|
||||
if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
|
||||
// Could have used an OP_PUSHDATA2.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class CScriptVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
private:
|
||||
CScript *script;
|
||||
public:
|
||||
CScriptVisitor(CScript *scriptin) { script = scriptin; }
|
||||
|
||||
bool operator()(const CNoDestination &dest) const {
|
||||
script->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(const CKeyID &keyID) const {
|
||||
script->clear();
|
||||
*script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const CScriptID &scriptID) const {
|
||||
script->clear();
|
||||
*script << OP_HASH160 << scriptID << OP_EQUAL;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void CScript::SetDestination(const CTxDestination& dest)
|
||||
{
|
||||
boost::apply_visitor(CScriptVisitor(this), dest);
|
||||
}
|
||||
|
||||
void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
*this << EncodeOP_N(nRequired);
|
||||
BOOST_FOREACH(const CPubKey& key, keys)
|
||||
*this << key;
|
||||
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
}
|
|
@ -7,248 +7,14 @@
|
|||
#define H_BITCOIN_SCRIPT
|
||||
|
||||
#include "key.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "tinyformat.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
class CKeyStore;
|
||||
class CTransaction;
|
||||
struct CMutableTransaction;
|
||||
|
||||
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
|
||||
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
|
||||
|
||||
class scriptnum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
class CScriptNum
|
||||
{
|
||||
// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
|
||||
// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
|
||||
// but results may overflow (and are valid as long as they are not used in a subsequent
|
||||
// numeric operation). CScriptNum enforces those semantics by storing results as
|
||||
// an int64 and allowing out-of-range values to be returned as a vector of bytes but
|
||||
// throwing an exception if arithmetic is done or the result is interpreted as an integer.
|
||||
public:
|
||||
|
||||
explicit CScriptNum(const int64_t& n)
|
||||
{
|
||||
m_value = n;
|
||||
}
|
||||
|
||||
explicit CScriptNum(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.size() > nMaxNumSize)
|
||||
throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
|
||||
m_value = set_vch(vch);
|
||||
}
|
||||
|
||||
inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
|
||||
inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
|
||||
inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
|
||||
inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
|
||||
inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
|
||||
inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
|
||||
|
||||
inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }
|
||||
inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }
|
||||
inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }
|
||||
inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }
|
||||
inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }
|
||||
inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}
|
||||
inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}
|
||||
inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }
|
||||
inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }
|
||||
|
||||
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
|
||||
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator-() const
|
||||
{
|
||||
assert(m_value != std::numeric_limits<int64_t>::min());
|
||||
return CScriptNum(-m_value);
|
||||
}
|
||||
|
||||
inline CScriptNum& operator=( const int64_t& rhs)
|
||||
{
|
||||
m_value = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator+=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
|
||||
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
|
||||
m_value += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator-=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
|
||||
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
|
||||
m_value -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int getint() const
|
||||
{
|
||||
if (m_value > std::numeric_limits<int>::max())
|
||||
return std::numeric_limits<int>::max();
|
||||
else if (m_value < std::numeric_limits<int>::min())
|
||||
return std::numeric_limits<int>::min();
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getvch() const
|
||||
{
|
||||
return serialize(m_value);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> serialize(const int64_t& value)
|
||||
{
|
||||
if(value == 0)
|
||||
return std::vector<unsigned char>();
|
||||
|
||||
std::vector<unsigned char> result;
|
||||
const bool neg = value < 0;
|
||||
uint64_t absvalue = neg ? -value : value;
|
||||
|
||||
while(absvalue)
|
||||
{
|
||||
result.push_back(absvalue & 0xff);
|
||||
absvalue >>= 8;
|
||||
}
|
||||
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is positive, push a
|
||||
// new zero-byte to make the significant byte < 0x80 again.
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is negative, push a
|
||||
// new 0x80 byte that will be popped off when converting to an integral.
|
||||
|
||||
// - If the most significant byte is < 0x80 and the value is negative, add
|
||||
// 0x80 to it, since it will be subtracted and interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
if (result.back() & 0x80)
|
||||
result.push_back(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result.back() |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const size_t nMaxNumSize = 4;
|
||||
|
||||
private:
|
||||
static int64_t set_vch(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.empty())
|
||||
return 0;
|
||||
|
||||
int64_t result = 0;
|
||||
for (size_t i = 0; i != vch.size(); ++i)
|
||||
result |= static_cast<int64_t>(vch[i]) << 8*i;
|
||||
|
||||
// If the input vector's most significant byte is 0x80, remove it from
|
||||
// the result's msb and return a negative.
|
||||
if (vch.back() & 0x80)
|
||||
return -(result & ~(0x80ULL << (8 * (vch.size() - 1))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t m_value;
|
||||
};
|
||||
|
||||
/** Signature hash types/flags */
|
||||
enum
|
||||
{
|
||||
SIGHASH_ALL = 1,
|
||||
SIGHASH_NONE = 2,
|
||||
SIGHASH_SINGLE = 3,
|
||||
SIGHASH_ANYONECANPAY = 0x80,
|
||||
};
|
||||
|
||||
/** Script verification flags */
|
||||
enum
|
||||
{
|
||||
SCRIPT_VERIFY_NONE = 0,
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
|
||||
SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
|
||||
};
|
||||
|
||||
/** IsMine() return codes */
|
||||
enum isminetype
|
||||
{
|
||||
ISMINE_NO = 0,
|
||||
ISMINE_WATCH_ONLY = 1,
|
||||
ISMINE_SPENDABLE = 2,
|
||||
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
|
||||
};
|
||||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
||||
// Mandatory script verification flags that all new blocks must comply with for
|
||||
// them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
// but in the future other flags may be added, such as a soft-fork to enforce
|
||||
// strict DER encoding.
|
||||
//
|
||||
// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
// details.
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||
|
||||
// Standard script verification flags that standard transactions will comply
|
||||
// with. However scripts violating these flags may still be present in valid
|
||||
// blocks and we must accept those blocks.
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_NULLDUMMY;
|
||||
|
||||
// For convenience, standard but not mandatory verify flags.
|
||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||
|
||||
enum txnouttype
|
||||
{
|
||||
TX_NONSTANDARD,
|
||||
// 'standard' transaction types:
|
||||
TX_PUBKEY,
|
||||
TX_PUBKEYHASH,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_NULL_DATA,
|
||||
};
|
||||
|
||||
class CNoDestination {
|
||||
public:
|
||||
friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
};
|
||||
|
||||
/** A txout script template with a specific destination. It is either:
|
||||
* * CNoDestination: no destination set
|
||||
* * CKeyID: TX_PUBKEYHASH destination
|
||||
* * CScriptID: TX_SCRIPTHASH destination
|
||||
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
|
||||
*/
|
||||
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
|
||||
|
||||
const char* GetTxnOutputType(txnouttype t);
|
||||
|
||||
/** Script opcodes */
|
||||
enum opcodetype
|
||||
|
@ -386,7 +152,6 @@ enum opcodetype
|
|||
OP_NOP10 = 0xb9,
|
||||
|
||||
|
||||
|
||||
// template matching params
|
||||
OP_SMALLDATA = 0xf9,
|
||||
OP_SMALLINTEGER = 0xfa,
|
||||
|
@ -399,7 +164,153 @@ enum opcodetype
|
|||
|
||||
const char* GetOpName(opcodetype opcode);
|
||||
|
||||
class scriptnum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
class CScriptNum
|
||||
{
|
||||
// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
|
||||
// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
|
||||
// but results may overflow (and are valid as long as they are not used in a subsequent
|
||||
// numeric operation). CScriptNum enforces those semantics by storing results as
|
||||
// an int64 and allowing out-of-range values to be returned as a vector of bytes but
|
||||
// throwing an exception if arithmetic is done or the result is interpreted as an integer.
|
||||
public:
|
||||
|
||||
explicit CScriptNum(const int64_t& n)
|
||||
{
|
||||
m_value = n;
|
||||
}
|
||||
|
||||
explicit CScriptNum(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.size() > nMaxNumSize)
|
||||
throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
|
||||
m_value = set_vch(vch);
|
||||
}
|
||||
|
||||
inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
|
||||
inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
|
||||
inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
|
||||
inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
|
||||
inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
|
||||
inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
|
||||
|
||||
inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }
|
||||
inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }
|
||||
inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }
|
||||
inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }
|
||||
inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }
|
||||
inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}
|
||||
inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}
|
||||
inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }
|
||||
inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }
|
||||
|
||||
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
|
||||
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator-() const
|
||||
{
|
||||
assert(m_value != std::numeric_limits<int64_t>::min());
|
||||
return CScriptNum(-m_value);
|
||||
}
|
||||
|
||||
inline CScriptNum& operator=( const int64_t& rhs)
|
||||
{
|
||||
m_value = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator+=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
|
||||
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
|
||||
m_value += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator-=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
|
||||
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
|
||||
m_value -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int getint() const
|
||||
{
|
||||
if (m_value > std::numeric_limits<int>::max())
|
||||
return std::numeric_limits<int>::max();
|
||||
else if (m_value < std::numeric_limits<int>::min())
|
||||
return std::numeric_limits<int>::min();
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getvch() const
|
||||
{
|
||||
return serialize(m_value);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> serialize(const int64_t& value)
|
||||
{
|
||||
if(value == 0)
|
||||
return std::vector<unsigned char>();
|
||||
|
||||
std::vector<unsigned char> result;
|
||||
const bool neg = value < 0;
|
||||
uint64_t absvalue = neg ? -value : value;
|
||||
|
||||
while(absvalue)
|
||||
{
|
||||
result.push_back(absvalue & 0xff);
|
||||
absvalue >>= 8;
|
||||
}
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is positive, push a
|
||||
// new zero-byte to make the significant byte < 0x80 again.
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is negative, push a
|
||||
// new 0x80 byte that will be popped off when converting to an integral.
|
||||
|
||||
// - If the most significant byte is < 0x80 and the value is negative, add
|
||||
// 0x80 to it, since it will be subtracted and interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
if (result.back() & 0x80)
|
||||
result.push_back(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result.back() |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const size_t nMaxNumSize = 4;
|
||||
|
||||
private:
|
||||
static int64_t set_vch(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.empty())
|
||||
return 0;
|
||||
|
||||
int64_t result = 0;
|
||||
for (size_t i = 0; i != vch.size(); ++i)
|
||||
result |= static_cast<int64_t>(vch[i]) << 8*i;
|
||||
|
||||
// If the input vector's most significant byte is 0x80, remove it from
|
||||
// the result's msb and return a negative.
|
||||
if (vch.back() & 0x80)
|
||||
return -(result & ~(0x80ULL << (8 * (vch.size() - 1))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t m_value;
|
||||
};
|
||||
|
||||
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
|
@ -409,6 +320,20 @@ inline std::string ValueString(const std::vector<unsigned char>& vch)
|
|||
return HexStr(vch);
|
||||
}
|
||||
|
||||
class CNoDestination {
|
||||
public:
|
||||
friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
};
|
||||
|
||||
/** A txout script template with a specific destination. It is either:
|
||||
* * CNoDestination: no destination set
|
||||
* * CKeyID: TX_PUBKEYHASH destination
|
||||
* * CScriptID: TX_SCRIPTHASH destination
|
||||
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
|
||||
*/
|
||||
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
|
||||
|
||||
/** Serialized script, used inside transaction inputs and outputs */
|
||||
class CScript : public std::vector<unsigned char>
|
||||
{
|
||||
|
@ -446,7 +371,6 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
CScript(int64_t b) { operator<<(b); }
|
||||
|
||||
explicit CScript(opcodetype b) { operator<<(b); }
|
||||
|
@ -718,98 +642,4 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/** Compact serializer for scripts.
|
||||
*
|
||||
* It detects common cases and encodes them much more efficiently.
|
||||
* 3 special cases are defined:
|
||||
* * Pay to pubkey hash (encoded as 21 bytes)
|
||||
* * Pay to script hash (encoded as 21 bytes)
|
||||
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
|
||||
*
|
||||
* Other scripts up to 121 bytes require 1 byte + script length. Above
|
||||
* that, scripts up to 16505 bytes require 2 bytes + script length.
|
||||
*/
|
||||
class CScriptCompressor
|
||||
{
|
||||
private:
|
||||
// make this static for now (there are only 6 special scripts defined)
|
||||
// this can potentially be extended together with a new nVersion for
|
||||
// transactions, in which case this value becomes dependent on nVersion
|
||||
// and nHeight of the enclosing transaction.
|
||||
static const unsigned int nSpecialScripts = 6;
|
||||
|
||||
CScript &script;
|
||||
protected:
|
||||
// These check for scripts for which a special case with a shorter encoding is defined.
|
||||
// They are implemented separately from the CScript test, as these test for exact byte
|
||||
// sequence correspondences, and are more strict. For example, IsToPubKey also verifies
|
||||
// whether the public key is valid (as invalid ones cannot be represented in compressed
|
||||
// form).
|
||||
bool IsToKeyID(CKeyID &hash) const;
|
||||
bool IsToScriptID(CScriptID &hash) const;
|
||||
bool IsToPubKey(CPubKey &pubkey) const;
|
||||
|
||||
bool Compress(std::vector<unsigned char> &out) const;
|
||||
unsigned int GetSpecialSize(unsigned int nSize) const;
|
||||
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
|
||||
public:
|
||||
CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
|
||||
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const {
|
||||
std::vector<unsigned char> compr;
|
||||
if (Compress(compr))
|
||||
return compr.size();
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s, int nType, int nVersion) const {
|
||||
std::vector<unsigned char> compr;
|
||||
if (Compress(compr)) {
|
||||
s << CFlatData(compr);
|
||||
return;
|
||||
}
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
s << VARINT(nSize);
|
||||
s << CFlatData(script);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s, int nType, int nVersion) {
|
||||
unsigned int nSize = 0;
|
||||
s >> VARINT(nSize);
|
||||
if (nSize < nSpecialScripts) {
|
||||
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
|
||||
s >> REF(CFlatData(vch));
|
||||
Decompress(nSize, vch);
|
||||
return;
|
||||
}
|
||||
nSize -= nSpecialScripts;
|
||||
script.resize(nSize);
|
||||
s >> REF(CFlatData(script));
|
||||
}
|
||||
};
|
||||
|
||||
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
|
||||
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
|
||||
|
||||
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
|
||||
// combine them intelligently and return the result.
|
||||
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||
|
||||
#endif // H_BITCOIN_SCRIPT
|
||||
#endif
|
260
src/script/sign.cpp
Normal file
260
src/script/sign.cpp
Normal file
|
@ -0,0 +1,260 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script/sign.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "script/standard.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
{
|
||||
CKey key;
|
||||
if (!keystore.GetKey(address, key))
|
||||
return false;
|
||||
|
||||
vector<unsigned char> vchSig;
|
||||
if (!key.Sign(hash, vchSig))
|
||||
return false;
|
||||
vchSig.push_back((unsigned char)nHashType);
|
||||
scriptSigRet << vchSig;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
{
|
||||
int nSigned = 0;
|
||||
int nRequired = multisigdata.front()[0];
|
||||
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
|
||||
{
|
||||
const valtype& pubkey = multisigdata[i];
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
++nSigned;
|
||||
}
|
||||
return nSigned==nRequired;
|
||||
}
|
||||
|
||||
//
|
||||
// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
|
||||
// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
||||
// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
||||
// Returns false if scriptPubKey could not be completely satisfied.
|
||||
//
|
||||
bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
|
||||
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
||||
{
|
||||
scriptSigRet.clear();
|
||||
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||
return false;
|
||||
|
||||
CKeyID keyID;
|
||||
switch (whichTypeRet)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
CPubKey vch;
|
||||
keystore.GetPubKey(keyID, vch);
|
||||
scriptSigRet << vch;
|
||||
}
|
||||
return true;
|
||||
case TX_SCRIPTHASH:
|
||||
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
||||
|
||||
case TX_MULTISIG:
|
||||
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
||||
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
|
||||
// Leave out the signature from the hash, since a signature can't sign itself.
|
||||
// The checksig op will also drop the signatures from its hash.
|
||||
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
|
||||
|
||||
txnouttype whichType;
|
||||
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
// Solver returns the subscript that need to be evaluated;
|
||||
// the final scriptSig is the signatures from that
|
||||
// and then the serialized subscript:
|
||||
CScript subscript = txin.scriptSig;
|
||||
|
||||
// Recompute txn hash using subscript in place of scriptPubKey:
|
||||
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
|
||||
|
||||
txnouttype subType;
|
||||
bool fSolved =
|
||||
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
|
||||
// Append serialized subscript whether or not it is completely signed:
|
||||
txin.scriptSig << static_cast<valtype>(subscript);
|
||||
if (!fSolved) return false;
|
||||
}
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
assert(txin.prevout.n < txFrom.vout.size());
|
||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||
|
||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
||||
}
|
||||
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
{
|
||||
CScript result;
|
||||
BOOST_FOREACH(const valtype& v, values)
|
||||
result << v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
|
||||
const vector<valtype>& vSolutions,
|
||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||
{
|
||||
// Combine all the signatures we've got:
|
||||
set<valtype> allsigs;
|
||||
BOOST_FOREACH(const valtype& v, sigs1)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
}
|
||||
BOOST_FOREACH(const valtype& v, sigs2)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
}
|
||||
|
||||
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
||||
assert(vSolutions.size() > 1);
|
||||
unsigned int nSigsRequired = vSolutions.front()[0];
|
||||
unsigned int nPubKeys = vSolutions.size()-2;
|
||||
map<valtype, valtype> sigs;
|
||||
BOOST_FOREACH(const valtype& sig, allsigs)
|
||||
{
|
||||
for (unsigned int i = 0; i < nPubKeys; i++)
|
||||
{
|
||||
const valtype& pubkey = vSolutions[i+1];
|
||||
if (sigs.count(pubkey))
|
||||
continue; // Already got a sig for this pubkey
|
||||
|
||||
if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
|
||||
{
|
||||
sigs[pubkey] = sig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now build a merged CScript:
|
||||
unsigned int nSigsHave = 0;
|
||||
CScript result; result << OP_0; // pop-one-too-many workaround
|
||||
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
|
||||
{
|
||||
if (sigs.count(vSolutions[i+1]))
|
||||
{
|
||||
result << sigs[vSolutions[i+1]];
|
||||
++nSigsHave;
|
||||
}
|
||||
}
|
||||
// Fill any missing with OP_0:
|
||||
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
||||
result << OP_0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const txnouttype txType, const vector<valtype>& vSolutions,
|
||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||
{
|
||||
switch (txType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
// Don't know anything about this, assume bigger one is correct:
|
||||
if (sigs1.size() >= sigs2.size())
|
||||
return PushAll(sigs1);
|
||||
return PushAll(sigs2);
|
||||
case TX_PUBKEY:
|
||||
case TX_PUBKEYHASH:
|
||||
// Signatures are bigger than placeholders or empty scripts:
|
||||
if (sigs1.empty() || sigs1[0].empty())
|
||||
return PushAll(sigs2);
|
||||
return PushAll(sigs1);
|
||||
case TX_SCRIPTHASH:
|
||||
if (sigs1.empty() || sigs1.back().empty())
|
||||
return PushAll(sigs2);
|
||||
else if (sigs2.empty() || sigs2.back().empty())
|
||||
return PushAll(sigs1);
|
||||
else
|
||||
{
|
||||
// Recur to combine:
|
||||
valtype spk = sigs1.back();
|
||||
CScript pubKey2(spk.begin(), spk.end());
|
||||
|
||||
txnouttype txType2;
|
||||
vector<vector<unsigned char> > vSolutions2;
|
||||
Solver(pubKey2, txType2, vSolutions2);
|
||||
sigs1.pop_back();
|
||||
sigs2.pop_back();
|
||||
CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
|
||||
result << spk;
|
||||
return result;
|
||||
}
|
||||
case TX_MULTISIG:
|
||||
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
|
||||
}
|
||||
|
||||
return CScript();
|
||||
}
|
||||
|
||||
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
||||
{
|
||||
txnouttype txType;
|
||||
vector<vector<unsigned char> > vSolutions;
|
||||
Solver(scriptPubKey, txType, vSolutions);
|
||||
|
||||
vector<valtype> stack1;
|
||||
EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
||||
vector<valtype> stack2;
|
||||
EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
|
||||
|
||||
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
||||
}
|
23
src/script/sign.h
Normal file
23
src/script/sign.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPT_SIGN
|
||||
#define H_BITCOIN_SCRIPT_SIGN
|
||||
|
||||
#include "script/interpreter.h"
|
||||
|
||||
class CKeyStore;
|
||||
class CScript;
|
||||
class CTransaction;
|
||||
struct CMutableTransaction;
|
||||
|
||||
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
|
||||
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
|
||||
// combine them intelligently and return the result.
|
||||
CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||
|
||||
#endif
|
254
src/script/standard.cpp
Normal file
254
src/script/standard.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script/standard.h"
|
||||
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
const char* GetTxnOutputType(txnouttype t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case TX_NONSTANDARD: return "nonstandard";
|
||||
case TX_PUBKEY: return "pubkey";
|
||||
case TX_PUBKEYHASH: return "pubkeyhash";
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
|
||||
//
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
|
||||
{
|
||||
// Templates
|
||||
static multimap<txnouttype, CScript> mTemplates;
|
||||
if (mTemplates.empty())
|
||||
{
|
||||
// Standard tx, sender provides pubkey, receiver adds signature
|
||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
|
||||
|
||||
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
|
||||
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
|
||||
|
||||
// Sender provides N pubkeys, receivers provides M signatures
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||
|
||||
// Empty, provably prunable, data-carrying output
|
||||
if (GetBoolArg("-datacarrier", true))
|
||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
|
||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
|
||||
}
|
||||
|
||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||
if (scriptPubKey.IsPayToScriptHash())
|
||||
{
|
||||
typeRet = TX_SCRIPTHASH;
|
||||
vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
|
||||
vSolutionsRet.push_back(hashBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
{
|
||||
const CScript& script2 = tplate.second;
|
||||
vSolutionsRet.clear();
|
||||
|
||||
opcodetype opcode1, opcode2;
|
||||
vector<unsigned char> vch1, vch2;
|
||||
|
||||
// Compare
|
||||
CScript::const_iterator pc1 = script1.begin();
|
||||
CScript::const_iterator pc2 = script2.begin();
|
||||
while (true)
|
||||
{
|
||||
if (pc1 == script1.end() && pc2 == script2.end())
|
||||
{
|
||||
// Found a match
|
||||
typeRet = tplate.first;
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
// Additional checks for TX_MULTISIG:
|
||||
unsigned char m = vSolutionsRet.front()[0];
|
||||
unsigned char n = vSolutionsRet.back()[0];
|
||||
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
break;
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
break;
|
||||
|
||||
// Template matching opcodes:
|
||||
if (opcode2 == OP_PUBKEYS)
|
||||
{
|
||||
while (vch1.size() >= 33 && vch1.size() <= 65)
|
||||
{
|
||||
vSolutionsRet.push_back(vch1);
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
break;
|
||||
}
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
break;
|
||||
// Normal situation is to fall through
|
||||
// to other if/else statements
|
||||
}
|
||||
|
||||
if (opcode2 == OP_PUBKEY)
|
||||
{
|
||||
if (vch1.size() < 33 || vch1.size() > 65)
|
||||
break;
|
||||
vSolutionsRet.push_back(vch1);
|
||||
}
|
||||
else if (opcode2 == OP_PUBKEYHASH)
|
||||
{
|
||||
if (vch1.size() != sizeof(uint160))
|
||||
break;
|
||||
vSolutionsRet.push_back(vch1);
|
||||
}
|
||||
else if (opcode2 == OP_SMALLINTEGER)
|
||||
{ // Single-byte small integer pushed onto vSolutions
|
||||
if (opcode1 == OP_0 ||
|
||||
(opcode1 >= OP_1 && opcode1 <= OP_16))
|
||||
{
|
||||
char n = (char)CScript::DecodeOP_N(opcode1);
|
||||
vSolutionsRet.push_back(valtype(1, n));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (opcode2 == OP_SMALLDATA)
|
||||
{
|
||||
// small pushdata, <= MAX_OP_RETURN_RELAY bytes
|
||||
if (vch1.size() > MAX_OP_RETURN_RELAY)
|
||||
break;
|
||||
}
|
||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||
{
|
||||
// Others must match exactly
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vSolutionsRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
return -1;
|
||||
case TX_PUBKEY:
|
||||
return 1;
|
||||
case TX_PUBKEYHASH:
|
||||
return 2;
|
||||
case TX_MULTISIG:
|
||||
if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
|
||||
return -1;
|
||||
return vSolutions[0][0] + 1;
|
||||
case TX_SCRIPTHASH:
|
||||
return 1; // doesn't include args needed by the script
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_MULTISIG)
|
||||
{
|
||||
unsigned char m = vSolutions.front()[0];
|
||||
unsigned char n = vSolutions.back()[0];
|
||||
// Support up to x-of-3 multisig txns as standard
|
||||
if (n < 1 || n > 3)
|
||||
return false;
|
||||
if (m < 1 || m > n)
|
||||
return false;
|
||||
}
|
||||
|
||||
return whichType != TX_NONSTANDARD;
|
||||
}
|
||||
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_PUBKEY)
|
||||
{
|
||||
addressRet = CPubKey(vSolutions[0]).GetID();
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_PUBKEYHASH)
|
||||
{
|
||||
addressRet = CKeyID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
addressRet = CScriptID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
// Multisig txns have more than one address...
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
|
||||
{
|
||||
addressRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
||||
return false;
|
||||
if (typeRet == TX_NULL_DATA){
|
||||
// This is data, not addresses
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
nRequiredRet = vSolutions.front()[0];
|
||||
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
||||
{
|
||||
CTxDestination address = CPubKey(vSolutions[i]).GetID();
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nRequiredRet = 1;
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(scriptPubKey, address))
|
||||
return false;
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
56
src/script/standard.h
Normal file
56
src/script/standard.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPT_STANDARD
|
||||
#define H_BITCOIN_SCRIPT_STANDARD
|
||||
|
||||
#include "script/script.h"
|
||||
#include "script/interpreter.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class CScript;
|
||||
|
||||
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
|
||||
|
||||
// Mandatory script verification flags that all new blocks must comply with for
|
||||
// them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
// but in the future other flags may be added, such as a soft-fork to enforce
|
||||
// strict DER encoding.
|
||||
//
|
||||
// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
// details.
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||
|
||||
// Standard script verification flags that standard transactions will comply
|
||||
// with. However scripts violating these flags may still be present in valid
|
||||
// blocks and we must accept those blocks.
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_NULLDUMMY;
|
||||
|
||||
// For convenience, standard but not mandatory verify flags.
|
||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||
|
||||
enum txnouttype
|
||||
{
|
||||
TX_NONSTANDARD,
|
||||
// 'standard' transaction types:
|
||||
TX_PUBKEY,
|
||||
TX_PUBKEYHASH,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_NULL_DATA,
|
||||
};
|
||||
|
||||
const char* GetTxnOutputType(txnouttype t);
|
||||
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||
|
||||
#endif
|
127
src/scriptutils.cpp
Normal file
127
src/scriptutils.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "scriptutils.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "script/standard.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
{
|
||||
unsigned int nResult = 0;
|
||||
BOOST_FOREACH(const valtype& pubkey, pubkeys)
|
||||
{
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (keystore.HaveKey(keyID))
|
||||
++nResult;
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
|
||||
{
|
||||
CScript script;
|
||||
script.SetDestination(dest);
|
||||
return IsMine(keystore, script);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions)) {
|
||||
if (keystore.HaveWatchOnly(scriptPubKey))
|
||||
return ISMINE_WATCH_ONLY;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
CKeyID keyID;
|
||||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
break;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if (keystore.HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (keystore.HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
case TX_SCRIPTHASH:
|
||||
{
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
isminetype ret = IsMine(keystore, subscript);
|
||||
if (ret == ISMINE_SPENDABLE)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_MULTISIG:
|
||||
{
|
||||
// Only consider transactions "mine" if we own ALL the
|
||||
// keys involved. multi-signature transactions that are
|
||||
// partially owned (somebody else has a key that can spend
|
||||
// them) enable spend-out-from-under-you attacks, especially
|
||||
// in shared-wallet situations.
|
||||
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
||||
if (HaveKeys(keys, keystore) == keys.size())
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keystore.HaveWatchOnly(scriptPubKey))
|
||||
return ISMINE_WATCH_ONLY;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
class CAffectedKeysVisitor : public boost::static_visitor<void> {
|
||||
private:
|
||||
const CKeyStore &keystore;
|
||||
std::vector<CKeyID> &vKeys;
|
||||
|
||||
public:
|
||||
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
|
||||
|
||||
void Process(const CScript &script) {
|
||||
txnouttype type;
|
||||
std::vector<CTxDestination> vDest;
|
||||
int nRequired;
|
||||
if (ExtractDestinations(script, type, vDest, nRequired)) {
|
||||
BOOST_FOREACH(const CTxDestination &dest, vDest)
|
||||
boost::apply_visitor(*this, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const CKeyID &keyId) {
|
||||
if (keystore.HaveKey(keyId))
|
||||
vKeys.push_back(keyId);
|
||||
}
|
||||
|
||||
void operator()(const CScriptID &scriptId) {
|
||||
CScript script;
|
||||
if (keystore.GetCScript(scriptId, script))
|
||||
Process(script);
|
||||
}
|
||||
|
||||
void operator()(const CNoDestination &none) {}
|
||||
};
|
||||
|
||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
|
||||
CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
|
||||
}
|
29
src/scriptutils.h
Normal file
29
src/scriptutils.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPTUTILS
|
||||
#define H_BITCOIN_SCRIPTUTILS
|
||||
|
||||
#include "key.h"
|
||||
#include "script/script.h"
|
||||
|
||||
class CKeyStore;
|
||||
|
||||
/** IsMine() return codes */
|
||||
enum isminetype
|
||||
{
|
||||
ISMINE_NO = 0,
|
||||
ISMINE_WATCH_ONLY = 1,
|
||||
ISMINE_SPENDABLE = 2,
|
||||
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
|
||||
};
|
||||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
|
||||
|
||||
#endif // H_BITCOIN_SCRIPT
|
|
@ -12,7 +12,7 @@
|
|||
#include "main.h"
|
||||
#include "net.h"
|
||||
#include "pow.h"
|
||||
#include "script.h"
|
||||
#include "script/sign.h"
|
||||
#include "serialize.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "data/base58_keys_valid.json.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
|
||||
#include "data/sig_noncanonical.json.h"
|
||||
#include "data/sig_canonical.json.h"
|
||||
#include "key.h"
|
||||
#include "random.h"
|
||||
#include "script.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "key.h"
|
||||
|
||||
#include "base58.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "script/sign.h"
|
||||
#include "scriptutils.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "scriptutils.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script.h"
|
||||
|
||||
#include "data/script_invalid.json.h"
|
||||
#include "data/script_valid.json.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "core_io.h"
|
||||
|
||||
#include <fstream>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "bignum.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include "main.h"
|
||||
#include "random.h"
|
||||
#include "serialize.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "util.h"
|
||||
#include "version.h"
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "key.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <vector>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "script.h"
|
||||
#include "script/script.h"
|
||||
#include "core_io.h"
|
||||
|
||||
#include <map>
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "checkpoints.h"
|
||||
#include "coincontrol.h"
|
||||
#include "net.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "timedata.h"
|
||||
#include "util.h"
|
||||
#include "utilmoneystr.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
#include "scriptutils.h"
|
||||
#include "ui_interface.h"
|
||||
#include "walletdb.h"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue