diff --git a/src/Makefile.am b/src/Makefile.am index 35fca6570..9b7e99861 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -98,7 +98,12 @@ BITCOIN_CORE_H = \ rpcclient.h \ rpcprotocol.h \ rpcserver.h \ - script.h \ + script/interpreter.h \ + script/compressor.h \ + script/script.h \ + script/sign.h \ + script/standard.h \ + scriptutils.h \ serialize.h \ sync.h \ threadsafety.h \ @@ -206,7 +211,12 @@ libbitcoin_common_a_SOURCES = \ keystore.cpp \ netbase.cpp \ protocol.cpp \ - script.cpp \ + script/interpreter.cpp \ + script/compressor.cpp \ + script/script.cpp \ + script/sign.cpp \ + script/standard.cpp \ + scriptutils.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. diff --git a/src/base58.h b/src/base58.h index 70681f589..216aca364 100644 --- a/src/base58.h +++ b/src/base58.h @@ -16,7 +16,7 @@ #include "chainparams.h" #include "key.h" -#include "script.h" +#include "script/script.h" #include #include diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 5f547bba8..c45535141 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -8,6 +8,8 @@ #include "core.h" #include "main.h" // for MAX_BLOCK_SIZE #include "keystore.h" +#include "script/script.h" +#include "script/sign.h" #include "ui_interface.h" // for _(...) #include "univalue/univalue.h" #include "core_io.h" diff --git a/src/bloom.cpp b/src/bloom.cpp index e34041336..cef74a3a5 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -5,7 +5,8 @@ #include "bloom.h" #include "core.h" -#include "script.h" +#include "script/script.h" +#include "script/standard.h" #include #include diff --git a/src/core.h b/src/core.h index cde8d8b3f..030eb1773 100644 --- a/src/core.h +++ b/src/core.h @@ -6,7 +6,8 @@ #ifndef BITCOIN_CORE_H #define BITCOIN_CORE_H -#include "script.h" +#include "script/compressor.h" +#include "script/script.h" #include "serialize.h" #include "uint256.h" diff --git a/src/core_read.cpp b/src/core_read.cpp index 57f1397f1..efcecb106 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -5,7 +5,7 @@ #include "core_io.h" #include "core.h" #include "serialize.h" -#include "script.h" +#include "script/script.h" #include "util.h" #include diff --git a/src/core_write.cpp b/src/core_write.cpp index e66e75515..62712b1ba 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -4,7 +4,8 @@ #include "core_io.h" #include "univalue/univalue.h" -#include "script.h" +#include "script/script.h" +#include "script/standard.h" #include "core.h" #include "serialize.h" #include "util.h" diff --git a/src/crypter.cpp b/src/crypter.cpp index 8aa2bb051..3df13021d 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -4,7 +4,7 @@ #include "crypter.h" -#include "script.h" +#include "script/script.h" #include "util.h" #include diff --git a/src/keystore.cpp b/src/keystore.cpp index 72ae9b0a3..98bc0e9e2 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -7,7 +7,7 @@ #include "crypter.h" #include "key.h" -#include "script.h" +#include "script/script.h" #include "util.h" #include diff --git a/src/main.h b/src/main.h index 8c0a743e2..30cccab2f 100644 --- a/src/main.h +++ b/src/main.h @@ -15,7 +15,8 @@ #include "core.h" #include "net.h" #include "pow.h" -#include "script.h" +#include "script/script.h" +#include "script/standard.h" #include "sync.h" #include "txmempool.h" #include "uint256.h" diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 8258e719a..727b8dc66 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -11,7 +11,7 @@ #include "db.h" #include "main.h" #include "paymentserver.h" -#include "script.h" +#include "script/script.h" #include "transactionrecord.h" #include "timedata.h" #include "ui_interface.h" diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index a73641834..b5551524b 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -11,6 +11,9 @@ #include "main.h" #include "net.h" #include "rpcserver.h" +#include "script/script.h" +#include "script/standard.h" +#include "script/sign.h" #include "uint256.h" #ifdef ENABLE_WALLET #include "wallet.h" diff --git a/src/script/compressor.cpp b/src/script/compressor.cpp new file mode 100644 index 000000000..2f8df602b --- /dev/null +++ b/src/script/compressor.cpp @@ -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 &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 &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; +} diff --git a/src/script/compressor.h b/src/script/compressor.h new file mode 100644 index 000000000..f0a3754f0 --- /dev/null +++ b/src/script/compressor.h @@ -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 &out) const; + unsigned int GetSpecialSize(unsigned int nSize) const; + bool Decompress(unsigned int nSize, const std::vector &out); +public: + CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } + + unsigned int GetSerializeSize(int nType, int nVersion) const { + std::vector compr; + if (Compress(compr)) + return compr.size(); + unsigned int nSize = script.size() + nSpecialScripts; + return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); + } + + template + void Serialize(Stream &s, int nType, int nVersion) const { + std::vector compr; + if (Compress(compr)) { + s << CFlatData(compr); + return; + } + unsigned int nSize = script.size() + nSpecialScripts; + s << VARINT(nSize); + s << CFlatData(script); + } + + template + void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int nSize = 0; + s >> VARINT(nSize); + if (nSize < nSpecialScripts) { + std::vector vch(GetSpecialSize(nSize), 0x00); + s >> REF(CFlatData(vch)); + Decompress(nSize, vch); + return; + } + nSize -= nSpecialScripts; + script.resize(nSize); + s >> REF(CFlatData(script)); + } +}; + +#endif diff --git a/src/script.cpp b/src/script/interpreter.cpp similarity index 52% rename from src/script.cpp rename to src/script/interpreter.cpp index f3d423a42..4f4fdb6b7 100644 --- a/src/script.cpp +++ b/src/script/interpreter.cpp @@ -3,27 +3,21 @@ // 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 "interpreter.h" +#include "core.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha2.h" -#include "core.h" -#include "hash.h" -#include "key.h" -#include "keystore.h" #include "random.h" -#include "sync.h" +#include "script/script.h" #include "uint256.h" #include "util.h" -#include #include -#include #include using namespace std; -using namespace boost; typedef vector valtype; static const valtype vchFalse(0); @@ -34,8 +28,6 @@ static const CScriptNum bnOne(1); static const CScriptNum bnFalse(0); static const CScriptNum bnTrue(1); -bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); - bool CastToBool(const valtype& vch) { for (unsigned int i = 0; i < vch.size(); i++) @@ -51,8 +43,6 @@ bool CastToBool(const valtype& vch) return false; } - - // // Script is a stack machine (like Forth) that evaluates a predicate // returning a bool indicating valid or not. There are no loops. @@ -66,165 +56,6 @@ static inline void popstack(vector& stack) stack.pop_back(); } - -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; -} - - -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"; - } -} - bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { if (!(flags & SCRIPT_VERIFY_STRICTENC)) return true; @@ -962,19 +793,12 @@ bool EvalScript(vector >& stack, const CScript& script, co return false; } - if (!vfExec.empty()) return false; return true; } - - - - - - namespace { /** Wrapper that serializes like CTransaction, but with the modifications @@ -1151,8 +975,7 @@ public: } }; -bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, - const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) +bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; @@ -1183,426 +1006,6 @@ bool CheckSig(vector vchSig, const vector &vchPubK return true; } - - - - - - - - -// -// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. -// -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) -{ - // Templates - static multimap 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 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 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; -} - - -bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) -{ - CKey key; - if (!keystore.GetKey(address, key)) - return false; - - vector vchSig; - if (!key.Sign(hash, vchSig)) - return false; - vchSig.push_back((unsigned char)nHashType); - scriptSigRet << vchSig; - - return true; -} - -bool SignN(const vector& 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 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; -} - -int ScriptSigArgsExpected(txnouttype t, const std::vector >& 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 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; -} - - -unsigned int HaveKeys(const vector& 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 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 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; -} - -bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) -{ - vector 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& addressRet, int& nRequiredRet) -{ - addressRet.clear(); - typeRet = TX_NONSTANDARD; - vector 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; -} - -class CAffectedKeysVisitor : public boost::static_visitor { -private: - const CKeyStore &keystore; - std::vector &vKeys; - -public: - CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} - - void Process(const CScript &script) { - txnouttype type; - std::vector 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 &vKeys) { - CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); -} - bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { @@ -1643,437 +1046,3 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return true; } - - -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(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& 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& vSolutions, - vector& sigs1, vector& sigs2) -{ - // Combine all the signatures we've got: - set 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 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& vSolutions, - vector& sigs1, vector& 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 > 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 > vSolutions; - Solver(scriptPubKey, txType, vSolutions); - - vector stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); - vector stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); - - return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); -} - -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 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()) - { - // Note how a script with an invalid PUSHDATA returns False. - 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 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 -{ -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& keys) -{ - this->clear(); - - *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CPubKey& key, keys) - *this << key; - *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; -} - -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 &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 &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; -} diff --git a/src/script/interpreter.h b/src/script/interpreter.h new file mode 100644 index 000000000..0c6f8b9d1 --- /dev/null +++ b/src/script/interpreter.h @@ -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 +#include +#include + +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 ( &vchPubKey, unsigned int flags); +bool IsCanonicalSignature(const std::vector &vchSig, unsigned int flags); + +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool CheckSig(std::vector vchSig, const std::vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); +bool EvalScript(std::vector >& 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 diff --git a/src/script/script.cpp b/src/script/script.cpp new file mode 100644 index 000000000..60d1beac9 --- /dev/null +++ b/src/script/script.cpp @@ -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 + +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 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 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 +{ +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& keys) +{ + this->clear(); + + *this << EncodeOP_N(nRequired); + BOOST_FOREACH(const CPubKey& key, keys) + *this << key; + *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; +} diff --git a/src/script.h b/src/script/script.h similarity index 71% rename from src/script.h rename to src/script/script.h index d17cfe3fa..21847c09b 100644 --- a/src/script.h +++ b/src/script/script.h @@ -7,248 +7,14 @@ #define H_BITCOIN_SCRIPT #include "key.h" -#include "utilstrencodings.h" #include "tinyformat.h" +#include "utilstrencodings.h" #include -#include -#include -#include #include -class CKeyStore; -class CTransaction; -struct CMutableTransaction; - static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes -static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes - -class scriptnum_error : public std::runtime_error -{ -public: - explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {} -}; - -class CScriptNum -{ -// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. -// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], -// but results may overflow (and are valid as long as they are not used in a subsequent -// numeric operation). CScriptNum enforces those semantics by storing results as -// an int64 and allowing out-of-range values to be returned as a vector of bytes but -// throwing an exception if arithmetic is done or the result is interpreted as an integer. -public: - - explicit CScriptNum(const int64_t& n) - { - m_value = n; - } - - explicit CScriptNum(const std::vector& vch) - { - if (vch.size() > nMaxNumSize) - throw scriptnum_error("CScriptNum(const std::vector&) : 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::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::max() - rhs) || - (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)); - m_value += rhs; - return *this; - } - - inline CScriptNum& operator-=( const int64_t& rhs) - { - assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || - (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)); - m_value -= rhs; - return *this; - } - - int getint() const - { - if (m_value > std::numeric_limits::max()) - return std::numeric_limits::max(); - else if (m_value < std::numeric_limits::min()) - return std::numeric_limits::min(); - return m_value; - } - - std::vector getvch() const - { - return serialize(m_value); - } - - static std::vector serialize(const int64_t& value) - { - if(value == 0) - return std::vector(); - - std::vector 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& vch) - { - if (vch.empty()) - return 0; - - int64_t result = 0; - for (size_t i = 0; i != vch.size(); ++i) - result |= static_cast(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 ( CTxDestination; - -const char* GetTxnOutputType(txnouttype t); /** Script opcodes */ enum opcodetype @@ -386,7 +152,6 @@ enum opcodetype OP_NOP10 = 0xb9, - // template matching params OP_SMALLDATA = 0xf9, OP_SMALLINTEGER = 0xfa, @@ -399,7 +164,153 @@ enum opcodetype const char* GetOpName(opcodetype opcode); +class scriptnum_error : public std::runtime_error +{ +public: + explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {} +}; +class CScriptNum +{ +// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. +// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], +// but results may overflow (and are valid as long as they are not used in a subsequent +// numeric operation). CScriptNum enforces those semantics by storing results as +// an int64 and allowing out-of-range values to be returned as a vector of bytes but +// throwing an exception if arithmetic is done or the result is interpreted as an integer. +public: + + explicit CScriptNum(const int64_t& n) + { + m_value = n; + } + + explicit CScriptNum(const std::vector& vch) + { + if (vch.size() > nMaxNumSize) + throw scriptnum_error("CScriptNum(const std::vector&) : 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::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::max() - rhs) || + (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)); + m_value += rhs; + return *this; + } + + inline CScriptNum& operator-=( const int64_t& rhs) + { + assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || + (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)); + m_value -= rhs; + return *this; + } + + int getint() const + { + if (m_value > std::numeric_limits::max()) + return std::numeric_limits::max(); + else if (m_value < std::numeric_limits::min()) + return std::numeric_limits::min(); + return m_value; + } + + std::vector getvch() const + { + return serialize(m_value); + } + + static std::vector serialize(const int64_t& value) + { + if(value == 0) + return std::vector(); + + std::vector 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& vch) + { + if (vch.empty()) + return 0; + + int64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast(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& vch) { @@ -409,6 +320,20 @@ inline std::string ValueString(const std::vector& 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 CTxDestination; + /** Serialized script, used inside transaction inputs and outputs */ class CScript : public std::vector { @@ -446,7 +371,6 @@ public: return ret; } - CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } @@ -718,98 +642,4 @@ public: } }; -/** Compact serializer for scripts. - * - * It detects common cases and encodes them much more efficiently. - * 3 special cases are defined: - * * Pay to pubkey hash (encoded as 21 bytes) - * * Pay to script hash (encoded as 21 bytes) - * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) - * - * Other scripts up to 121 bytes require 1 byte + script length. Above - * that, scripts up to 16505 bytes require 2 bytes + script length. - */ -class CScriptCompressor -{ -private: - // make this static for now (there are only 6 special scripts defined) - // this can potentially be extended together with a new nVersion for - // transactions, in which case this value becomes dependent on nVersion - // and nHeight of the enclosing transaction. - static const unsigned int nSpecialScripts = 6; - - CScript &script; -protected: - // These check for scripts for which a special case with a shorter encoding is defined. - // They are implemented separately from the CScript test, as these test for exact byte - // sequence correspondences, and are more strict. For example, IsToPubKey also verifies - // whether the public key is valid (as invalid ones cannot be represented in compressed - // form). - bool IsToKeyID(CKeyID &hash) const; - bool IsToScriptID(CScriptID &hash) const; - bool IsToPubKey(CPubKey &pubkey) const; - - bool Compress(std::vector &out) const; - unsigned int GetSpecialSize(unsigned int nSize) const; - bool Decompress(unsigned int nSize, const std::vector &out); -public: - CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } - - unsigned int GetSerializeSize(int nType, int nVersion) const { - std::vector compr; - if (Compress(compr)) - return compr.size(); - unsigned int nSize = script.size() + nSpecialScripts; - return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); - } - - template - void Serialize(Stream &s, int nType, int nVersion) const { - std::vector compr; - if (Compress(compr)) { - s << CFlatData(compr); - return; - } - unsigned int nSize = script.size() + nSpecialScripts; - s << VARINT(nSize); - s << CFlatData(script); - } - - template - void Unserialize(Stream &s, int nType, int nVersion) { - unsigned int nSize = 0; - s >> VARINT(nSize); - if (nSize < nSpecialScripts) { - std::vector 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 &vchPubKey, unsigned int flags); -bool IsCanonicalSignature(const std::vector &vchSig, unsigned int flags); - -bool EvalScript(std::vector >& 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 >& vSolutionsRet); -int ScriptSigArgsExpected(txnouttype t, const std::vector >& 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 &vKeys); -bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); -bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); -bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); - -// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, -// combine them intelligently and return the result. -CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); - -#endif // H_BITCOIN_SCRIPT +#endif diff --git a/src/script/sign.cpp b/src/script/sign.cpp new file mode 100644 index 000000000..958177de3 --- /dev/null +++ b/src/script/sign.cpp @@ -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 + +using namespace std; + +typedef vector 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 vchSig; + if (!key.Sign(hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + + return true; +} + +bool SignN(const vector& 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 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(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& 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& vSolutions, + vector& sigs1, vector& sigs2) +{ + // Combine all the signatures we've got: + set 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 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& vSolutions, + vector& sigs1, vector& 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 > 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 > vSolutions; + Solver(scriptPubKey, txType, vSolutions); + + vector stack1; + EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); + vector stack2; + EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); + + return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); +} diff --git a/src/script/sign.h b/src/script/sign.h new file mode 100644 index 000000000..51723b53a --- /dev/null +++ b/src/script/sign.h @@ -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 diff --git a/src/script/standard.cpp b/src/script/standard.cpp new file mode 100644 index 000000000..684edff4d --- /dev/null +++ b/src/script/standard.cpp @@ -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 + +using namespace std; + +typedef vector 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 >& vSolutionsRet) +{ + // Templates + static multimap 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 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 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 >& 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 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 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& addressRet, int& nRequiredRet) +{ + addressRet.clear(); + typeRet = TX_NONSTANDARD; + vector 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; +} diff --git a/src/script/standard.h b/src/script/standard.h new file mode 100644 index 000000000..18092e879 --- /dev/null +++ b/src/script/standard.h @@ -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 + +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 >& vSolutionsRet); +int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions); +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); + +#endif diff --git a/src/scriptutils.cpp b/src/scriptutils.cpp new file mode 100644 index 000000000..a636eeeda --- /dev/null +++ b/src/scriptutils.cpp @@ -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 + +using namespace std; + +typedef vector valtype; + +unsigned int HaveKeys(const vector& 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 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 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 { +private: + const CKeyStore &keystore; + std::vector &vKeys; + +public: + CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} + + void Process(const CScript &script) { + txnouttype type; + std::vector 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 &vKeys) { + CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); +} diff --git a/src/scriptutils.h b/src/scriptutils.h new file mode 100644 index 000000000..98080fc45 --- /dev/null +++ b/src/scriptutils.h @@ -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 &vKeys); + +#endif // H_BITCOIN_SCRIPT diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 8fa38c360..fa4edff63 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -12,7 +12,7 @@ #include "main.h" #include "net.h" #include "pow.h" -#include "script.h" +#include "script/sign.h" #include "serialize.h" #include "util.h" diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 0ac3e9a36..fe68e9e97 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -9,7 +9,7 @@ #include "data/base58_keys_valid.json.h" #include "key.h" -#include "script.h" +#include "script/script.h" #include "uint256.h" #include "util.h" diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp index a9798623e..a17099de7 100644 --- a/src/test/canonical_tests.cpp +++ b/src/test/canonical_tests.cpp @@ -8,9 +8,11 @@ #include "data/sig_noncanonical.json.h" #include "data/sig_canonical.json.h" +#include "key.h" #include "random.h" -#include "script.h" +#include "script/interpreter.h" #include "util.h" +#include "utilstrencodings.h" #include #include diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 864d90128..203c20731 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -5,7 +5,7 @@ #include "key.h" #include "base58.h" -#include "script.h" +#include "script/script.h" #include "uint256.h" #include "util.h" diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 02c6d095f..6c5afa130 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -5,7 +5,10 @@ #include "key.h" #include "keystore.h" #include "main.h" -#include "script.h" +#include "script/script.h" +#include "script/interpreter.h" +#include "script/sign.h" +#include "scriptutils.h" #include "uint256.h" #include diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 51ff1ffbc..b7e7487bb 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -2,12 +2,12 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script.h" - #include "key.h" #include "keystore.h" #include "main.h" -#include "script.h" +#include "script/script.h" +#include "script/sign.h" +#include "scriptutils.h" #include diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 77c44501a..88efc3896 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -2,15 +2,14 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script.h" - #include "data/script_invalid.json.h" #include "data/script_valid.json.h" #include "key.h" #include "keystore.h" #include "main.h" -#include "script.h" +#include "script/script.h" +#include "script/sign.h" #include "core_io.h" #include diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp index cd194cc4d..ac60fa426 100644 --- a/src/test/scriptnum_tests.cpp +++ b/src/test/scriptnum_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "bignum.h" -#include "script.h" +#include "script/script.h" #include #include #include diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index bff151cdd..8abde887c 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -6,7 +6,8 @@ #include "main.h" #include "random.h" #include "serialize.h" -#include "script.h" +#include "script/script.h" +#include "script/interpreter.h" #include "util.h" #include "version.h" diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 722f14a98..2d10c356a 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" -#include "script.h" +#include "script/script.h" #include "uint256.h" #include diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 03919e7c7..943568e89 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -8,7 +8,7 @@ #include "key.h" #include "keystore.h" #include "main.h" -#include "script.h" +#include "script/script.h" #include "core_io.h" #include diff --git a/src/wallet.cpp b/src/wallet.cpp index d3ad4869b..b69ed223b 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -9,6 +9,8 @@ #include "checkpoints.h" #include "coincontrol.h" #include "net.h" +#include "script/script.h" +#include "script/sign.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" diff --git a/src/wallet.h b/src/wallet.h index f8e1ebac1..6788986f8 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -11,6 +11,7 @@ #include "key.h" #include "keystore.h" #include "main.h" +#include "scriptutils.h" #include "ui_interface.h" #include "walletdb.h"