diff --git a/src/Makefile.am b/src/Makefile.am index a9f1ceeeb..a3fdd3ee6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,352 +1,354 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) if USE_LIBSECP256K1 secp256k1/libsecp256k1.la: $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) @$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) endif if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv LIBLEVELDB += $(builddir)/leveldb/libleveldb.a LIBMEMENV += $(builddir)/leveldb/libmemenv.a # NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ OPT="$(CXXFLAGS) $(CPPFLAGS)" endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) if USE_LIBSECP256K1 BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include endif LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a LIBBITCOINQT=qt/libbitcoinqt.a noinst_LIBRARIES = \ libbitcoin_server.a \ libbitcoin_common.a \ libbitcoin_cli.a \ libbitcoin_util.a \ univalue/libbitcoin_univalue.a \ crypto/libbitcoin_crypto.a if ENABLE_WALLET BITCOIN_INCLUDES += $(BDB_CPPFLAGS) noinst_LIBRARIES += libbitcoin_wallet.a endif bin_PROGRAMS = TESTS = if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif if BUILD_BITCOIN_UTILS bin_PROGRAMS += bitcoin-cli bitcoin-tx endif .PHONY: FORCE # bitcoin core # BITCOIN_CORE_H = \ addrman.h \ alert.h \ allocators.h \ base58.h \ bloom.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ checkpoints.h \ checkqueue.h \ clientversion.h \ coincontrol.h \ coins.h \ compat.h \ core.h \ core_io.h \ crypter.h \ db.h \ hash.h \ init.h \ key.h \ keystore.h \ leveldbwrapper.h \ limitedmap.h \ main.h \ miner.h \ mruset.h \ netbase.h \ net.h \ noui.h \ pow.h \ protocol.h \ random.h \ rpcclient.h \ rpcprotocol.h \ rpcserver.h \ + script/interpreter.h \ script/script.h \ scriptutils.h \ serialize.h \ sync.h \ threadsafety.h \ timedata.h \ tinyformat.h \ txdb.h \ txmempool.h \ ui_interface.h \ uint256.h \ util.h \ utilstrencodings.h \ utilmoneystr.h \ utiltime.h \ version.h \ walletdb.h \ wallet.h \ compat/sanity.h JSON_H = \ json/json_spirit.h \ json/json_spirit_error_position.h \ json/json_spirit_reader.h \ json/json_spirit_reader_template.h \ json/json_spirit_stream_reader.h \ json/json_spirit_utils.h \ json/json_spirit_value.h \ json/json_spirit_writer.h \ json/json_spirit_writer_template.h obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ $(abs_top_srcdir) libbitcoin_util_a-version.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ alert.cpp \ bloom.cpp \ checkpoints.cpp \ init.cpp \ leveldbwrapper.cpp \ main.cpp \ miner.cpp \ net.cpp \ noui.cpp \ pow.cpp \ rpcblockchain.cpp \ rpcmining.cpp \ rpcmisc.cpp \ rpcnet.cpp \ rpcrawtransaction.cpp \ rpcserver.cpp \ timedata.cpp \ txdb.cpp \ txmempool.cpp \ $(JSON_H) \ $(BITCOIN_CORE_H) # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ db.cpp \ crypter.cpp \ rpcdump.cpp \ rpcwallet.cpp \ wallet.cpp \ walletdb.cpp \ $(BITCOIN_CORE_H) # crypto primitives library crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha1.cpp \ crypto/sha2.cpp \ crypto/ripemd160.cpp \ crypto/common.h \ crypto/sha2.h \ crypto/sha1.h \ crypto/ripemd160.h # univalue JSON library univalue_libbitcoin_univalue_a_SOURCES = \ univalue/univalue.cpp \ univalue/univalue_read.cpp \ univalue/univalue_write.cpp \ univalue/univalue_escapes.h \ univalue/univalue.h # common: shared between bitcoind, and bitcoin-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_common_a_SOURCES = \ allocators.cpp \ base58.cpp \ chainparams.cpp \ coins.cpp \ core.cpp \ core_read.cpp \ core_write.cpp \ hash.cpp \ key.cpp \ keystore.cpp \ netbase.cpp \ protocol.cpp \ + script/interpreter.cpp \ script/script.cpp \ scriptutils.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_util_a_SOURCES = \ compat/glibc_sanity.cpp \ compat/glibcxx_sanity.cpp \ chainparamsbase.cpp \ random.cpp \ rpcprotocol.cpp \ sync.cpp \ uint256.cpp \ util.cpp \ utilstrencodings.cpp \ utilmoneystr.cpp \ utiltime.cpp \ version.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp endif # cli: shared between bitcoin-cli and bitcoin-qt libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # # bitcoind binary # bitcoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBMEMENV) if USE_LIBSECP256K1 bitcoind_LDADD += secp256k1/libsecp256k1.la endif if ENABLE_WALLET bitcoind_LDADD += libbitcoin_wallet.a endif bitcoind_SOURCES = bitcoind.cpp # if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc endif bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) # bitcoin-cli binary # bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(BOOST_LIBS) \ $(SSL_LIBS) \ $(CRYPTO_LIBS) bitcoin_cli_SOURCES = \ bitcoin-cli.cpp if USE_LIBSECP256K1 bitcoin_cli_LDADD += secp256k1/libsecp256k1.la endif bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES) # # bitcoin-tx binary # bitcoin_tx_LDADD = \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) if USE_LIBSECP256K1 bitcoin_tx_LDADD += secp256k1/libsecp256k1.la endif bitcoin_tx_LDADD += $(BOOST_LIBS) \ $(SSL_LIBS) \ $(CRYPTO_LIBS) bitcoin_tx_SOURCES = bitcoin-tx.cpp bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES) # bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno DISTCLEANFILES = obj/build.h EXTRA_DIST = leveldb secp256k1 clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean 2>/dev/null rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h .rc.o: @test -f $(WINDRES) $(AM_V_GEN) $(WINDRES) -i $< -o $@ .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $< %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<) if ENABLE_TESTS include Makefile.test.include endif if ENABLE_QT include Makefile.qt.include endif if ENABLE_QT_TESTS include Makefile.qttest.include endif diff --git a/src/scriptutils.cpp b/src/script/interpreter.cpp similarity index 61% copy from src/scriptutils.cpp copy to src/script/interpreter.cpp index 56edc2c2d..4f4fdb6b7 100644 --- a/src/scriptutils.cpp +++ b/src/script/interpreter.cpp @@ -1,1791 +1,1048 @@ // 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 "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 <boost/foreach.hpp> #include <boost/thread.hpp> -#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple_comparison.hpp> using namespace std; -using namespace boost; typedef vector<unsigned char> valtype; static const valtype vchFalse(0); static const valtype vchZero(0); static const valtype vchTrue(1, 1); static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); static const CScriptNum bnFalse(0); static const CScriptNum bnTrue(1); -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &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++) { if (vch[i] != 0) { // Can be negative zero if (i == vch.size()-1 && vch[i] == 0x80) return false; return true; } } return false; } - - // // Script is a stack machine (like Forth) that evaluates a predicate // returning a bool indicating valid or not. There are no loops. // #define stacktop(i) (stack.at(stack.size()+(i))) #define altstacktop(i) (altstack.at(altstack.size()+(i))) static inline void popstack(vector<valtype>& stack) { if (stack.empty()) throw runtime_error("popstack() : stack empty"); 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; -} - bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { if (!(flags & SCRIPT_VERIFY_STRICTENC)) return true; if (vchPubKey.size() < 33) return error("Non-canonical public key: too short"); if (vchPubKey[0] == 0x04) { if (vchPubKey.size() != 65) return error("Non-canonical public key: invalid length for uncompressed key"); } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { if (vchPubKey.size() != 33) return error("Non-canonical public key: invalid length for compressed key"); } else { return error("Non-canonical public key: neither compressed nor uncompressed"); } return true; } bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (!(flags & SCRIPT_VERIFY_STRICTENC)) return true; // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 // A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> // Where R and S are not negative (their first byte has its highest bit not set), and not // excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, // in which case a single 0 byte is necessary and even required). if (vchSig.size() < 9) return error("Non-canonical signature: too short"); if (vchSig.size() > 73) return error("Non-canonical signature: too long"); unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) return error("Non-canonical signature: unknown hashtype byte"); if (vchSig[0] != 0x30) return error("Non-canonical signature: wrong type"); if (vchSig[1] != vchSig.size()-3) return error("Non-canonical signature: wrong length marker"); unsigned int nLenR = vchSig[3]; if (5 + nLenR >= vchSig.size()) return error("Non-canonical signature: S length misplaced"); unsigned int nLenS = vchSig[5+nLenR]; if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) return error("Non-canonical signature: R+S length mismatch"); const unsigned char *R = &vchSig[4]; if (R[-2] != 0x02) return error("Non-canonical signature: R value type mismatch"); if (nLenR == 0) return error("Non-canonical signature: R length is zero"); if (R[0] & 0x80) return error("Non-canonical signature: R value negative"); if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) return error("Non-canonical signature: R value excessively padded"); const unsigned char *S = &vchSig[6+nLenR]; if (S[-2] != 0x02) return error("Non-canonical signature: S value type mismatch"); if (nLenS == 0) return error("Non-canonical signature: S length is zero"); if (S[0] & 0x80) return error("Non-canonical signature: S value negative"); if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); if (flags & SCRIPT_VERIFY_LOW_S) { // If the S value is above the order of the curve divided by two, its // complement modulo the order could have been used instead, which is // one byte shorter when encoded correctly. if (!CKey::CheckSignatureElement(S, nLenS, true)) return error("Non-canonical signature: S value is unnecessarily high"); } return true; } bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; vector<bool> vfExec; vector<valtype> altstack; if (script.size() > 10000) return false; int nOpCount = 0; try { while (pc < pend) { bool fExec = !count(vfExec.begin(), vfExec.end(), false); // // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) return false; if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) return false; // Note how OP_RESERVED does not count towards the opcode limit. if (opcode > OP_16 && ++nOpCount > 201) return false; if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT || opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_AND || opcode == OP_OR || opcode == OP_XOR || opcode == OP_2MUL || opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) return false; // Disabled opcodes. if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) switch (opcode) { // // Push value // case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: { // ( -- value) CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; // // Control // case OP_NOP: case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; case OP_IF: case OP_NOTIF: { // <expression> if [statements] [else [statements]] endif bool fValue = false; if (fExec) { if (stack.size() < 1) return false; valtype& vch = stacktop(-1); fValue = CastToBool(vch); if (opcode == OP_NOTIF) fValue = !fValue; popstack(stack); } vfExec.push_back(fValue); } break; case OP_ELSE: { if (vfExec.empty()) return false; vfExec.back() = !vfExec.back(); } break; case OP_ENDIF: { if (vfExec.empty()) return false; vfExec.pop_back(); } break; case OP_VERIFY: { // (true -- ) or // (false -- false) and return if (stack.size() < 1) return false; bool fValue = CastToBool(stacktop(-1)); if (fValue) popstack(stack); else return false; } break; case OP_RETURN: { return false; } break; // // Stack ops // case OP_TOALTSTACK: { if (stack.size() < 1) return false; altstack.push_back(stacktop(-1)); popstack(stack); } break; case OP_FROMALTSTACK: { if (altstack.size() < 1) return false; stack.push_back(altstacktop(-1)); popstack(altstack); } break; case OP_2DROP: { // (x1 x2 -- ) if (stack.size() < 2) return false; popstack(stack); popstack(stack); } break; case OP_2DUP: { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) return false; valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_3DUP: { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) return false; valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); stack.push_back(vch3); } break; case OP_2OVER: { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) return false; valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2ROT: { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) return false; valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end()-6, stack.end()-4); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2SWAP: { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) return false; swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } break; case OP_IFDUP: { // (x - 0 | x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); if (CastToBool(vch)) stack.push_back(vch); } break; case OP_DEPTH: { // -- stacksize CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; case OP_DROP: { // (x -- ) if (stack.size() < 1) return false; popstack(stack); } break; case OP_DUP: { // (x -- x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); stack.push_back(vch); } break; case OP_NIP: { // (x1 x2 -- x2) if (stack.size() < 2) return false; stack.erase(stack.end() - 2); } break; case OP_OVER: { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) return false; valtype vch = stacktop(-2); stack.push_back(vch); } break; case OP_PICK: case OP_ROLL: { // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; int n = CScriptNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) stack.erase(stack.end()-n-1); stack.push_back(vch); } break; case OP_ROT: { // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) return false; swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } break; case OP_SWAP: { // (x1 x2 -- x2 x1) if (stack.size() < 2) return false; swap(stacktop(-2), stacktop(-1)); } break; case OP_TUCK: { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) return false; valtype vch = stacktop(-1); stack.insert(stack.end()-2, vch); } break; case OP_SIZE: { // (in -- in size) if (stack.size() < 1) return false; CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; // // Bitwise logic // case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL { // (x1 x2 - bool) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); // OP_NOTEQUAL is disabled because it would be too easy to say // something like n != 1 and have some wiseguy pass in 1 with extra // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) //if (opcode == OP_NOTEQUAL) // fEqual = !fEqual; popstack(stack); popstack(stack); stack.push_back(fEqual ? vchTrue : vchFalse); if (opcode == OP_EQUALVERIFY) { if (fEqual) popstack(stack); else return false; } } break; // // Numeric // case OP_1ADD: case OP_1SUB: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: { // (in -- out) if (stack.size() < 1) return false; CScriptNum bn(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; default: assert(!"invalid opcode"); break; } popstack(stack); stack.push_back(bn.getvch()); } break; case OP_ADD: case OP_SUB: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: { // (x1 x2 -- out) if (stack.size() < 2) return false; CScriptNum bn1(stacktop(-2)); CScriptNum bn2(stacktop(-1)); CScriptNum bn(0); switch (opcode) { case OP_ADD: bn = bn1 + bn2; break; case OP_SUB: bn = bn1 - bn2; break; case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; case OP_LESSTHAN: bn = (bn1 < bn2); break; case OP_GREATERTHAN: bn = (bn1 > bn2); break; case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; default: assert(!"invalid opcode"); break; } popstack(stack); popstack(stack); stack.push_back(bn.getvch()); if (opcode == OP_NUMEQUALVERIFY) { if (CastToBool(stacktop(-1))) popstack(stack); else return false; } } break; case OP_WITHIN: { // (x min max -- out) if (stack.size() < 3) return false; CScriptNum bn1(stacktop(-3)); CScriptNum bn2(stacktop(-2)); CScriptNum bn3(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); popstack(stack); stack.push_back(fValue ? vchTrue : vchFalse); } break; // // Crypto // case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: { // (in -- hash) if (stack.size() < 1) return false; valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_SHA1) CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_SHA256) CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_HASH160) CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_HASH256) CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); popstack(stack); stack.push_back(vchHash); } break; case OP_CODESEPARATOR: { // Hash starts after the code separator pbegincodehash = pc; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: { // (sig pubkey -- bool) if (stack.size() < 2) return false; valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKSIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; if ((int)stack.size() < i) return false; int nKeysCount = CScriptNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; if (nOpCount > 201) return false; int ikey = ++i; i += nKeysCount; if ((int)stack.size() < i) return false; int nSigsCount = CScriptNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; i += nSigsCount; if ((int)stack.size() < i) return false; // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signatures, since there's no way for a signature to sign itself for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); scriptCode.FindAndDelete(CScript(vchSig)); } bool fSuccess = true; while (fSuccess && nSigsCount > 0) { valtype& vchSig = stacktop(-isig); valtype& vchPubKey = stacktop(-ikey); // Check signature bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); if (fOk) { isig++; nSigsCount--; } ikey++; nKeysCount--; // If there are more signatures left than keys left, // then too many signatures have failed if (nSigsCount > nKeysCount) fSuccess = false; } // Clean up stack of actual arguments while (i-- > 1) popstack(stack); // A bug causes CHECKMULTISIG to consume one extra argument // whose contents were not checked in any way. // // Unfortunately this is a potential source of mutability, // so optionally verify it is exactly equal to zero prior // to removing it from the stack. if (stack.size() < 1) return false; if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) return error("CHECKMULTISIG dummy argument not null"); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; default: return false; } // Size limits if (stack.size() + altstack.size() > 1000) return false; } } catch (...) { return false; } - if (!vfExec.empty()) return false; return true; } - - - - - - namespace { /** Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ class CTransactionSignatureSerializer { private: const CTransaction &txTo; // reference to the spending transaction (the one being serialized) const CScript &scriptCode; // output script being consumed const unsigned int nIn; // input index of txTo being signed const bool fAnyoneCanPay; // whether the hashtype has the SIGHASH_ANYONECANPAY flag set const bool fHashSingle; // whether the hashtype is SIGHASH_SINGLE const bool fHashNone; // whether the hashtype is SIGHASH_NONE public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {} /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ template<typename S> void SerializeScriptCode(S &s, int nType, int nVersion) const { CScript::const_iterator it = scriptCode.begin(); CScript::const_iterator itBegin = it; opcodetype opcode; unsigned int nCodeSeparators = 0; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) nCodeSeparators++; } ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); it = itBegin; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { s.write((char*)&itBegin[0], it-itBegin-1); itBegin = it; } } s.write((char*)&itBegin[0], it-itBegin); } /** Serialize an input of txTo */ template<typename S> void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized if (fAnyoneCanPay) nInput = nIn; // Serialize the prevout ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); // Serialize the script if (nInput != nIn) // Blank out other inputs' signatures ::Serialize(s, CScript(), nType, nVersion); else SerializeScriptCode(s, nType, nVersion); // Serialize the nSequence if (nInput != nIn && (fHashSingle || fHashNone)) // let the others update at will ::Serialize(s, (int)0, nType, nVersion); else ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); } /** Serialize an output of txTo */ template<typename S> void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { if (fHashSingle && nOutput != nIn) // Do not lock-in the txout payee at other indices as txin ::Serialize(s, CTxOut(), nType, nVersion); else ::Serialize(s, txTo.vout[nOutput], nType, nVersion); } /** Serialize txTo */ template<typename S> void Serialize(S &s, int nType, int nVersion) const { // Serialize nVersion ::Serialize(s, txTo.nVersion, nType, nVersion); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); for (unsigned int nInput = 0; nInput < nInputs; nInput++) SerializeInput(s, nInput, nType, nVersion); // Serialize vout unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) SerializeOutput(s, nOutput, nType, nVersion); // Serialie nLockTime ::Serialize(s, txTo.nLockTime, nType, nVersion); } }; } // anon namespace uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { if (nIn >= txTo.vin.size()) { LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); return 1; } // Check for invalid use of SIGHASH_SINGLE if ((nHashType & 0x1f) == SIGHASH_SINGLE) { if (nIn >= txTo.vout.size()) { LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn); return 1; } } // Wrapper to serialize only the necessary parts of the transaction being signed CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; return ss.GetHash(); } // Valid signature cache, to avoid doing expensive ECDSA signature checking // twice for every transaction (once when accepted into memory pool, and // again when accepted into the block chain) class CSignatureCache { private: // sigdata_type is (signature hash, signature, public key): typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; std::set< sigdata_type> setValid; boost::shared_mutex cs_sigcache; public: bool Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) { boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); sigdata_type k(hash, vchSig, pubKey); std::set<sigdata_type>::iterator mi = setValid.find(k); if (mi != setValid.end()) return true; return false; } void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) { // DoS prevention: limit cache size to less than 10MB // (~200 bytes per cache entry times 50,000 entries) // Since there are a maximum of 20,000 signature operations per block // 50,000 is a reasonable default. int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) { // Evict a random entry. Random because that helps // foil would-be DoS attackers who might try to pre-generate // and re-use a set of valid signatures just-slightly-greater // than our cache size. uint256 randomHash = GetRandHash(); std::vector<unsigned char> unused; std::set<sigdata_type>::iterator it = setValid.lower_bound(sigdata_type(randomHash, unused, unused)); if (it == setValid.end()) it = setValid.begin(); setValid.erase(*it); } sigdata_type k(hash, vchSig, pubKey); setValid.insert(k); } }; -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, - const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) +bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) return false; if (nHashType == 0) nHashType = vchSig.back(); else if (nHashType != vchSig.back()) return false; vchSig.pop_back(); uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); if (signatureCache.Get(sighash, vchSig, pubkey)) return true; if (!pubkey.Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) signatureCache.Set(sighash, vchSig, pubkey); return true; } - - - - - - - - -// -// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. -// -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) -{ - // Templates - static multimap<txnouttype, CScript> mTemplates; - if (mTemplates.empty()) - { - // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); - - // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); - - // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); - - // Empty, provably prunable, data-carrying output - if (GetBoolArg("-datacarrier", true)) - mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA)); - mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN)); - } - - // Shortcut for pay-to-script-hash, which are more constrained than the other types: - // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL - if (scriptPubKey.IsPayToScriptHash()) - { - typeRet = TX_SCRIPTHASH; - vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); - vSolutionsRet.push_back(hashBytes); - return true; - } - - // Scan templates - const CScript& script1 = scriptPubKey; - BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) - { - const CScript& script2 = tplate.second; - vSolutionsRet.clear(); - - opcodetype opcode1, opcode2; - vector<unsigned char> vch1, vch2; - - // Compare - CScript::const_iterator pc1 = script1.begin(); - CScript::const_iterator pc2 = script2.begin(); - while (true) - { - if (pc1 == script1.end() && pc2 == script2.end()) - { - // Found a match - typeRet = tplate.first; - if (typeRet == TX_MULTISIG) - { - // Additional checks for TX_MULTISIG: - unsigned char m = vSolutionsRet.front()[0]; - unsigned char n = vSolutionsRet.back()[0]; - if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) - return false; - } - return true; - } - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - - // Template matching opcodes: - if (opcode2 == OP_PUBKEYS) - { - while (vch1.size() >= 33 && vch1.size() <= 65) - { - vSolutionsRet.push_back(vch1); - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - } - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - // Normal situation is to fall through - // to other if/else statements - } - - if (opcode2 == OP_PUBKEY) - { - if (vch1.size() < 33 || vch1.size() > 65) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_PUBKEYHASH) - { - if (vch1.size() != sizeof(uint160)) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_SMALLINTEGER) - { // Single-byte small integer pushed onto vSolutions - if (opcode1 == OP_0 || - (opcode1 >= OP_1 && opcode1 <= OP_16)) - { - char n = (char)CScript::DecodeOP_N(opcode1); - vSolutionsRet.push_back(valtype(1, n)); - } - else - break; - } - else if (opcode2 == OP_SMALLDATA) - { - // small pushdata, <= MAX_OP_RETURN_RELAY bytes - if (vch1.size() > MAX_OP_RETURN_RELAY) - break; - } - else if (opcode1 != opcode2 || vch1 != vch2) - { - // Others must match exactly - break; - } - } - } - - vSolutionsRet.clear(); - typeRet = TX_NONSTANDARD; - return false; -} - - -bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) -{ - CKey key; - if (!keystore.GetKey(address, key)) - return false; - - vector<unsigned char> vchSig; - if (!key.Sign(hash, vchSig)) - return false; - vchSig.push_back((unsigned char)nHashType); - scriptSigRet << vchSig; - - return true; -} - -bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) -{ - int nSigned = 0; - int nRequired = multisigdata.front()[0]; - for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) - { - const valtype& pubkey = multisigdata[i]; - CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) - ++nSigned; - } - return nSigned==nRequired; -} - -// -// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. -// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), -// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. -// Returns false if scriptPubKey could not be completely satisfied. -// -bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, - CScript& scriptSigRet, txnouttype& whichTypeRet) -{ - scriptSigRet.clear(); - - vector<valtype> vSolutions; - if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) - return false; - - CKeyID keyID; - switch (whichTypeRet) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - return false; - case TX_PUBKEY: - keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); - case TX_PUBKEYHASH: - keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) - return false; - else - { - CPubKey vch; - keystore.GetPubKey(keyID, vch); - scriptSigRet << vch; - } - return true; - case TX_SCRIPTHASH: - return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet); - - case TX_MULTISIG: - scriptSigRet << OP_0; // workaround CHECKMULTISIG bug - return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet)); - } - return false; -} - -int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions) -{ - switch (t) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - return -1; - case TX_PUBKEY: - return 1; - case TX_PUBKEYHASH: - return 2; - case TX_MULTISIG: - if (vSolutions.size() < 1 || vSolutions[0].size() < 1) - return -1; - return vSolutions[0][0] + 1; - case TX_SCRIPTHASH: - return 1; // doesn't include args needed by the script - } - return -1; -} - -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) -{ - vector<valtype> vSolutions; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; - - if (whichType == TX_MULTISIG) - { - unsigned char m = vSolutions.front()[0]; - unsigned char n = vSolutions.back()[0]; - // Support up to x-of-3 multisig txns as standard - if (n < 1 || n > 3) - return false; - if (m < 1 || m > n) - return false; - } - - return whichType != TX_NONSTANDARD; -} - - -unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) -{ - unsigned int nResult = 0; - BOOST_FOREACH(const valtype& pubkey, pubkeys) - { - CKeyID keyID = CPubKey(pubkey).GetID(); - if (keystore.HaveKey(keyID)) - ++nResult; - } - return nResult; -} - -isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) -{ - CScript script; - script.SetDestination(dest); - return IsMine(keystore, script); -} - -isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) -{ - vector<valtype> vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) { - if (keystore.HaveWatchOnly(scriptPubKey)) - return ISMINE_WATCH_ONLY; - return ISMINE_NO; - } - - CKeyID keyID; - switch (whichType) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - break; - case TX_PUBKEY: - keyID = CPubKey(vSolutions[0]).GetID(); - if (keystore.HaveKey(keyID)) - return ISMINE_SPENDABLE; - break; - case TX_PUBKEYHASH: - keyID = CKeyID(uint160(vSolutions[0])); - if (keystore.HaveKey(keyID)) - return ISMINE_SPENDABLE; - break; - case TX_SCRIPTHASH: - { - CScriptID scriptID = CScriptID(uint160(vSolutions[0])); - CScript subscript; - if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMine(keystore, subscript); - if (ret == ISMINE_SPENDABLE) - return ret; - } - break; - } - case TX_MULTISIG: - { - // Only consider transactions "mine" if we own ALL the - // keys involved. multi-signature transactions that are - // partially owned (somebody else has a key that can spend - // them) enable spend-out-from-under-you attacks, especially - // in shared-wallet situations. - vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - if (HaveKeys(keys, keystore) == keys.size()) - return ISMINE_SPENDABLE; - break; - } - } - - if (keystore.HaveWatchOnly(scriptPubKey)) - return ISMINE_WATCH_ONLY; - return ISMINE_NO; -} - -bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) -{ - vector<valtype> vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; - - if (whichType == TX_PUBKEY) - { - addressRet = CPubKey(vSolutions[0]).GetID(); - return true; - } - else if (whichType == TX_PUBKEYHASH) - { - addressRet = CKeyID(uint160(vSolutions[0])); - return true; - } - else if (whichType == TX_SCRIPTHASH) - { - addressRet = CScriptID(uint160(vSolutions[0])); - return true; - } - // Multisig txns have more than one address... - return false; -} - -bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) -{ - addressRet.clear(); - typeRet = TX_NONSTANDARD; - vector<valtype> vSolutions; - if (!Solver(scriptPubKey, typeRet, vSolutions)) - return false; - if (typeRet == TX_NULL_DATA){ - // This is data, not addresses - return false; - } - - if (typeRet == TX_MULTISIG) - { - nRequiredRet = vSolutions.front()[0]; - for (unsigned int i = 1; i < vSolutions.size()-1; i++) - { - CTxDestination address = CPubKey(vSolutions[i]).GetID(); - addressRet.push_back(address); - } - } - else - { - nRequiredRet = 1; - CTxDestination address; - if (!ExtractDestination(scriptPubKey, address)) - return false; - addressRet.push_back(address); - } - - return true; -} - -class CAffectedKeysVisitor : public boost::static_visitor<void> { -private: - const CKeyStore &keystore; - std::vector<CKeyID> &vKeys; - -public: - CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} - - void Process(const CScript &script) { - txnouttype type; - std::vector<CTxDestination> vDest; - int nRequired; - if (ExtractDestinations(script, type, vDest, nRequired)) { - BOOST_FOREACH(const CTxDestination &dest, vDest) - boost::apply_visitor(*this, dest); - } - } - - void operator()(const CKeyID &keyId) { - if (keystore.HaveKey(keyId)) - vKeys.push_back(keyId); - } - - void operator()(const CScriptID &scriptId) { - CScript script; - if (keystore.GetCScript(scriptId, script)) - Process(script); - } - - void operator()(const CNoDestination &none) {} -}; - -void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) { - CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); -} - bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { vector<vector<unsigned char> > stack, stackCopy; if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType)) return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType)) return false; if (stack.empty()) return false; if (CastToBool(stack.back()) == false) return false; // Additional validation for spend-to-script-hash transactions: if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only return false; // or validation fails // stackCopy cannot be empty here, because if it was the // P2SH HASH <> EQUAL scriptPubKey would be evaluated with // an empty stack and the EvalScript above would return false. assert(!stackCopy.empty()); const valtype& pubKeySerialized = stackCopy.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType)) return false; if (stackCopy.empty()) return false; return CastToBool(stackCopy.back()); } 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<valtype>(subscript); - if (!fSolved) return false; - } - - // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); -} - -bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) -{ - assert(nIn < txTo.vin.size()); - CTxIn& txin = txTo.vin[nIn]; - assert(txin.prevout.n < txFrom.vout.size()); - const CTxOut& txout = txFrom.vout[txin.prevout.n]; - - return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); -} - -static CScript PushAll(const vector<valtype>& values) -{ - CScript result; - BOOST_FOREACH(const valtype& v, values) - result << v; - return result; -} - -static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn, - const vector<valtype>& vSolutions, - vector<valtype>& sigs1, vector<valtype>& sigs2) -{ - // Combine all the signatures we've got: - set<valtype> allsigs; - BOOST_FOREACH(const valtype& v, sigs1) - { - if (!v.empty()) - allsigs.insert(v); - } - BOOST_FOREACH(const valtype& v, sigs2) - { - if (!v.empty()) - allsigs.insert(v); - } - - // Build a map of pubkey -> signature by matching sigs to pubkeys: - assert(vSolutions.size() > 1); - unsigned int nSigsRequired = vSolutions.front()[0]; - unsigned int nPubKeys = vSolutions.size()-2; - map<valtype, valtype> sigs; - BOOST_FOREACH(const valtype& sig, allsigs) - { - for (unsigned int i = 0; i < nPubKeys; i++) - { - const valtype& pubkey = vSolutions[i+1]; - if (sigs.count(pubkey)) - continue; // Already got a sig for this pubkey - - if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0)) - { - sigs[pubkey] = sig; - break; - } - } - } - // Now build a merged CScript: - unsigned int nSigsHave = 0; - CScript result; result << OP_0; // pop-one-too-many workaround - for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) - { - if (sigs.count(vSolutions[i+1])) - { - result << sigs[vSolutions[i+1]]; - ++nSigsHave; - } - } - // Fill any missing with OP_0: - for (unsigned int i = nSigsHave; i < nSigsRequired; i++) - result << OP_0; - - return result; -} - -static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, - const txnouttype txType, const vector<valtype>& vSolutions, - vector<valtype>& sigs1, vector<valtype>& sigs2) -{ - switch (txType) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - // Don't know anything about this, assume bigger one is correct: - if (sigs1.size() >= sigs2.size()) - return PushAll(sigs1); - return PushAll(sigs2); - case TX_PUBKEY: - case TX_PUBKEYHASH: - // Signatures are bigger than placeholders or empty scripts: - if (sigs1.empty() || sigs1[0].empty()) - return PushAll(sigs2); - return PushAll(sigs1); - case TX_SCRIPTHASH: - if (sigs1.empty() || sigs1.back().empty()) - return PushAll(sigs2); - else if (sigs2.empty() || sigs2.back().empty()) - return PushAll(sigs1); - else - { - // Recur to combine: - valtype spk = sigs1.back(); - CScript pubKey2(spk.begin(), spk.end()); - - txnouttype txType2; - vector<vector<unsigned char> > vSolutions2; - Solver(pubKey2, txType2, vSolutions2); - sigs1.pop_back(); - sigs2.pop_back(); - CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); - result << spk; - return result; - } - case TX_MULTISIG: - return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); - } - - return CScript(); -} - -CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, - const CScript& scriptSig1, const CScript& scriptSig2) -{ - txnouttype txType; - vector<vector<unsigned char> > vSolutions; - Solver(scriptPubKey, txType, vSolutions); - - vector<valtype> stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); - vector<valtype> stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); - - return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); -} - -bool CScriptCompressor::IsToKeyID(CKeyID &hash) const -{ - if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 - && script[2] == 20 && script[23] == OP_EQUALVERIFY - && script[24] == OP_CHECKSIG) { - memcpy(&hash, &script[3], 20); - return true; - } - return false; -} - -bool CScriptCompressor::IsToScriptID(CScriptID &hash) const -{ - if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 - && script[22] == OP_EQUAL) { - memcpy(&hash, &script[2], 20); - return true; - } - return false; -} - -bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const -{ - if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG - && (script[1] == 0x02 || script[1] == 0x03)) { - pubkey.Set(&script[1], &script[34]); - return true; - } - if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG - && script[1] == 0x04) { - pubkey.Set(&script[1], &script[66]); - return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible - } - return false; -} - -bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const -{ - CKeyID keyID; - if (IsToKeyID(keyID)) { - out.resize(21); - out[0] = 0x00; - memcpy(&out[1], &keyID, 20); - return true; - } - CScriptID scriptID; - if (IsToScriptID(scriptID)) { - out.resize(21); - out[0] = 0x01; - memcpy(&out[1], &scriptID, 20); - return true; - } - CPubKey pubkey; - if (IsToPubKey(pubkey)) { - out.resize(33); - memcpy(&out[1], &pubkey[1], 32); - if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { - out[0] = pubkey[0]; - return true; - } else if (pubkey[0] == 0x04) { - out[0] = 0x04 | (pubkey[64] & 0x01); - return true; - } - } - return false; -} - -unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const -{ - if (nSize == 0 || nSize == 1) - return 20; - if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) - return 32; - return 0; -} - -bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in) -{ - switch(nSize) { - case 0x00: - script.resize(25); - script[0] = OP_DUP; - script[1] = OP_HASH160; - script[2] = 20; - memcpy(&script[3], &in[0], 20); - script[23] = OP_EQUALVERIFY; - script[24] = OP_CHECKSIG; - return true; - case 0x01: - script.resize(23); - script[0] = OP_HASH160; - script[1] = 20; - memcpy(&script[2], &in[0], 20); - script[22] = OP_EQUAL; - return true; - case 0x02: - case 0x03: - script.resize(35); - script[0] = 33; - script[1] = nSize; - memcpy(&script[2], &in[0], 32); - script[34] = OP_CHECKSIG; - return true; - case 0x04: - case 0x05: - unsigned char vch[33] = {}; - vch[0] = nSize - 2; - memcpy(&vch[1], &in[0], 32); - CPubKey pubkey(&vch[0], &vch[33]); - if (!pubkey.Decompress()) - return false; - assert(pubkey.size() == 65); - script.resize(67); - script[0] = 65; - memcpy(&script[1], pubkey.begin(), 65); - script[66] = OP_CHECKSIG; - return true; - } - return false; -} 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 <vector> +#include <stdint.h> +#include <string> + +class uint256; +class CScript; +class CTransaction; + +/** Signature hash types/flags */ +enum +{ + SIGHASH_ALL = 1, + SIGHASH_NONE = 2, + SIGHASH_SINGLE = 3, + SIGHASH_ANYONECANPAY = 0x80, +}; + +/** Script verification flags */ +enum +{ + SCRIPT_VERIFY_NONE = 0, + SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts + SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys + SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC) + SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) + SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length +}; + +bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags); +bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags); + +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); + +#endif diff --git a/src/scriptutils.cpp b/src/scriptutils.cpp index 56edc2c2d..fb3766ab1 100644 --- a/src/scriptutils.cpp +++ b/src/scriptutils.cpp @@ -1,1791 +1,733 @@ // 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 "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 "uint256.h" #include "util.h" #include <boost/foreach.hpp> -#include <boost/thread.hpp> -#include <boost/tuple/tuple.hpp> -#include <boost/tuple/tuple_comparison.hpp> using namespace std; -using namespace boost; typedef vector<unsigned char> valtype; -static const valtype vchFalse(0); -static const valtype vchZero(0); -static const valtype vchTrue(1, 1); -static const CScriptNum bnZero(0); -static const CScriptNum bnOne(1); -static const CScriptNum bnFalse(0); -static const CScriptNum bnTrue(1); - -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &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++) - { - if (vch[i] != 0) - { - // Can be negative zero - if (i == vch.size()-1 && vch[i] == 0x80) - return false; - return true; - } - } - return false; -} - - - -// -// Script is a stack machine (like Forth) that evaluates a predicate -// returning a bool indicating valid or not. There are no loops. -// -#define stacktop(i) (stack.at(stack.size()+(i))) -#define altstacktop(i) (altstack.at(altstack.size()+(i))) -static inline void popstack(vector<valtype>& stack) -{ - if (stack.empty()) - throw runtime_error("popstack() : stack empty"); - 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; } -bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - - if (vchPubKey.size() < 33) - return error("Non-canonical public key: too short"); - if (vchPubKey[0] == 0x04) { - if (vchPubKey.size() != 65) - return error("Non-canonical public key: invalid length for uncompressed key"); - } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { - if (vchPubKey.size() != 33) - return error("Non-canonical public key: invalid length for compressed key"); - } else { - return error("Non-canonical public key: neither compressed nor uncompressed"); - } - return true; -} - -bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - - // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - // A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> - // Where R and S are not negative (their first byte has its highest bit not set), and not - // excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, - // in which case a single 0 byte is necessary and even required). - if (vchSig.size() < 9) - return error("Non-canonical signature: too short"); - if (vchSig.size() > 73) - return error("Non-canonical signature: too long"); - unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); - if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return error("Non-canonical signature: unknown hashtype byte"); - if (vchSig[0] != 0x30) - return error("Non-canonical signature: wrong type"); - if (vchSig[1] != vchSig.size()-3) - return error("Non-canonical signature: wrong length marker"); - unsigned int nLenR = vchSig[3]; - if (5 + nLenR >= vchSig.size()) - return error("Non-canonical signature: S length misplaced"); - unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) - return error("Non-canonical signature: R+S length mismatch"); - - const unsigned char *R = &vchSig[4]; - if (R[-2] != 0x02) - return error("Non-canonical signature: R value type mismatch"); - if (nLenR == 0) - return error("Non-canonical signature: R length is zero"); - if (R[0] & 0x80) - return error("Non-canonical signature: R value negative"); - if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) - return error("Non-canonical signature: R value excessively padded"); - - const unsigned char *S = &vchSig[6+nLenR]; - if (S[-2] != 0x02) - return error("Non-canonical signature: S value type mismatch"); - if (nLenS == 0) - return error("Non-canonical signature: S length is zero"); - if (S[0] & 0x80) - return error("Non-canonical signature: S value negative"); - if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) - return error("Non-canonical signature: S value excessively padded"); - - if (flags & SCRIPT_VERIFY_LOW_S) { - // If the S value is above the order of the curve divided by two, its - // complement modulo the order could have been used instead, which is - // one byte shorter when encoded correctly. - if (!CKey::CheckSignatureElement(S, nLenS, true)) - return error("Non-canonical signature: S value is unnecessarily high"); - } - - return true; -} - -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) -{ - CScript::const_iterator pc = script.begin(); - CScript::const_iterator pend = script.end(); - CScript::const_iterator pbegincodehash = script.begin(); - opcodetype opcode; - valtype vchPushValue; - vector<bool> vfExec; - vector<valtype> altstack; - if (script.size() > 10000) - return false; - int nOpCount = 0; - - try - { - while (pc < pend) - { - bool fExec = !count(vfExec.begin(), vfExec.end(), false); - - // - // Read instruction - // - if (!script.GetOp(pc, opcode, vchPushValue)) - return false; - if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) - return false; - - // Note how OP_RESERVED does not count towards the opcode limit. - if (opcode > OP_16 && ++nOpCount > 201) - return false; - - if (opcode == OP_CAT || - opcode == OP_SUBSTR || - opcode == OP_LEFT || - opcode == OP_RIGHT || - opcode == OP_INVERT || - opcode == OP_AND || - opcode == OP_OR || - opcode == OP_XOR || - opcode == OP_2MUL || - opcode == OP_2DIV || - opcode == OP_MUL || - opcode == OP_DIV || - opcode == OP_MOD || - opcode == OP_LSHIFT || - opcode == OP_RSHIFT) - return false; // Disabled opcodes. - - if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) - stack.push_back(vchPushValue); - else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) - switch (opcode) - { - // - // Push value - // - case OP_1NEGATE: - case OP_1: - case OP_2: - case OP_3: - case OP_4: - case OP_5: - case OP_6: - case OP_7: - case OP_8: - case OP_9: - case OP_10: - case OP_11: - case OP_12: - case OP_13: - case OP_14: - case OP_15: - case OP_16: - { - // ( -- value) - CScriptNum bn((int)opcode - (int)(OP_1 - 1)); - stack.push_back(bn.getvch()); - } - break; - - - // - // Control - // - case OP_NOP: - case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: - case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: - break; - - case OP_IF: - case OP_NOTIF: - { - // <expression> if [statements] [else [statements]] endif - bool fValue = false; - if (fExec) - { - if (stack.size() < 1) - return false; - valtype& vch = stacktop(-1); - fValue = CastToBool(vch); - if (opcode == OP_NOTIF) - fValue = !fValue; - popstack(stack); - } - vfExec.push_back(fValue); - } - break; - - case OP_ELSE: - { - if (vfExec.empty()) - return false; - vfExec.back() = !vfExec.back(); - } - break; - - case OP_ENDIF: - { - if (vfExec.empty()) - return false; - vfExec.pop_back(); - } - break; - - case OP_VERIFY: - { - // (true -- ) or - // (false -- false) and return - if (stack.size() < 1) - return false; - bool fValue = CastToBool(stacktop(-1)); - if (fValue) - popstack(stack); - else - return false; - } - break; - - case OP_RETURN: - { - return false; - } - break; - - - // - // Stack ops - // - case OP_TOALTSTACK: - { - if (stack.size() < 1) - return false; - altstack.push_back(stacktop(-1)); - popstack(stack); - } - break; - - case OP_FROMALTSTACK: - { - if (altstack.size() < 1) - return false; - stack.push_back(altstacktop(-1)); - popstack(altstack); - } - break; - - case OP_2DROP: - { - // (x1 x2 -- ) - if (stack.size() < 2) - return false; - popstack(stack); - popstack(stack); - } - break; - - case OP_2DUP: - { - // (x1 x2 -- x1 x2 x1 x2) - if (stack.size() < 2) - return false; - valtype vch1 = stacktop(-2); - valtype vch2 = stacktop(-1); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_3DUP: - { - // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) - if (stack.size() < 3) - return false; - valtype vch1 = stacktop(-3); - valtype vch2 = stacktop(-2); - valtype vch3 = stacktop(-1); - stack.push_back(vch1); - stack.push_back(vch2); - stack.push_back(vch3); - } - break; - - case OP_2OVER: - { - // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) - if (stack.size() < 4) - return false; - valtype vch1 = stacktop(-4); - valtype vch2 = stacktop(-3); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_2ROT: - { - // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) - if (stack.size() < 6) - return false; - valtype vch1 = stacktop(-6); - valtype vch2 = stacktop(-5); - stack.erase(stack.end()-6, stack.end()-4); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_2SWAP: - { - // (x1 x2 x3 x4 -- x3 x4 x1 x2) - if (stack.size() < 4) - return false; - swap(stacktop(-4), stacktop(-2)); - swap(stacktop(-3), stacktop(-1)); - } - break; - - case OP_IFDUP: - { - // (x - 0 | x x) - if (stack.size() < 1) - return false; - valtype vch = stacktop(-1); - if (CastToBool(vch)) - stack.push_back(vch); - } - break; - - case OP_DEPTH: - { - // -- stacksize - CScriptNum bn(stack.size()); - stack.push_back(bn.getvch()); - } - break; - - case OP_DROP: - { - // (x -- ) - if (stack.size() < 1) - return false; - popstack(stack); - } - break; - - case OP_DUP: - { - // (x -- x x) - if (stack.size() < 1) - return false; - valtype vch = stacktop(-1); - stack.push_back(vch); - } - break; - - case OP_NIP: - { - // (x1 x2 -- x2) - if (stack.size() < 2) - return false; - stack.erase(stack.end() - 2); - } - break; - - case OP_OVER: - { - // (x1 x2 -- x1 x2 x1) - if (stack.size() < 2) - return false; - valtype vch = stacktop(-2); - stack.push_back(vch); - } - break; - - case OP_PICK: - case OP_ROLL: - { - // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) - // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) - if (stack.size() < 2) - return false; - int n = CScriptNum(stacktop(-1)).getint(); - popstack(stack); - if (n < 0 || n >= (int)stack.size()) - return false; - valtype vch = stacktop(-n-1); - if (opcode == OP_ROLL) - stack.erase(stack.end()-n-1); - stack.push_back(vch); - } - break; - - case OP_ROT: - { - // (x1 x2 x3 -- x2 x3 x1) - // x2 x1 x3 after first swap - // x2 x3 x1 after second swap - if (stack.size() < 3) - return false; - swap(stacktop(-3), stacktop(-2)); - swap(stacktop(-2), stacktop(-1)); - } - break; - - case OP_SWAP: - { - // (x1 x2 -- x2 x1) - if (stack.size() < 2) - return false; - swap(stacktop(-2), stacktop(-1)); - } - break; - - case OP_TUCK: - { - // (x1 x2 -- x2 x1 x2) - if (stack.size() < 2) - return false; - valtype vch = stacktop(-1); - stack.insert(stack.end()-2, vch); - } - break; - - - case OP_SIZE: - { - // (in -- in size) - if (stack.size() < 1) - return false; - CScriptNum bn(stacktop(-1).size()); - stack.push_back(bn.getvch()); - } - break; - - - // - // Bitwise logic - // - case OP_EQUAL: - case OP_EQUALVERIFY: - //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL - { - // (x1 x2 - bool) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - bool fEqual = (vch1 == vch2); - // OP_NOTEQUAL is disabled because it would be too easy to say - // something like n != 1 and have some wiseguy pass in 1 with extra - // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) - //if (opcode == OP_NOTEQUAL) - // fEqual = !fEqual; - popstack(stack); - popstack(stack); - stack.push_back(fEqual ? vchTrue : vchFalse); - if (opcode == OP_EQUALVERIFY) - { - if (fEqual) - popstack(stack); - else - return false; - } - } - break; - - - // - // Numeric - // - case OP_1ADD: - case OP_1SUB: - case OP_NEGATE: - case OP_ABS: - case OP_NOT: - case OP_0NOTEQUAL: - { - // (in -- out) - if (stack.size() < 1) - return false; - CScriptNum bn(stacktop(-1)); - switch (opcode) - { - case OP_1ADD: bn += bnOne; break; - case OP_1SUB: bn -= bnOne; break; - case OP_NEGATE: bn = -bn; break; - case OP_ABS: if (bn < bnZero) bn = -bn; break; - case OP_NOT: bn = (bn == bnZero); break; - case OP_0NOTEQUAL: bn = (bn != bnZero); break; - default: assert(!"invalid opcode"); break; - } - popstack(stack); - stack.push_back(bn.getvch()); - } - break; - - case OP_ADD: - case OP_SUB: - case OP_BOOLAND: - case OP_BOOLOR: - case OP_NUMEQUAL: - case OP_NUMEQUALVERIFY: - case OP_NUMNOTEQUAL: - case OP_LESSTHAN: - case OP_GREATERTHAN: - case OP_LESSTHANOREQUAL: - case OP_GREATERTHANOREQUAL: - case OP_MIN: - case OP_MAX: - { - // (x1 x2 -- out) - if (stack.size() < 2) - return false; - CScriptNum bn1(stacktop(-2)); - CScriptNum bn2(stacktop(-1)); - CScriptNum bn(0); - switch (opcode) - { - case OP_ADD: - bn = bn1 + bn2; - break; - - case OP_SUB: - bn = bn1 - bn2; - break; - - case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; - case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; - case OP_NUMEQUAL: bn = (bn1 == bn2); break; - case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; - case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; - case OP_LESSTHAN: bn = (bn1 < bn2); break; - case OP_GREATERTHAN: bn = (bn1 > bn2); break; - case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; - case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; - case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; - case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; - default: assert(!"invalid opcode"); break; - } - popstack(stack); - popstack(stack); - stack.push_back(bn.getvch()); - - if (opcode == OP_NUMEQUALVERIFY) - { - if (CastToBool(stacktop(-1))) - popstack(stack); - else - return false; - } - } - break; - - case OP_WITHIN: - { - // (x min max -- out) - if (stack.size() < 3) - return false; - CScriptNum bn1(stacktop(-3)); - CScriptNum bn2(stacktop(-2)); - CScriptNum bn3(stacktop(-1)); - bool fValue = (bn2 <= bn1 && bn1 < bn3); - popstack(stack); - popstack(stack); - popstack(stack); - stack.push_back(fValue ? vchTrue : vchFalse); - } - break; - - - // - // Crypto - // - case OP_RIPEMD160: - case OP_SHA1: - case OP_SHA256: - case OP_HASH160: - case OP_HASH256: - { - // (in -- hash) - if (stack.size() < 1) - return false; - valtype& vch = stacktop(-1); - valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); - if (opcode == OP_RIPEMD160) - CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); - else if (opcode == OP_SHA1) - CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); - else if (opcode == OP_SHA256) - CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); - else if (opcode == OP_HASH160) - CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); - else if (opcode == OP_HASH256) - CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); - popstack(stack); - stack.push_back(vchHash); - } - break; - - case OP_CODESEPARATOR: - { - // Hash starts after the code separator - pbegincodehash = pc; - } - break; - - case OP_CHECKSIG: - case OP_CHECKSIGVERIFY: - { - // (sig pubkey -- bool) - if (stack.size() < 2) - return false; - - valtype& vchSig = stacktop(-2); - valtype& vchPubKey = stacktop(-1); - - // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); - - // Drop the signature, since there's no way for a signature to sign itself - scriptCode.FindAndDelete(CScript(vchSig)); - - bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); - - popstack(stack); - popstack(stack); - stack.push_back(fSuccess ? vchTrue : vchFalse); - if (opcode == OP_CHECKSIGVERIFY) - { - if (fSuccess) - popstack(stack); - else - return false; - } - } - break; - - case OP_CHECKMULTISIG: - case OP_CHECKMULTISIGVERIFY: - { - // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) - - int i = 1; - if ((int)stack.size() < i) - return false; - - int nKeysCount = CScriptNum(stacktop(-i)).getint(); - if (nKeysCount < 0 || nKeysCount > 20) - return false; - nOpCount += nKeysCount; - if (nOpCount > 201) - return false; - int ikey = ++i; - i += nKeysCount; - if ((int)stack.size() < i) - return false; - - int nSigsCount = CScriptNum(stacktop(-i)).getint(); - if (nSigsCount < 0 || nSigsCount > nKeysCount) - return false; - int isig = ++i; - i += nSigsCount; - if ((int)stack.size() < i) - return false; - - // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); - - // Drop the signatures, since there's no way for a signature to sign itself - for (int k = 0; k < nSigsCount; k++) - { - valtype& vchSig = stacktop(-isig-k); - scriptCode.FindAndDelete(CScript(vchSig)); - } - - bool fSuccess = true; - while (fSuccess && nSigsCount > 0) - { - valtype& vchSig = stacktop(-isig); - valtype& vchPubKey = stacktop(-ikey); - - // Check signature - bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); - - if (fOk) { - isig++; - nSigsCount--; - } - ikey++; - nKeysCount--; - - // If there are more signatures left than keys left, - // then too many signatures have failed - if (nSigsCount > nKeysCount) - fSuccess = false; - } - - // Clean up stack of actual arguments - while (i-- > 1) - popstack(stack); - - // A bug causes CHECKMULTISIG to consume one extra argument - // whose contents were not checked in any way. - // - // Unfortunately this is a potential source of mutability, - // so optionally verify it is exactly equal to zero prior - // to removing it from the stack. - if (stack.size() < 1) - return false; - if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) - return error("CHECKMULTISIG dummy argument not null"); - popstack(stack); - - stack.push_back(fSuccess ? vchTrue : vchFalse); - - if (opcode == OP_CHECKMULTISIGVERIFY) - { - if (fSuccess) - popstack(stack); - else - return false; - } - } - break; - - default: - return false; - } - - // Size limits - if (stack.size() + altstack.size() > 1000) - return false; - } - } - catch (...) - { - return false; - } - - - if (!vfExec.empty()) - return false; - - return true; -} - - - - - - - -namespace { - -/** Wrapper that serializes like CTransaction, but with the modifications - * required for the signature hash done in-place - */ -class CTransactionSignatureSerializer { -private: - const CTransaction &txTo; // reference to the spending transaction (the one being serialized) - const CScript &scriptCode; // output script being consumed - const unsigned int nIn; // input index of txTo being signed - const bool fAnyoneCanPay; // whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; // whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; // whether the hashtype is SIGHASH_NONE - -public: - CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : - txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), - fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), - fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), - fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {} - - /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ - template<typename S> - void SerializeScriptCode(S &s, int nType, int nVersion) const { - CScript::const_iterator it = scriptCode.begin(); - CScript::const_iterator itBegin = it; - opcodetype opcode; - unsigned int nCodeSeparators = 0; - while (scriptCode.GetOp(it, opcode)) { - if (opcode == OP_CODESEPARATOR) - nCodeSeparators++; - } - ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); - it = itBegin; - while (scriptCode.GetOp(it, opcode)) { - if (opcode == OP_CODESEPARATOR) { - s.write((char*)&itBegin[0], it-itBegin-1); - itBegin = it; - } - } - s.write((char*)&itBegin[0], it-itBegin); - } - - /** Serialize an input of txTo */ - template<typename S> - void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { - // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized - if (fAnyoneCanPay) - nInput = nIn; - // Serialize the prevout - ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); - // Serialize the script - if (nInput != nIn) - // Blank out other inputs' signatures - ::Serialize(s, CScript(), nType, nVersion); - else - SerializeScriptCode(s, nType, nVersion); - // Serialize the nSequence - if (nInput != nIn && (fHashSingle || fHashNone)) - // let the others update at will - ::Serialize(s, (int)0, nType, nVersion); - else - ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); - } - - /** Serialize an output of txTo */ - template<typename S> - void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { - if (fHashSingle && nOutput != nIn) - // Do not lock-in the txout payee at other indices as txin - ::Serialize(s, CTxOut(), nType, nVersion); - else - ::Serialize(s, txTo.vout[nOutput], nType, nVersion); - } - - /** Serialize txTo */ - template<typename S> - void Serialize(S &s, int nType, int nVersion) const { - // Serialize nVersion - ::Serialize(s, txTo.nVersion, nType, nVersion); - // Serialize vin - unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); - ::WriteCompactSize(s, nInputs); - for (unsigned int nInput = 0; nInput < nInputs; nInput++) - SerializeInput(s, nInput, nType, nVersion); - // Serialize vout - unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); - ::WriteCompactSize(s, nOutputs); - for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) - SerializeOutput(s, nOutput, nType, nVersion); - // Serialie nLockTime - ::Serialize(s, txTo.nLockTime, nType, nVersion); - } -}; - -} // anon namespace - -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) -{ - if (nIn >= txTo.vin.size()) { - LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); - return 1; - } - - // Check for invalid use of SIGHASH_SINGLE - if ((nHashType & 0x1f) == SIGHASH_SINGLE) { - if (nIn >= txTo.vout.size()) { - LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn); - return 1; - } - } - - // Wrapper to serialize only the necessary parts of the transaction being signed - CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); - - // Serialize and hash - CHashWriter ss(SER_GETHASH, 0); - ss << txTmp << nHashType; - return ss.GetHash(); -} - -// Valid signature cache, to avoid doing expensive ECDSA signature checking -// twice for every transaction (once when accepted into memory pool, and -// again when accepted into the block chain) -class CSignatureCache -{ -private: - // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; - -public: - bool - Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); - - sigdata_type k(hash, vchSig, pubKey); - std::set<sigdata_type>::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; - } - - void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); - if (nMaxCacheSize <= 0) return; - - boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); - - while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) - { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector<unsigned char> unused; - std::set<sigdata_type>::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); - } - - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); - } -}; - -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, - const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) -{ - static CSignatureCache signatureCache; - - CPubKey pubkey(vchPubKey); - if (!pubkey.IsValid()) - return false; - - // Hash type is one byte tacked on to the end of the signature - if (vchSig.empty()) - return false; - if (nHashType == 0) - nHashType = vchSig.back(); - else if (nHashType != vchSig.back()) - return false; - vchSig.pop_back(); - - uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - - if (signatureCache.Get(sighash, vchSig, pubkey)) - return true; - - if (!pubkey.Verify(sighash, vchSig)) - return false; - - if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, pubkey); - - return true; -} - - - - - - - - - // // Return public keys or hashes from scriptPubKey, for 'standard' transaction types. // bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) { // Templates static multimap<txnouttype, CScript> mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); // Empty, provably prunable, data-carrying output if (GetBoolArg("-datacarrier", true)) mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA)); mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN)); } // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { typeRet = TX_SCRIPTHASH; vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } // Scan templates const CScript& script1 = scriptPubKey; BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) { const CScript& script2 = tplate.second; vSolutionsRet.clear(); opcodetype opcode1, opcode2; vector<unsigned char> vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); while (true) { if (pc1 == script1.end() && pc2 == script2.end()) { // Found a match typeRet = tplate.first; if (typeRet == TX_MULTISIG) { // Additional checks for TX_MULTISIG: unsigned char m = vSolutionsRet.front()[0]; unsigned char n = vSolutionsRet.back()[0]; if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) return false; } return true; } if (!script1.GetOp(pc1, opcode1, vch1)) break; if (!script2.GetOp(pc2, opcode2, vch2)) break; // Template matching opcodes: if (opcode2 == OP_PUBKEYS) { while (vch1.size() >= 33 && vch1.size() <= 65) { vSolutionsRet.push_back(vch1); if (!script1.GetOp(pc1, opcode1, vch1)) break; } if (!script2.GetOp(pc2, opcode2, vch2)) break; // Normal situation is to fall through // to other if/else statements } if (opcode2 == OP_PUBKEY) { if (vch1.size() < 33 || vch1.size() > 65) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_PUBKEYHASH) { if (vch1.size() != sizeof(uint160)) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_SMALLINTEGER) { // Single-byte small integer pushed onto vSolutions if (opcode1 == OP_0 || (opcode1 >= OP_1 && opcode1 <= OP_16)) { char n = (char)CScript::DecodeOP_N(opcode1); vSolutionsRet.push_back(valtype(1, n)); } else break; } else if (opcode2 == OP_SMALLDATA) { // small pushdata, <= MAX_OP_RETURN_RELAY bytes if (vch1.size() > MAX_OP_RETURN_RELAY) break; } else if (opcode1 != opcode2 || vch1 != vch2) { // Others must match exactly break; } } } vSolutionsRet.clear(); typeRet = TX_NONSTANDARD; return false; } bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { CKey key; if (!keystore.GetKey(address, key)) return false; vector<unsigned char> vchSig; if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); scriptSigRet << vchSig; return true; } bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; int nRequired = multisigdata.front()[0]; for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) ++nSigned; } return nSigned==nRequired; } // // Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. // Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), // unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. // Returns false if scriptPubKey could not be completely satisfied. // bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) { scriptSigRet.clear(); vector<valtype> vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) return false; else { CPubKey vch; keystore.GetPubKey(keyID, vch); scriptSigRet << vch; } return true; case TX_SCRIPTHASH: return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet); case TX_MULTISIG: scriptSigRet << OP_0; // workaround CHECKMULTISIG bug return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet)); } return false; } int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions) { switch (t) { case TX_NONSTANDARD: case TX_NULL_DATA: return -1; case TX_PUBKEY: return 1; case TX_PUBKEYHASH: return 2; case TX_MULTISIG: if (vSolutions.size() < 1 || vSolutions[0].size() < 1) return -1; return vSolutions[0][0] + 1; case TX_SCRIPTHASH: return 1; // doesn't include args needed by the script } return -1; } bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) { vector<valtype> vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_MULTISIG) { unsigned char m = vSolutions.front()[0]; unsigned char n = vSolutions.back()[0]; // Support up to x-of-3 multisig txns as standard if (n < 1 || n > 3) return false; if (m < 1 || m > n) return false; } return whichType != TX_NONSTANDARD; } unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) { unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); if (keystore.HaveKey(keyID)) ++nResult; } return nResult; } isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) { CScript script; script.SetDestination(dest); return IsMine(keystore, script); } isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { if (keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; return ISMINE_NO; } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: { CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript); if (ret == ISMINE_SPENDABLE) return ret; } break; } case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the // keys involved. multi-signature transactions that are // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); if (HaveKeys(keys, keystore) == keys.size()) return ISMINE_SPENDABLE; break; } } if (keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; return ISMINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_PUBKEY) { addressRet = CPubKey(vSolutions[0]).GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { addressRet = CScriptID(uint160(vSolutions[0])); return true; } // Multisig txns have more than one address... return false; } bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; vector<valtype> vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA){ // This is data, not addresses return false; } if (typeRet == TX_MULTISIG) { nRequiredRet = vSolutions.front()[0]; for (unsigned int i = 1; i < vSolutions.size()-1; i++) { CTxDestination address = CPubKey(vSolutions[i]).GetID(); addressRet.push_back(address); } } else { nRequiredRet = 1; CTxDestination address; if (!ExtractDestination(scriptPubKey, address)) return false; addressRet.push_back(address); } return true; } class CAffectedKeysVisitor : public boost::static_visitor<void> { private: const CKeyStore &keystore; std::vector<CKeyID> &vKeys; public: CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} void Process(const CScript &script) { txnouttype type; std::vector<CTxDestination> vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { BOOST_FOREACH(const CTxDestination &dest, vDest) boost::apply_visitor(*this, dest); } } void operator()(const CKeyID &keyId) { if (keystore.HaveKey(keyId)) vKeys.push_back(keyId); } void operator()(const CScriptID &scriptId) { CScript script; if (keystore.GetCScript(scriptId, script)) Process(script); } void operator()(const CNoDestination &none) {} }; void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) { CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - unsigned int flags, int nHashType) -{ - vector<vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType)) - return false; - if (flags & SCRIPT_VERIFY_P2SH) - stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType)) - return false; - if (stack.empty()) - return false; - - if (CastToBool(stack.back()) == false) - return false; - - // Additional validation for spend-to-script-hash transactions: - if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) - { - if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only - return false; // or validation fails - - // stackCopy cannot be empty here, because if it was the - // P2SH HASH <> EQUAL scriptPubKey would be evaluated with - // an empty stack and the EvalScript above would return false. - assert(!stackCopy.empty()); - - const valtype& pubKeySerialized = stackCopy.back(); - CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); - popstack(stackCopy); - - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType)) - return false; - if (stackCopy.empty()) - return false; - return CastToBool(stackCopy.back()); - } - - 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<valtype>(subscript); if (!fSolved) return false; } // Test solution return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); } static CScript PushAll(const vector<valtype>& values) { CScript result; BOOST_FOREACH(const valtype& v, values) result << v; return result; } static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn, const vector<valtype>& vSolutions, vector<valtype>& sigs1, vector<valtype>& sigs2) { // Combine all the signatures we've got: set<valtype> allsigs; BOOST_FOREACH(const valtype& v, sigs1) { if (!v.empty()) allsigs.insert(v); } BOOST_FOREACH(const valtype& v, sigs2) { if (!v.empty()) allsigs.insert(v); } // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; map<valtype, valtype> sigs; BOOST_FOREACH(const valtype& sig, allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { const valtype& pubkey = vSolutions[i+1]; if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; CScript result; result << OP_0; // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { result << sigs[vSolutions[i+1]]; ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) result << OP_0; return result; } static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const txnouttype txType, const vector<valtype>& vSolutions, vector<valtype>& sigs1, vector<valtype>& sigs2) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.size() >= sigs2.size()) return PushAll(sigs1); return PushAll(sigs2); case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.empty() || sigs1[0].empty()) return PushAll(sigs2); return PushAll(sigs1); case TX_SCRIPTHASH: if (sigs1.empty() || sigs1.back().empty()) return PushAll(sigs2); else if (sigs2.empty() || sigs2.back().empty()) return PushAll(sigs1); else { // Recur to combine: valtype spk = sigs1.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; vector<vector<unsigned char> > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.pop_back(); sigs2.pop_back(); CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); result << spk; return result; } case TX_MULTISIG: return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); } return CScript(); } CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2) { txnouttype txType; vector<vector<unsigned char> > vSolutions; Solver(scriptPubKey, txType, vSolutions); vector<valtype> stack1; EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); vector<valtype> stack2; EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } bool CScriptCompressor::IsToKeyID(CKeyID &hash) const { if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) { memcpy(&hash, &script[3], 20); return true; } return false; } bool CScriptCompressor::IsToScriptID(CScriptID &hash) const { if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 && script[22] == OP_EQUAL) { memcpy(&hash, &script[2], 20); return true; } return false; } bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const { if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03)) { pubkey.Set(&script[1], &script[34]); return true; } if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) { pubkey.Set(&script[1], &script[66]); return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible } return false; } bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const { CKeyID keyID; if (IsToKeyID(keyID)) { out.resize(21); out[0] = 0x00; memcpy(&out[1], &keyID, 20); return true; } CScriptID scriptID; if (IsToScriptID(scriptID)) { out.resize(21); out[0] = 0x01; memcpy(&out[1], &scriptID, 20); return true; } CPubKey pubkey; if (IsToPubKey(pubkey)) { out.resize(33); memcpy(&out[1], &pubkey[1], 32); if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { out[0] = pubkey[0]; return true; } else if (pubkey[0] == 0x04) { out[0] = 0x04 | (pubkey[64] & 0x01); return true; } } return false; } unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const { if (nSize == 0 || nSize == 1) return 20; if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) return 32; return 0; } bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in) { switch(nSize) { case 0x00: script.resize(25); script[0] = OP_DUP; script[1] = OP_HASH160; script[2] = 20; memcpy(&script[3], &in[0], 20); script[23] = OP_EQUALVERIFY; script[24] = OP_CHECKSIG; return true; case 0x01: script.resize(23); script[0] = OP_HASH160; script[1] = 20; memcpy(&script[2], &in[0], 20); script[22] = OP_EQUAL; return true; case 0x02: case 0x03: script.resize(35); script[0] = 33; script[1] = nSize; memcpy(&script[2], &in[0], 32); script[34] = OP_CHECKSIG; return true; case 0x04: case 0x05: unsigned char vch[33] = {}; vch[0] = nSize - 2; memcpy(&vch[1], &in[0], 32); CPubKey pubkey(&vch[0], &vch[33]); if (!pubkey.Decompress()) return false; assert(pubkey.size() == 65); script.resize(67); script[0] = 65; memcpy(&script[1], pubkey.begin(), 65); script[66] = OP_CHECKSIG; return true; } return false; } diff --git a/src/scriptutils.h b/src/scriptutils.h index 4f29f7ab2..1df95b1fa 100644 --- a/src/scriptutils.h +++ b/src/scriptutils.h @@ -1,180 +1,155 @@ // 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" +#include "script/interpreter.h" #include <stdexcept> #include <stdint.h> #include <string> #include <vector> class CKeyStore; class CTransaction; struct CMutableTransaction; static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes -/** Signature hash types/flags */ -enum -{ - SIGHASH_ALL = 1, - SIGHASH_NONE = 2, - SIGHASH_SINGLE = 3, - SIGHASH_ANYONECANPAY = 0x80, -}; - -/** Script verification flags */ -enum -{ - SCRIPT_VERIFY_NONE = 0, - SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts - SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys - SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC) - SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) - SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length -}; - /** IsMine() return codes */ enum isminetype { ISMINE_NO = 0, ISMINE_WATCH_ONLY = 1, ISMINE_SPENDABLE = 2, ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE }; /** used for bitflags of isminetype */ typedef uint8_t isminefilter; // Mandatory script verification flags that all new blocks must comply with for // them to be valid. (but old blocks may not comply with) Currently just P2SH, // but in the future other flags may be added, such as a soft-fork to enforce // strict DER encoding. // // Failing one of these tests may trigger a DoS ban - see CheckInputs() for // details. static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; // Standard script verification flags that standard transactions will comply // with. However scripts violating these flags may still be present in valid // blocks and we must accept those blocks. static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_NULLDUMMY; // For convenience, standard but not mandatory verify flags. static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; enum txnouttype { TX_NONSTANDARD, // 'standard' transaction types: TX_PUBKEY, TX_PUBKEYHASH, TX_SCRIPTHASH, TX_MULTISIG, TX_NULL_DATA, }; const char* GetTxnOutputType(txnouttype t); /** Compact serializer for scripts. * * It detects common cases and encodes them much more efficiently. * 3 special cases are defined: * * Pay to pubkey hash (encoded as 21 bytes) * * Pay to script hash (encoded as 21 bytes) * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) * * Other scripts up to 121 bytes require 1 byte + script length. Above * that, scripts up to 16505 bytes require 2 bytes + script length. */ class CScriptCompressor { private: // make this static for now (there are only 6 special scripts defined) // this can potentially be extended together with a new nVersion for // transactions, in which case this value becomes dependent on nVersion // and nHeight of the enclosing transaction. static const unsigned int nSpecialScripts = 6; CScript &script; protected: // These check for scripts for which a special case with a shorter encoding is defined. // They are implemented separately from the CScript test, as these test for exact byte // sequence correspondences, and are more strict. For example, IsToPubKey also verifies // whether the public key is valid (as invalid ones cannot be represented in compressed // form). bool IsToKeyID(CKeyID &hash) const; bool IsToScriptID(CScriptID &hash) const; bool IsToPubKey(CPubKey &pubkey) const; bool Compress(std::vector<unsigned char> &out) const; unsigned int GetSpecialSize(unsigned int nSize) const; bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out); public: CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } unsigned int GetSerializeSize(int nType, int nVersion) const { std::vector<unsigned char> compr; if (Compress(compr)) return compr.size(); unsigned int nSize = script.size() + nSpecialScripts; return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); } template<typename Stream> void Serialize(Stream &s, int nType, int nVersion) const { std::vector<unsigned char> compr; if (Compress(compr)) { s << CFlatData(compr); return; } unsigned int nSize = script.size() + nSpecialScripts; s << VARINT(nSize); s << CFlatData(script); } template<typename Stream> void Unserialize(Stream &s, int nType, int nVersion) { unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00); s >> REF(CFlatData(vch)); Decompress(nSize, vch); return; } nSize -= nSpecialScripts; script.resize(nSize); s >> REF(CFlatData(script)); } }; -bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags); -bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags); - -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); // Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, // combine them intelligently and return the result. CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); #endif // H_BITCOIN_SCRIPT diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp index 2d2a60074..a17099de7 100644 --- a/src/test/canonical_tests.cpp +++ b/src/test/canonical_tests.cpp @@ -1,111 +1,113 @@ // Copyright (c) 2012-2013 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // // Unit tests for canonical signatures // #include "data/sig_noncanonical.json.h" #include "data/sig_canonical.json.h" +#include "key.h" #include "random.h" -#include "scriptutils.h" +#include "script/interpreter.h" #include "util.h" +#include "utilstrencodings.h" #include <boost/foreach.hpp> #include <boost/test/unit_test.hpp> #include "json/json_spirit_writer_template.h" #include <openssl/ecdsa.h> using namespace std; using namespace json_spirit; // In script_tests.cpp extern Array read_json(const std::string& jsondata); BOOST_AUTO_TEST_SUITE(canonical_tests) // OpenSSL-based test for canonical signature (without test for hashtype byte) bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig) { if (vchSig.size() == 0) return false; const unsigned char *input = &vchSig[0]; ECDSA_SIG *psig = NULL; d2i_ECDSA_SIG(&psig, &input, vchSig.size()); if (psig == NULL) return false; unsigned char buf[256]; unsigned char *pbuf = buf; unsigned int nLen = i2d_ECDSA_SIG(psig, NULL); if (nLen != vchSig.size()) { ECDSA_SIG_free(psig); return false; } nLen = i2d_ECDSA_SIG(psig, &pbuf); ECDSA_SIG_free(psig); return (memcmp(&vchSig[0], &buf[0], nLen) == 0); } // OpenSSL-based test for canonical signature bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) { if (vchSignature.size() < 1) return false; if (vchSignature.size() > 127) return false; if (vchSignature[vchSignature.size() - 1] & 0x7C) return false; std::vector<unsigned char> vchSig(vchSignature); vchSig.pop_back(); if (!IsCanonicalSignature_OpenSSL_inner(vchSig)) return false; return true; } BOOST_AUTO_TEST_CASE(script_canon) { Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical))); BOOST_FOREACH(Value &tv, tests) { string test = tv.get_str(); if (IsHex(test)) { std::vector<unsigned char> sig = ParseHex(test); BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test); BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test); } } } BOOST_AUTO_TEST_CASE(script_noncanon) { Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical))); BOOST_FOREACH(Value &tv, tests) { string test = tv.get_str(); if (IsHex(test)) { std::vector<unsigned char> sig = ParseHex(test); BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test); BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test); } } } BOOST_AUTO_TEST_CASE(script_signstrict) { for (int i=0; i<100; i++) { CKey key; key.MakeNewKey(i & 1); std::vector<unsigned char> sig; uint256 hash = GetRandHash(); BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature. BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it. sig.push_back(0x01); // Append a sighash type. BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S)); BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig)); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index aa9b0de4c..e28682522 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,295 +1,296 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" #include "keystore.h" #include "main.h" #include "script/script.h" +#include "script/interpreter.h" #include "scriptutils.h" #include "uint256.h" #include <boost/assign/std/vector.hpp> #include <boost/foreach.hpp> #include <boost/test/unit_test.hpp> using namespace std; using namespace boost::assign; typedef vector<unsigned char> valtype; BOOST_AUTO_TEST_SUITE(multisig_tests) CScript sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn) { uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL); CScript result; result << OP_0; // CHECKMULTISIG bug workaround BOOST_FOREACH(const CKey &key, keys) { vector<unsigned char> vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; } return result; } BOOST_AUTO_TEST_CASE(multisig_verify) { unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript escrow; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom; // Funding transaction txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; CMutableTransaction txTo[3]; // Spending transaction for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; } vector<CKey> keys; CScript s; // Test a AND b: keys.clear(); keys += key[0],key[1]; // magic operator+= from boost.assign s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags, 0)); for (int i = 0; i < 4; i++) { keys.clear(); keys += key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 1: %d", i)); keys.clear(); keys += key[1],key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 2: %d", i)); } // Test a OR b: for (int i = 0; i < 4; i++) { keys.clear(); keys += key[i]; s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); else BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); } s.clear(); s << OP_0 << OP_0; BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); s.clear(); s << OP_0 << OP_1; BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { keys.clear(); keys += key[i],key[j]; s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 1: %d %d", i, j)); else BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 2: %d %d", i, j)); } } BOOST_AUTO_TEST_CASE(multisig_IsStandard) { CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); txnouttype whichType; CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(a_and_b, whichType)); CScript a_or_b; a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(a_or_b, whichType)); CScript escrow; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(escrow, whichType)); CScript one_of_four; one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG; BOOST_CHECK(!::IsStandard(one_of_four, whichType)); CScript malformed[6]; malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG; malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG; malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG; malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey(); for (int i = 0; i < 6; i++) BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } BOOST_AUTO_TEST_CASE(multisig_Solver1) { // Tests Solver() that returns lists of keys that are // required to satisfy a ScriptPubKey // // Also tests IsMine() and ExtractDestination() // // Note: ExtractDestination for the multisignature transactions // always returns false for this release, even if you have // one key that would satisfy an (a|b) or 2-of-3 keys needed // to spend an escrow transaction. // CBasicKeyStore keystore, emptykeystore, partialkeystore; CKey key[3]; CTxDestination keyaddr[3]; for (int i = 0; i < 3; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); keyaddr[i] = key[i].GetPubKey().GetID(); } partialkeystore.AddKey(key[0]); { vector<valtype> solutions; txnouttype whichType; CScript s; s << key[0].GetPubKey() << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); } { vector<valtype> solutions; txnouttype whichType; CScript s; s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); } { vector<valtype> solutions; txnouttype whichType; CScript s; s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); } { vector<valtype> solutions; txnouttype whichType; CScript s; s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); vector<CTxDestination> addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired == 1); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); } { vector<valtype> solutions; txnouttype whichType; CScript s; s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 5); } } BOOST_AUTO_TEST_CASE(multisig_Sign) { // Test SignSignature() (and therefore the version of Solver() that signs transactions) CBasicKeyStore keystore; CKey key[4]; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript escrow; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom; // Funding transaction txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; CMutableTransaction txTo[3]; // Spending transaction for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; } for (int i = 0; i < 3; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 1421288ee..8abde887c 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -1,214 +1,214 @@ // Copyright (c) 2013 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "data/sighash.json.h" #include "main.h" #include "random.h" #include "serialize.h" #include "script/script.h" -#include "scriptutils.h" +#include "script/interpreter.h" #include "util.h" #include "version.h" #include <iostream> #include <boost/test/unit_test.hpp> #include "json/json_spirit_reader_template.h" #include "json/json_spirit_utils.h" #include "json/json_spirit_writer_template.h" using namespace json_spirit; extern Array read_json(const std::string& jsondata); // Old script.cpp SignatureHash function uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { if (nIn >= txTo.vin.size()) { printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); return 1; } CMutableTransaction txTmp(txTo); // In case concatenating two scripts ends up with two codeseparators, // or an extra one at the end, this prevents all those possible incompatibilities. scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); // Blank out other inputs' signatures for (unsigned int i = 0; i < txTmp.vin.size(); i++) txTmp.vin[i].scriptSig = CScript(); txTmp.vin[nIn].scriptSig = scriptCode; // Blank out some of the outputs if ((nHashType & 0x1f) == SIGHASH_NONE) { // Wildcard payee txTmp.vout.clear(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } else if ((nHashType & 0x1f) == SIGHASH_SINGLE) { // Only lock-in the txout payee at same index as txin unsigned int nOut = nIn; if (nOut >= txTmp.vout.size()) { printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); return 1; } txTmp.vout.resize(nOut+1); for (unsigned int i = 0; i < nOut; i++) txTmp.vout[i].SetNull(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } // Blank out other inputs completely, not recommended for open transactions if (nHashType & SIGHASH_ANYONECANPAY) { txTmp.vin[0] = txTmp.vin[nIn]; txTmp.vin.resize(1); } // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; return ss.GetHash(); } void static RandomScript(CScript &script) { static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); int ops = (insecure_rand() % 10); for (int i=0; i<ops; i++) script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; } void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { tx.nVersion = insecure_rand(); tx.vin.clear(); tx.vout.clear(); tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; int ins = (insecure_rand() % 4) + 1; int outs = fSingle ? ins : (insecure_rand() % 4) + 1; for (int in = 0; in < ins; in++) { tx.vin.push_back(CTxIn()); CTxIn &txin = tx.vin.back(); txin.prevout.hash = GetRandHash(); txin.prevout.n = insecure_rand() % 4; RandomScript(txin.scriptSig); txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1; } for (int out = 0; out < outs; out++) { tx.vout.push_back(CTxOut()); CTxOut &txout = tx.vout.back(); txout.nValue = insecure_rand() % 100000000; RandomScript(txout.scriptPubKey); } } BOOST_AUTO_TEST_SUITE(sighash_tests) BOOST_AUTO_TEST_CASE(sighash_test) { seed_insecure_rand(false); #if defined(PRINT_SIGHASH_JSON) std::cout << "[\n"; std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; #endif int nRandomTests = 50000; #if defined(PRINT_SIGHASH_JSON) nRandomTests = 500; #endif for (int i=0; i<nRandomTests; i++) { int nHashType = insecure_rand(); CMutableTransaction txTo; RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); CScript scriptCode; RandomScript(scriptCode); int nIn = insecure_rand() % txTo.vin.size(); uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); sh = SignatureHash(scriptCode, txTo, nIn, nHashType); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; std::cout << "\t[\"" ; std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; std::cout << HexStr(scriptCode) << "\", "; std::cout << nIn << ", "; std::cout << nHashType << ", \""; std::cout << sho.GetHex() << "\"]"; if (i+1 != nRandomTests) { std::cout << ","; } std::cout << "\n"; #endif BOOST_CHECK(sh == sho); } #if defined(PRINT_SIGHASH_JSON) std::cout << "]\n"; #endif } // Goal: check that SignatureHash generates correct hash BOOST_AUTO_TEST_CASE(sighash_from_data) { Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); std::string strTest = write_string(tv, false); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); continue; } if (test.size() == 1) continue; // comment std::string raw_tx, raw_script, sigHashHex; int nIn, nHashType; uint256 sh; CTransaction tx; CScript scriptCode = CScript(); try { // deserialize test data raw_tx = test[0].get_str(); raw_script = test[1].get_str(); nIn = test[2].get_int(); nHashType = test[3].get_int(); sigHashHex = test[4].get_str(); uint256 sh; CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); stream >> tx; CValidationState state; BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK(state.IsValid()); std::vector<unsigned char> raw = ParseHex(raw_script); scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); } catch (...) { BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); continue; } sh = SignatureHash(scriptCode, tx, nIn, nHashType); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } BOOST_AUTO_TEST_SUITE_END()