mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
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 \
|
rpcclient.h \
|
||||||
rpcprotocol.h \
|
rpcprotocol.h \
|
||||||
rpcserver.h \
|
rpcserver.h \
|
||||||
script.h \
|
script/interpreter.h \
|
||||||
|
script/compressor.h \
|
||||||
|
script/script.h \
|
||||||
|
script/sign.h \
|
||||||
|
script/standard.h \
|
||||||
|
scriptutils.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
sync.h \
|
sync.h \
|
||||||
threadsafety.h \
|
threadsafety.h \
|
||||||
|
@ -206,7 +211,12 @@ libbitcoin_common_a_SOURCES = \
|
||||||
keystore.cpp \
|
keystore.cpp \
|
||||||
netbase.cpp \
|
netbase.cpp \
|
||||||
protocol.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)
|
$(BITCOIN_CORE_H)
|
||||||
|
|
||||||
# util: shared between all executables.
|
# util: shared between all executables.
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "main.h" // for MAX_BLOCK_SIZE
|
#include "main.h" // for MAX_BLOCK_SIZE
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "ui_interface.h" // for _(...)
|
#include "ui_interface.h" // for _(...)
|
||||||
#include "univalue/univalue.h"
|
#include "univalue/univalue.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
#include "bloom.h"
|
#include "bloom.h"
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/standard.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
#ifndef BITCOIN_CORE_H
|
#ifndef BITCOIN_CORE_H
|
||||||
#define BITCOIN_CORE_H
|
#define BITCOIN_CORE_H
|
||||||
|
|
||||||
#include "script.h"
|
#include "script/compressor.h"
|
||||||
|
#include "script/script.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <boost/assign/list_of.hpp>
|
#include <boost/assign/list_of.hpp>
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "univalue/univalue.h"
|
#include "univalue/univalue.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/standard.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "crypter.h"
|
#include "crypter.h"
|
||||||
|
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "crypter.h"
|
#include "crypter.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/standard.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "paymentserver.h"
|
#include "paymentserver.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "transactionrecord.h"
|
#include "transactionrecord.h"
|
||||||
#include "timedata.h"
|
#include "timedata.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
|
#include "script/script.h"
|
||||||
|
#include "script/standard.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
#include "wallet.h"
|
#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
|
#define H_BITCOIN_SCRIPT
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "utilstrencodings.h"
|
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
|
#include "utilstrencodings.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdint.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#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_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 */
|
/** Script opcodes */
|
||||||
enum opcodetype
|
enum opcodetype
|
||||||
|
@ -386,7 +152,6 @@ enum opcodetype
|
||||||
OP_NOP10 = 0xb9,
|
OP_NOP10 = 0xb9,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// template matching params
|
// template matching params
|
||||||
OP_SMALLDATA = 0xf9,
|
OP_SMALLDATA = 0xf9,
|
||||||
OP_SMALLINTEGER = 0xfa,
|
OP_SMALLINTEGER = 0xfa,
|
||||||
|
@ -399,7 +164,153 @@ enum opcodetype
|
||||||
|
|
||||||
const char* GetOpName(opcodetype opcode);
|
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)
|
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);
|
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 */
|
/** Serialized script, used inside transaction inputs and outputs */
|
||||||
class CScript : public std::vector<unsigned char>
|
class CScript : public std::vector<unsigned char>
|
||||||
{
|
{
|
||||||
|
@ -446,7 +371,6 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CScript(int64_t b) { operator<<(b); }
|
CScript(int64_t b) { operator<<(b); }
|
||||||
|
|
||||||
explicit CScript(opcodetype b) { operator<<(b); }
|
explicit CScript(opcodetype b) { operator<<(b); }
|
||||||
|
@ -718,98 +642,4 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Compact serializer for scripts.
|
#endif
|
||||||
*
|
|
||||||
* 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
|
|
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 "main.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "script.h"
|
#include "script/sign.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "data/base58_keys_valid.json.h"
|
#include "data/base58_keys_valid.json.h"
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
|
|
||||||
#include "data/sig_noncanonical.json.h"
|
#include "data/sig_noncanonical.json.h"
|
||||||
#include "data/sig_canonical.json.h"
|
#include "data/sig_canonical.json.h"
|
||||||
|
#include "key.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "script.h"
|
#include "script/interpreter.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "utilstrencodings.h"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.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 "uint256.h"
|
||||||
|
|
||||||
#include <boost/assign/std/vector.hpp>
|
#include <boost/assign/std/vector.hpp>
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "script.h"
|
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
|
#include "scriptutils.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "script.h"
|
|
||||||
|
|
||||||
#include "data/script_invalid.json.h"
|
#include "data/script_invalid.json.h"
|
||||||
#include "data/script_valid.json.h"
|
#include "data/script_valid.json.h"
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "bignum.h"
|
#include "bignum.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
|
#include "script/interpreter.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script.h"
|
#include "script/script.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "coincontrol.h"
|
#include "coincontrol.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "script/script.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "timedata.h"
|
#include "timedata.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "scriptutils.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
#include "walletdb.h"
|
#include "walletdb.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue