Browse Source
0.10e088d65
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
Pieter Wuille
10 years ago
37 changed files with 1513 additions and 1387 deletions
@ -0,0 +1,127 @@
@@ -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; |
||||
} |
@ -0,0 +1,84 @@
@@ -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
@ -0,0 +1,45 @@
@@ -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 |
@ -0,0 +1,295 @@
@@ -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; |
||||
} |
@ -0,0 +1,260 @@
@@ -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); |
||||
} |
@ -0,0 +1,23 @@
@@ -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 |
@ -0,0 +1,254 @@
@@ -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; |
||||
} |
@ -0,0 +1,56 @@
@@ -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 |
@ -0,0 +1,127 @@
@@ -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); |
||||
} |
@ -0,0 +1,29 @@
@@ -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
|
Loading…
Reference in new issue