diff options
37 files changed, 749 insertions, 422 deletions
diff --git a/.travis.yml b/.travis.yml index b0c8580e6c..567428daf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,9 +35,9 @@ matrix: - compiler: ": Cross-Mac" env: HOST=x86_64-apple-darwin11 PACKAGES="gcc-multilib g++-multilib cmake libcap-dev libz-dev libbz2-dev" OSX_SDK=10.7 GOAL="deploy" - compiler: ": Win64" - env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" + env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui" MAKEJOBS="-j2" - compiler: ": Win32" - env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" + env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui" MAKEJOBS="-j2" install: - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi @@ -46,7 +46,7 @@ before_script: - mkdir -p depends/SDKs depends/sdk-sources - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then wget $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -O depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS || (echo "Build failure. Verbose build follows." && make -C depends V=1 HOST=$HOST $DEP_OPTS) + - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS script: - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5fbab57dd4..51f2ea663b 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -93,5 +93,5 @@ endef define $(package)_postprocess_cmds rm -rf mkspecs/ lib/cmake/ && \ - rm lib/libQt5Bootstrap.a lib/lib*.la lib/lib*.prl + rm lib/libQt5Bootstrap.a lib/lib*.la lib/*.prl plugins/*/*.prl endef diff --git a/doc/README_osx.txt b/doc/README_osx.txt index 2be56c1592..8831649bd8 100644 --- a/doc/README_osx.txt +++ b/doc/README_osx.txt @@ -20,14 +20,6 @@ https://github.com/mingwandroid/toolchain4 In order to build a working toolchain, the following source packages are needed from Apple: cctools, dyld, and ld64. -Beware. This part is ugly. Very very very ugly. In the future, this should be -broken out into a new repository and cleaned up. Additionally, the binaries -only work when built as x86 and not x86_64. This is an especially nasty -limitation because it must be linked with the toolchain's libLTO.so, meaning -that the entire toolchain must be x86. Gitian x86_64 should not be used until -this has been fixed, because it would mean that several native dependencies -(openssl, libuuid, etc) would need to be built as x86 first. - These tools inject timestamps by default, which produce non-deterministic binaries. The ZERO_AR_DATE environment variable is used to disable that. diff --git a/doc/build-osx.md b/doc/build-osx.md index dc55f8259e..c79c1317b0 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -5,8 +5,7 @@ This guide will show you how to build bitcoind(headless client) for OSX. Notes ----- -* Tested on OS X 10.6 through 10.9 on 64-bit Intel processors only. -Older OSX releases or 32-bit processors are no longer supported. +* Tested on OS X 10.7 through 10.10 on 64-bit Intel processors only. * All of the commands should be executed in a Terminal application. The built-in one is located in `/Applications/Utilities`. @@ -96,9 +95,9 @@ as follows for maximum compatibility: All dependencies should be compiled with these flags: - -mmacosx-version-min=10.6 + -mmacosx-version-min=10.7 -arch x86_64 - -isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.6.sdk + -isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk Once dependencies are compiled, see release-process.md for how the Bitcoin-Qt.app bundle is packaged and signed to create the .dmg disk image that is distributed. diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index f07e3c6d9d..a0056c141b 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -13,7 +13,7 @@ export BITCOIND=${REAL_BITCOIND} if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then ${BUILDDIR}/qa/rpc-tests/wallet.sh "${BUILDDIR}/src" ${BUILDDIR}/qa/rpc-tests/listtransactions.py --srcdir "${BUILDDIR}/src" - ${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src" + #${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src" else echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" fi diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py index c3396a5a83..9591c024fb 100755 --- a/qa/rpc-tests/test_framework.py +++ b/qa/rpc-tests/test_framework.py @@ -44,8 +44,8 @@ class BitcoinTestFramework(object): # on outward. This ensures that chains are properly reorganised. if not split: connect_nodes_bi(self.nodes, 1, 2) - sync_blocks(self.nodes[1:2]) - sync_mempools(self.nodes[1:2]) + sync_blocks(self.nodes[1:3]) + sync_mempools(self.nodes[1:3]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 2, 3) @@ -63,9 +63,9 @@ class BitcoinTestFramework(object): def sync_all(self): if self.is_network_split: - sync_blocks(self.nodes[:1]) + sync_blocks(self.nodes[:2]) sync_blocks(self.nodes[2:]) - sync_mempools(self.nodes[:1]) + sync_mempools(self.nodes[:2]) sync_mempools(self.nodes[2:]) else: sync_blocks(self.nodes) diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index e5383b6c57..0d5eeefa79 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -61,8 +61,8 @@ def sync_mempools(rpc_connections): bitcoind_processes = {} -def initialize_datadir(dir, n): - datadir = os.path.join(dir, "node"+str(n)) +def initialize_datadir(dirname, n): + datadir = os.path.join(dirname, "node"+str(n)) if not os.path.isdir(datadir): os.makedirs(datadir) with open(os.path.join(datadir, "bitcoin.conf"), 'w') as f: @@ -145,11 +145,11 @@ def _rpchost_to_args(rpchost): rv += ['-rpcport=' + rpcport] return rv -def start_node(i, dir, extra_args=None, rpchost=None): +def start_node(i, dirname, extra_args=None, rpchost=None): """ Start a bitcoind and return RPC connection to it """ - datadir = os.path.join(dir, "node"+str(i)) + datadir = os.path.join(dirname, "node"+str(i)) args = [ os.getenv("BITCOIND", "bitcoind"), "-datadir="+datadir, "-keypool=1", "-discover=0" ] if extra_args is not None: args.extend(extra_args) bitcoind_processes[i] = subprocess.Popen(args) @@ -163,15 +163,15 @@ def start_node(i, dir, extra_args=None, rpchost=None): proxy.url = url # store URL on proxy for info return proxy -def start_nodes(num_nodes, dir, extra_args=None, rpchost=None): +def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None): """ Start multiple bitcoinds, return RPC connections to them """ if extra_args is None: extra_args = [ None for i in range(num_nodes) ] - return [ start_node(i, dir, extra_args[i], rpchost) for i in range(num_nodes) ] + return [ start_node(i, dirname, extra_args[i], rpchost) for i in range(num_nodes) ] -def log_filename(dir, n_node, logname): - return os.path.join(dir, "node"+str(n_node), "regtest", logname) +def log_filename(dirname, n_node, logname): + return os.path.join(dirname, "node"+str(n_node), "regtest", logname) def stop_node(node, i): node.stop() diff --git a/src/Makefile.am b/src/Makefile.am index 8b5d009842..b3b41e3d17 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,7 @@ BITCOIN_CORE_H = \ script/sigcache.h \ script/sign.h \ script/standard.h \ + script/script_error.h \ serialize.h \ streams.h \ sync.h \ @@ -235,6 +236,7 @@ libbitcoin_common_a_SOURCES = \ script/script.cpp \ script/sign.cpp \ script/standard.cpp \ + script/script_error.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9ffc369b40..e539eb7bd7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -369,7 +369,6 @@ bool SelectParamsFromCommandLine() if (network == CBaseChainParams::MAX_NETWORK_TYPES) return false; - SelectBaseParams(network); SelectParams(network); return true; } diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 6e35bf17b3..2c100337d2 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -130,6 +130,7 @@ public: extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxEditField, this).size(); hint += extra; + hint.setHeight(h); opt.rect = rect(); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 879a504115..2bde02c0a1 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -121,6 +121,8 @@ Value setgenerate(const Array& params, bool fHelp) "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" " Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array, -regtest only) hashes of blocks generated\n" "\nExamples:\n" "\nSet the generation on with a limit of one processor\n" + HelpExampleCli("setgenerate", "true 1") + @@ -154,26 +156,38 @@ Value setgenerate(const Array& params, bool fHelp) int nHeightEnd = 0; int nHeight = 0; int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1); + CReserveKey reservekey(pwalletMain); + { // Don't keep cs_main locked LOCK(cs_main); nHeightStart = chainActive.Height(); nHeight = nHeightStart; nHeightEnd = nHeightStart+nGenerate; } - int nHeightLast = -1; + unsigned int nExtraNonce = 0; + Array blockHashes; while (nHeight < nHeightEnd) { - if (nHeightLast != nHeight) + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + CBlock *pblock = &pblocktemplate->block; { - nHeightLast = nHeight; - GenerateBitcoins(fGenerate, pwalletMain, 1); - } - MilliSleep(1); - { // Don't keep cs_main locked LOCK(cs_main); - nHeight = chainActive.Height(); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^32). That ain't gonna happen. + ++pblock->nNonce; } + CValidationState state; + if (!ProcessNewBlock(state, NULL, pblock)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + ++nHeight; + blockHashes.push_back(pblock->GetHash().GetHex()); } + return blockHashes; } else // Not -regtest: start generate thread, return immediately { diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index f2b5e2061e..4d9e5ea137 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1067,7 +1067,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) "\nList balances by receiving address.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. includeempty (numeric, optional, dafault=false) Whether to include addresses that haven't received any payments.\n" + "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n" "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" "\nResult:\n" @@ -1335,7 +1335,7 @@ Value listaccounts(const Array& params, bool fHelp) "listaccounts ( minconf includeWatchonly)\n" "\nReturns Object that has account names as keys, account balances as values.\n" "\nArguments:\n" - "1. minconf (numeric, optional, default=1) Only onclude transactions with at least this many confirmations\n" + "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n" "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n" "\nResult:\n" "{ (json object where keys are account names, and values are numeric balances\n" diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 54c2847f79..cf81fe30a2 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -13,7 +13,6 @@ #include "pubkey.h" #include "script/script.h" #include "uint256.h" -#include "util.h" using namespace std; @@ -26,6 +25,24 @@ static const CScriptNum bnOne(1); static const CScriptNum bnFalse(0); static const CScriptNum bnTrue(1); +namespace { + +inline bool set_success(ScriptError* ret) +{ + if (ret) + *ret = SCRIPT_ERR_OK; + return true; +} + +inline bool set_error(ScriptError* ret, const ScriptError serror) +{ + if (ret) + *ret = serror; + return false; +} + +} // anon namespace + bool CastToBool(const valtype& vch) { for (unsigned int i = 0; i < vch.size(); i++) @@ -41,10 +58,10 @@ bool CastToBool(const valtype& vch) return false; } -// -// Script is a stack machine (like Forth) that evaluates a predicate -// returning a bool indicating valid or not. There are no loops. -// +/** + * 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) @@ -55,67 +72,105 @@ static inline void popstack(vector<valtype>& stack) } bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { - if (vchPubKey.size() < 33) - return error("Non-canonical public key: too short"); + if (vchPubKey.size() < 33) { + // Non-canonical public key: too short + return false; + } if (vchPubKey[0] == 0x04) { - if (vchPubKey.size() != 65) - return error("Non-canonical public key: invalid length for uncompressed key"); + if (vchPubKey.size() != 65) { + // Non-canonical public key: invalid length for uncompressed key + return false; + } } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { - if (vchPubKey.size() != 33) - return error("Non-canonical public key: invalid length for compressed key"); + if (vchPubKey.size() != 33) { + // Non-canonical public key: invalid length for compressed key + return false; + } } else { - return error("Non-canonical public key: neither compressed nor uncompressed"); + // Non-canonical public key: neither compressed nor uncompressed + return false; } return true; } +/** + * 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). + * + * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 + */ bool static IsDERSignature(const valtype &vchSig) { - // 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"); - 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"); + + if (vchSig.size() < 9) { + // Non-canonical signature: too short + return false; + } + if (vchSig.size() > 73) { + // Non-canonical signature: too long + return false; + } + if (vchSig[0] != 0x30) { + // Non-canonical signature: wrong type + return false; + } + if (vchSig[1] != vchSig.size()-3) { + // Non-canonical signature: wrong length marker + return false; + } unsigned int nLenR = vchSig[3]; - if (5 + nLenR >= vchSig.size()) - return error("Non-canonical signature: S length misplaced"); + if (5 + nLenR >= vchSig.size()) { + // Non-canonical signature: S length misplaced + return false; + } unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) - return error("Non-canonical signature: R+S length mismatch"); + if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) { + // Non-canonical signature: R+S length mismatch + return false; + } 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"); + if (R[-2] != 0x02) { + // Non-canonical signature: R value type mismatch + return false; + } + if (nLenR == 0) { + // Non-canonical signature: R length is zero + return false; + } + if (R[0] & 0x80) { + // Non-canonical signature: R value negative + return false; + } + if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) { + // Non-canonical signature: R value excessively padded + return false; + } 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 (S[-2] != 0x02) { + // Non-canonical signature: S value type mismatch + return false; + } + if (nLenS == 0) { + // Non-canonical signature: S length is zero + return false; + } + if (S[0] & 0x80) { + // Non-canonical signature: S value negative + return false; + } + if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) { + // Non-canonical signature: S value excessively padded + return false; + } return true; } -bool static IsLowDERSignature(const valtype &vchSig) { +bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { if (!IsDERSignature(vchSig)) { - return false; + return set_error(serror, SCRIPT_ERR_SIG_DER); } unsigned int nLenR = vchSig[3]; unsigned int nLenS = vchSig[5+nLenR]; @@ -124,7 +179,7 @@ bool static IsLowDERSignature(const valtype &vchSig) { // complement modulo the order could have been used instead, which is // one byte shorter when encoded correctly. if (!eccrypto::CheckSignatureElement(S, nLenS, true)) - return error("Non-canonical signature: S value is unnecessarily high"); + return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); return true; } @@ -135,18 +190,19 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) { } unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return error("Non-canonical signature: unknown hashtype byte"); + return false; return true; } -bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) { +bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) { - return false; - } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) { + return set_error(serror, SCRIPT_ERR_SIG_DER); + } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { + // serror is set return false; } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) { - return false; + return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); } return true; } @@ -181,7 +237,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) +bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); @@ -190,8 +246,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un valtype vchPushValue; vector<bool> vfExec; vector<valtype> altstack; + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > 10000) - return false; + return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; @@ -205,13 +262,13 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) - return false; + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) - return false; + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); // Note how OP_RESERVED does not count towards the opcode limit. if (opcode > OP_16 && ++nOpCount > 201) - return false; + return set_error(serror, SCRIPT_ERR_OP_COUNT); if (opcode == OP_CAT || opcode == OP_SUBSTR || @@ -228,11 +285,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) - return false; // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes. if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { - return false; + return set_error(serror, SCRIPT_ERR_MINIMALDATA); } stack.push_back(vchPushValue); } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) @@ -284,7 +341,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (fExec) { if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); fValue = CastToBool(vch); if (opcode == OP_NOTIF) @@ -298,7 +355,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un case OP_ELSE: { if (vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); vfExec.back() = !vfExec.back(); } break; @@ -306,7 +363,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un case OP_ENDIF: { if (vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); vfExec.pop_back(); } break; @@ -316,18 +373,18 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // (true -- ) or // (false -- false) and return if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); bool fValue = CastToBool(stacktop(-1)); if (fValue) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_VERIFY); } break; case OP_RETURN: { - return false; + return set_error(serror, SCRIPT_ERR_OP_RETURN); } break; @@ -338,7 +395,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un case OP_TOALTSTACK: { if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); altstack.push_back(stacktop(-1)); popstack(stack); } @@ -347,7 +404,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un case OP_FROMALTSTACK: { if (altstack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); stack.push_back(altstacktop(-1)); popstack(altstack); } @@ -357,7 +414,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- ) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); popstack(stack); popstack(stack); } @@ -367,7 +424,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); @@ -379,7 +436,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); @@ -393,7 +450,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); @@ -405,7 +462,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end()-6, stack.end()-4); @@ -418,7 +475,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } @@ -428,7 +485,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x - 0 | x x) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); if (CastToBool(vch)) stack.push_back(vch); @@ -447,7 +504,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x -- ) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); popstack(stack); } break; @@ -456,7 +513,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x -- x x) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); stack.push_back(vch); } @@ -466,7 +523,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); stack.erase(stack.end() - 2); } break; @@ -475,7 +532,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-2); stack.push_back(vch); } @@ -487,11 +544,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // (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; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) stack.erase(stack.end()-n-1); @@ -505,7 +562,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } @@ -515,7 +572,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- x2 x1) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); swap(stacktop(-2), stacktop(-1)); } break; @@ -524,7 +581,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype vch = stacktop(-1); stack.insert(stack.end()-2, vch); } @@ -535,7 +592,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (in -- in size) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } @@ -551,7 +608,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 - bool) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); @@ -568,7 +625,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (fEqual) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_EQUALVERIFY); } } break; @@ -586,7 +643,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (in -- out) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); CScriptNum bn(stacktop(-1), fRequireMinimal); switch (opcode) { @@ -619,7 +676,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x1 x2 -- out) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); CScriptNum bn1(stacktop(-2), fRequireMinimal); CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); @@ -655,7 +712,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (CastToBool(stacktop(-1))) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY); } } break; @@ -664,7 +721,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (x min max -- out) if (stack.size() < 3) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); CScriptNum bn1(stacktop(-3), fRequireMinimal); CScriptNum bn2(stacktop(-2), fRequireMinimal); CScriptNum bn3(stacktop(-1), fRequireMinimal); @@ -688,7 +745,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (in -- hash) if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) @@ -718,7 +775,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un { // (sig pubkey -- bool) if (stack.size() < 2) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); @@ -729,10 +786,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); - if (!CheckSignatureEncoding(vchSig, flags)) { + if (!CheckSignatureEncoding(vchSig, flags, serror)) { + //serror is set return false; } - bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode); popstack(stack); @@ -743,7 +800,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (fSuccess) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); } } break; @@ -755,26 +812,26 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un int i = 1; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nKeysCount < 0 || nKeysCount > 20) - return false; + return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); nOpCount += nKeysCount; if (nOpCount > 201) - return false; + return set_error(serror, SCRIPT_ERR_OP_COUNT); int ikey = ++i; i += nKeysCount; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) - return false; + return set_error(serror, SCRIPT_ERR_SIG_COUNT); int isig = ++i; i += nSigsCount; if ((int)stack.size() < i) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); @@ -792,7 +849,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un valtype& vchSig = stacktop(-isig); valtype& vchPubKey = stacktop(-ikey); - if (!CheckSignatureEncoding(vchSig, flags)) { + if (!CheckSignatureEncoding(vchSig, flags, serror)) { + // serror is set return false; } @@ -823,9 +881,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // so optionally verify it is exactly equal to zero prior // to removing it from the stack. if (stack.size() < 1) - return false; + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) - return error("CHECKMULTISIG dummy argument not null"); + return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -835,44 +893,45 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (fSuccess) popstack(stack); else - return false; + return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); } } break; default: - return false; + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } // Size limits if (stack.size() + altstack.size() > 1000) - return false; + return set_error(serror, SCRIPT_ERR_STACK_SIZE); } } catch (...) { - return false; + return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); } if (!vfExec.empty()) - return false; + return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - return true; + return set_success(serror); } namespace { -/** Wrapper that serializes like CTransaction, but with the modifications +/** + * 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 + 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) : @@ -951,7 +1010,7 @@ public: ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) SerializeOutput(s, nOutput, nType, nVersion); - // Serialie nLockTime + // Serialize nLockTime ::Serialize(s, txTo.nLockTime, nType, nVersion); } }; @@ -961,14 +1020,14 @@ public: 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); + // nIn out of range 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); + // nOut out of range return 1; } } @@ -1008,30 +1067,35 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); + if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { - return false; + return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } vector<vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker)) + if (!EvalScript(stack, scriptSig, flags, checker, serror)) + // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker)) + if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) + // serror is set return false; if (stack.empty()) - return false; + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); if (CastToBool(stack.back()) == false) - return false; + return set_error(serror, SCRIPT_ERR_EVAL_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 + // scriptSig must be literals-only or validation fails + if (!scriptSig.IsPushOnly()) + return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); // stackCopy cannot be empty here, because if it was the // P2SH HASH <> EQUAL scriptPubKey would be evaluated with @@ -1042,12 +1106,16 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, flags, checker)) + if (!EvalScript(stackCopy, pubKey2, flags, checker, serror)) + // serror is set return false; if (stackCopy.empty()) - return false; - return CastToBool(stackCopy.back()); + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); + if (!CastToBool(stackCopy.back())) + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); + else + return set_success(serror); } - return true; + return set_success(serror); } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index ed899fc411..14cccc558f 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_SCRIPT_INTERPRETER_H #define BITCOIN_SCRIPT_INTERPRETER_H +#include "script_error.h" + #include <vector> #include <stdint.h> #include <string> @@ -85,7 +87,7 @@ public: bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; }; -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker); +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); #endif // BITCOIN_SCRIPT_INTERPRETER_H diff --git a/src/script/script.h b/src/script/script.h index e525ad13ee..9c22cb908c 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -179,12 +179,14 @@ public: class CScriptNum { -// Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. -// The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], -// but results may overflow (and are valid as long as they are not used in a subsequent -// numeric operation). CScriptNum enforces those semantics by storing results as -// an int64 and allowing out-of-range values to be returned as a vector of bytes but -// throwing an exception if arithmetic is done or the result is interpreted as an integer. +/** + * Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers. + * The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1], + * but results may overflow (and are valid as long as they are not used in a subsequent + * numeric operation). CScriptNum enforces those semantics by storing results as + * an int64 and allowing out-of-range values to be returned as a vector of bytes but + * throwing an exception if arithmetic is done or the result is interpreted as an integer. + */ public: explicit CScriptNum(const int64_t& n) @@ -516,7 +518,7 @@ public: return true; } - // Encode/decode small integers: + /** Encode/decode small integers: */ static int DecodeOP_N(opcodetype opcode) { if (opcode == OP_0) @@ -560,25 +562,31 @@ public: return nFound; } - // Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs - // as 20 sigops. With pay-to-script-hash, that changed: - // CHECKMULTISIGs serialized in scriptSigs are - // counted more accurately, assuming they are of the form - // ... OP_N CHECKMULTISIG ... + /** + * Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs + * as 20 sigops. With pay-to-script-hash, that changed: + * CHECKMULTISIGs serialized in scriptSigs are + * counted more accurately, assuming they are of the form + * ... OP_N CHECKMULTISIG ... + */ unsigned int GetSigOpCount(bool fAccurate) const; - // Accurately count sigOps, including sigOps in - // pay-to-script-hash transactions: + /** + * Accurately count sigOps, including sigOps in + * pay-to-script-hash transactions: + */ unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsPayToScriptHash() const; - // Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). + /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; - // Returns whether the script is guaranteed to fail at execution, - // regardless of the initial stack. This allows outputs to be pruned - // instantly when entering the UTXO set. + /** + * Returns whether the script is guaranteed to fail at execution, + * regardless of the initial stack. This allows outputs to be pruned + * instantly when entering the UTXO set. + */ bool IsUnspendable() const { return (size() > 0 && *begin() == OP_RETURN); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp new file mode 100644 index 0000000000..4a3df268ec --- /dev/null +++ b/src/script/script_error.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "script_error.h" + +const char* ScriptErrorString(const ScriptError serror) +{ + switch (serror) + { + case SCRIPT_ERR_OK: + return "No error"; + case SCRIPT_ERR_EVAL_FALSE: + return "Script evaluated without error but finished with a false/empty top stack element"; + case SCRIPT_ERR_VERIFY: + return "Script failed an OP_VERIFY operation"; + case SCRIPT_ERR_EQUALVERIFY: + return "Script failed an OP_EQUALVERIFY operation"; + case SCRIPT_ERR_CHECKMULTISIGVERIFY: + return "Script failed an OP_CHECKMULTISIGVERIFY operation"; + case SCRIPT_ERR_CHECKSIGVERIFY: + return "Script failed an OP_CHECKSIGVERIFY operation"; + case SCRIPT_ERR_NUMEQUALVERIFY: + return "Script failed an OP_NUMEQUALVERIFY operation"; + case SCRIPT_ERR_SCRIPT_SIZE: + return "Script is too big"; + case SCRIPT_ERR_PUSH_SIZE: + return "Push value size limit exceeded"; + case SCRIPT_ERR_OP_COUNT: + return "Operation limit exceeded"; + case SCRIPT_ERR_STACK_SIZE: + return "Stack size limit exceeded"; + case SCRIPT_ERR_SIG_COUNT: + return "Signature count negative or greater than pubkey count"; + case SCRIPT_ERR_PUBKEY_COUNT: + return "Pubkey count negative or limit exceeded"; + case SCRIPT_ERR_BAD_OPCODE: + return "Opcode missing or not understood"; + case SCRIPT_ERR_DISABLED_OPCODE: + return "Attempted to use a disabled opcode"; + case SCRIPT_ERR_INVALID_STACK_OPERATION: + return "Operation not valid with the current stack size"; + case SCRIPT_ERR_INVALID_ALTSTACK_OPERATION: + return "Operation not valid with the current altstack size"; + case SCRIPT_ERR_OP_RETURN: + return "OP_RETURN was encountered"; + case SCRIPT_ERR_UNBALANCED_CONDITIONAL: + return "Invalid OP_IF construction"; + case SCRIPT_ERR_SIG_HASHTYPE: + return "Signature hash type missing or not understood"; + case SCRIPT_ERR_SIG_DER: + return "Non-canonical DER signature"; + case SCRIPT_ERR_MINIMALDATA: + return "Data push larger than necessary"; + case SCRIPT_ERR_SIG_PUSHONLY: + return "Only non-push operators allowed in signatures"; + case SCRIPT_ERR_SIG_HIGH_S: + return "Non-canonical signature: S value is unnecessarily high"; + case SCRIPT_ERR_SIG_NULLDUMMY: + return "Dummy CHECKMULTISIG argument must be zero"; + case SCRIPT_ERR_UNKNOWN_ERROR: + case SCRIPT_ERR_ERROR_COUNT: + default: break; + } + return "unknown error"; +} diff --git a/src/script/script_error.h b/src/script/script_error.h new file mode 100644 index 0000000000..ae6626b257 --- /dev/null +++ b/src/script/script_error.h @@ -0,0 +1,53 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SCRIPT_ERROR_H +#define BITCOIN_SCRIPT_ERROR_H + +typedef enum ScriptError_t +{ + SCRIPT_ERR_OK = 0, + SCRIPT_ERR_UNKNOWN_ERROR, + SCRIPT_ERR_EVAL_FALSE, + SCRIPT_ERR_OP_RETURN, + + /* Max sizes */ + SCRIPT_ERR_SCRIPT_SIZE, + SCRIPT_ERR_PUSH_SIZE, + SCRIPT_ERR_OP_COUNT, + SCRIPT_ERR_STACK_SIZE, + SCRIPT_ERR_SIG_COUNT, + SCRIPT_ERR_PUBKEY_COUNT, + + /* Failed verify operations */ + SCRIPT_ERR_VERIFY, + SCRIPT_ERR_EQUALVERIFY, + SCRIPT_ERR_CHECKMULTISIGVERIFY, + SCRIPT_ERR_CHECKSIGVERIFY, + SCRIPT_ERR_NUMEQUALVERIFY, + + /* Logical/Format/Canonical errors */ + SCRIPT_ERR_BAD_OPCODE, + SCRIPT_ERR_DISABLED_OPCODE, + SCRIPT_ERR_INVALID_STACK_OPERATION, + SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, + SCRIPT_ERR_UNBALANCED_CONDITIONAL, + + /* BIP62 */ + SCRIPT_ERR_SIG_HASHTYPE, + SCRIPT_ERR_SIG_DER, + SCRIPT_ERR_MINIMALDATA, + SCRIPT_ERR_SIG_PUSHONLY, + SCRIPT_ERR_SIG_HIGH_S, + SCRIPT_ERR_SIG_NULLDUMMY, + + SCRIPT_ERR_ERROR_COUNT +} ScriptError; + +#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT + +const char* ScriptErrorString(const ScriptError error); + +#endif // BITCOIN_SCRIPT_ERROR_H diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index d76a5acd63..5580a5933e 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -15,13 +15,15 @@ namespace { -// 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) +/** + * 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): + //! 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; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 9dfd640dfb..7dfed751b6 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -46,12 +46,12 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2 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. -// +/** + * 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) { diff --git a/src/script/sign.h b/src/script/sign.h index 99d5516adb..45a5e0dea3 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -17,8 +17,10 @@ struct CMutableTransaction; bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, -// combine them intelligently and return the result. +/** + * Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, + * combine them intelligently and return the result. + */ CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index e238ecedb0..ab6e6cde0d 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -34,9 +34,9 @@ const char* GetTxnOutputType(txnouttype t) return NULL; } -// -// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. -// +/** + * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. + */ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) { // Templates diff --git a/src/script/standard.h b/src/script/standard.h index 55a27881aa..f3dcc75fdc 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -25,27 +25,31 @@ public: CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes +static const unsigned int MAX_OP_RETURN_RELAY = 40; //! bytes extern unsigned nMaxDatacarrierBytes; -// 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. +/** + * 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. +/** + * 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_MINIMALDATA | SCRIPT_VERIFY_NULLDUMMY; -// For convenience, standard but not mandatory verify flags. +/** 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 @@ -65,7 +69,8 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; -/** A txout script template with a specific destination. It is either: +/** + * A txout script template with a specific destination. It is either: * * CNoDestination: no destination set * * CKeyID: TX_PUBKEYHASH destination * * CScriptID: TX_SCRIPTHASH destination diff --git a/src/serialize.h b/src/serialize.h index 877ef8640a..ad38a3fa22 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SERIALIZE_H @@ -22,23 +22,28 @@ class CScript; static const unsigned int MAX_SIZE = 0x02000000; -// Used to bypass the rule against non-const reference to temporary -// where it makes sense with wrappers such as CFlatData or CTxDB +/** + * Used to bypass the rule against non-const reference to temporary + * where it makes sense with wrappers such as CFlatData or CTxDB + */ template<typename T> inline T& REF(const T& val) { return const_cast<T&>(val); } -// Used to acquire a non-const pointer "this" to generate bodies -// of const serialization operations from a template +/** + * Used to acquire a non-const pointer "this" to generate bodies + * of const serialization operations from a template + */ template<typename T> inline T* NCONST_PTR(const T* val) { return const_cast<T*>(val); } -/** Get begin pointer of vector (non-const version). +/** + * Get begin pointer of vector (non-const version). * @note These functions avoid the undefined case of indexing into an empty * vector, as well as that of indexing after the end of the vector. */ @@ -82,10 +87,12 @@ enum #define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) -/* Implement three methods for serializable objects. These are actually wrappers over +/** + * Implement three methods for serializable objects. These are actually wrappers over * "SerializationOp" template, which implements the body of each class' serialization * code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be - * added as members. */ + * added as members. + */ #define ADD_SERIALIZE_METHODS \ size_t GetSerializeSize(int nType, int nVersion) const { \ CSizeComputer s(nType, nVersion); \ @@ -103,9 +110,9 @@ enum -// -// Basic types -// +/* + * Basic Types + */ #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) @@ -160,13 +167,13 @@ template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0 -// -// Compact size -// size < 253 -- 1 byte -// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) -// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) -// size > UINT_MAX -- 9 bytes (255 + 8 bytes) -// +/** + * Compact Size + * size < 253 -- 1 byte + * size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) + * size <= UINT_MAX -- 5 bytes (254 + 4 bytes) + * size > UINT_MAX -- 9 bytes (255 + 8 bytes) + */ inline unsigned int GetSizeOfCompactSize(uint64_t nSize) { if (nSize < 253) return sizeof(unsigned char); @@ -246,27 +253,29 @@ uint64_t ReadCompactSize(Stream& is) return nSizeRet; } -// Variable-length integers: bytes are a MSB base-128 encoding of the number. -// The high bit in each byte signifies whether another digit follows. To make -// the encoding is one-to-one, one is subtracted from all but the last digit. -// Thus, the byte sequence a[] with length len, where all but the last byte -// has bit 128 set, encodes the number: -// -// (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) -// -// Properties: -// * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) -// * Every integer has exactly one encoding -// * Encoding does not depend on size of original integer type -// * No redundancy: every (infinite) byte sequence corresponds to a list -// of encoded integers. -// -// 0: [0x00] 256: [0x81 0x00] -// 1: [0x01] 16383: [0xFE 0x7F] -// 127: [0x7F] 16384: [0xFF 0x00] -// 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] -// 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] -// 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] +/** + * Variable-length integers: bytes are a MSB base-128 encoding of the number. + * The high bit in each byte signifies whether another digit follows. To make + * sure the encoding is one-to-one, one is subtracted from all but the last digit. + * Thus, the byte sequence a[] with length len, where all but the last byte + * has bit 128 set, encodes the number: + * + * (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) + * + * Properties: + * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) + * * Every integer has exactly one encoding + * * Encoding does not depend on size of original integer type + * * No redundancy: every (infinite) byte sequence corresponds to a list + * of encoded integers. + * + * 0: [0x00] 256: [0x81 0x00] + * 1: [0x01] 16383: [0xFE 0x7F] + * 127: [0x7F] 16384: [0xFF 0x00] + * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] + * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] + * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] + */ template<typename I> inline unsigned int GetSizeOfVarInt(I n) @@ -317,7 +326,8 @@ I ReadVarInt(Stream& is) #define VARINT(obj) REF(WrapVarInt(REF(obj))) #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) -/** Wrapper for serializing arrays and POD. +/** + * Wrapper for serializing arrays and POD. */ class CFlatData { @@ -415,17 +425,21 @@ public: template<typename I> CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); } -// -// Forward declarations -// +/** + * Forward declarations + */ -// string +/** + * string + */ template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0); template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0); template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0); -// vector -// vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. +/** + * vector + * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. + */ template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&); template<typename T, typename A, typename V> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&); template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion); @@ -436,22 +450,30 @@ template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&); template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion); -// others derived from vector +/** + * others derived from vector + */ extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion); template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion); -// pair +/** + * pair + */ template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion); template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion); template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion); -// map +/** + * map + */ template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion); template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion); template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion); -// set +/** + * set + */ template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion); template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion); template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion); @@ -460,12 +482,12 @@ template<typename Stream, typename K, typename Pred, typename A> void Unserializ -// -// If none of the specialized versions above matched, default to calling member function. -// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. -// The compiler will only cast int to long if none of the other templates matched. -// Thanks to Boost serialization for this idea. -// +/** + * If none of the specialized versions above matched, default to calling member function. + * "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. + * The compiler will only cast int to long if none of the other templates matched. + * Thanks to Boost serialization for this idea. + */ template<typename T> inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) { @@ -488,9 +510,9 @@ inline void Unserialize(Stream& is, T& a, long nType, int nVersion) -// -// string -// +/** + * string + */ template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int) { @@ -516,9 +538,9 @@ void Unserialize(Stream& is, std::basic_string<C>& str, int, int) -// -// vector -// +/** + * vector + */ template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&) { @@ -606,9 +628,9 @@ inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersio -// -// others derived from vector -// +/** + * others derived from vector + */ inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) { return GetSerializeSize((const std::vector<unsigned char>&)v, nType, nVersion); @@ -628,9 +650,9 @@ void Unserialize(Stream& is, CScript& v, int nType, int nVersion) -// -// pair -// +/** + * pair + */ template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion) { @@ -653,9 +675,9 @@ void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion) -// -// map -// +/** + * map + */ template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion) { @@ -689,9 +711,9 @@ void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion -// -// set -// +/** + * set + */ template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion) { @@ -725,9 +747,9 @@ void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion) -// -// Support for ADD_SERIALIZE_METHODS and READWRITE macro -// +/** + * Support for ADD_SERIALIZE_METHODS and READWRITE macro + */ struct CSerActionSerialize { bool ForRead() const { return false; } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index e9fc86779a..8d06caa147 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -6,6 +6,7 @@ #include "keystore.h" #include "main.h" #include "script/script.h" +#include "script/script_error.h" #include "script/interpreter.h" #include "script/sign.h" #include "uint256.h" @@ -46,6 +47,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify) { unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; + ScriptError err; CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); @@ -82,19 +84,22 @@ BOOST_AUTO_TEST_CASE(multisig_verify) 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, flags, SignatureChecker(txTo[0], 0))); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); 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, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); 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, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } // Test a OR b: @@ -104,16 +109,24 @@ BOOST_AUTO_TEST_CASE(multisig_verify) 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, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); + { + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } else - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); + { + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); + } } s.clear(); s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); for (int i = 0; i < 4; i++) @@ -123,9 +136,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify) 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, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 1: %d %d", i, j)); + { + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); + } else - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 2: %d %d", i, j)); + { + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); + } } } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index fcab652783..a969eefa05 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -6,6 +6,7 @@ #include "keystore.h" #include "main.h" #include "script/script.h" +#include "script/script_error.h" #include "script/sign.h" #ifdef ENABLE_WALLET @@ -27,7 +28,7 @@ Serialize(const CScript& s) } static bool -Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) +Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err) { // Create dummy to/from transactions: CMutableTransaction txFrom; @@ -42,7 +43,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0)); + return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0), &err); } @@ -124,6 +125,7 @@ BOOST_AUTO_TEST_CASE(sign) BOOST_AUTO_TEST_CASE(norecurse) { + ScriptError err; // Make sure only the outer pay-to-script-hash does the // extra-validation thing: CScript invalidAsScript; @@ -135,7 +137,8 @@ BOOST_AUTO_TEST_CASE(norecurse) scriptSig << Serialize(invalidAsScript); // Should not verify, because it will try to execute OP_INVALIDOPCODE - BOOST_CHECK(!Verify(scriptSig, p2sh, true)); + BOOST_CHECK(!Verify(scriptSig, p2sh, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err)); // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: @@ -143,7 +146,8 @@ BOOST_AUTO_TEST_CASE(norecurse) CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); - BOOST_CHECK(Verify(scriptSig2, p2sh2, true)); + BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(set) @@ -238,6 +242,7 @@ BOOST_AUTO_TEST_CASE(switchover) { // Test switch over code CScript notValid; + ScriptError err; notValid << OP_11 << OP_12 << OP_EQUALVERIFY; CScript scriptSig; scriptSig << Serialize(notValid); @@ -246,9 +251,11 @@ BOOST_AUTO_TEST_CASE(switchover) // Validation should succeed under old rules (hash is correct): - BOOST_CHECK(Verify(scriptSig, fund, false)); + BOOST_CHECK(Verify(scriptSig, fund, false, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); // Fail under new: - BOOST_CHECK(!Verify(scriptSig, fund, true)); + BOOST_CHECK(!Verify(scriptSig, fund, true, err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(AreInputsStandard) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index cff1664a1e..ede13b23c2 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -10,6 +10,7 @@ #include "keystore.h" #include "main.h" #include "script/script.h" +#include "script/script_error.h" #include "script/sign.h" #include "util.h" @@ -92,7 +93,9 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) { - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0)) == expect, message); + ScriptError err; + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0), &err) == expect, message); + BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); } void static NegateSignatureS(std::vector<unsigned char>& vchSig) { @@ -590,20 +593,25 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a }; static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; + ScriptError err; vector<vector<unsigned char> > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker())); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker(), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector<vector<unsigned char> > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker())); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector<vector<unsigned char> > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker())); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector<vector<unsigned char> > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker())); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript @@ -640,6 +648,7 @@ sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { + ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); @@ -652,19 +661,24 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { + ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); @@ -680,46 +694,55 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector<CKey> keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err)); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) @@ -833,11 +856,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_AUTO_TEST_CASE(script_standard_push) { + ScriptError err; for (int i=0; i<67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); - BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Number " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) { @@ -845,7 +870,8 @@ BOOST_AUTO_TEST_CASE(script_standard_push) CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); - BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Length " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d4c9b1a0ea..bf3a60c04f 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -10,6 +10,7 @@ #include "keystore.h" #include "main.h" #include "script/script.h" +#include "script/script_error.h" #include "core_io.h" #include <map> @@ -86,6 +87,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); + ScriptError err; BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); @@ -142,8 +144,9 @@ BOOST_AUTO_TEST_CASE(tx_valid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, SignatureChecker(tx, i)), + verify_flags, SignatureChecker(tx, i), &err), strTest); + BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } } @@ -160,6 +163,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); + ScriptError err; BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); @@ -215,10 +219,10 @@ BOOST_AUTO_TEST_CASE(tx_invalid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, SignatureChecker(tx, i)); + verify_flags, SignatureChecker(tx, i), &err); } - BOOST_CHECK_MESSAGE(!fValid, strTest); + BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err)); } } } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b5070d5104..e13f1cc350 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "txmempool.h" @@ -45,9 +45,9 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const return dResult; } -// -// Keep track of fee/priority for transactions confirmed within N blocks -// +/** + * Keep track of fee/priority for transactions confirmed within N blocks + */ class CBlockAverage { private: @@ -86,8 +86,10 @@ public: return prioritySamples.size(); } - // Used as belt-and-suspenders check when reading to detect - // file corruption + /** + * Used as belt-and-suspenders check when reading to detect + * file corruption + */ bool AreSane(const std::vector<CFeeRate>& vecFee, const CFeeRate& minRelayFee) { BOOST_FOREACH(CFeeRate fee, vecFee) @@ -139,16 +141,20 @@ public: class CMinerPolicyEstimator { private: - // Records observed averages transactions that confirmed within one block, two blocks, - // three blocks etc. + /** + * Records observed averages transactions that confirmed within one block, two blocks, + * three blocks etc. + */ std::vector<CBlockAverage> history; std::vector<CFeeRate> sortedFeeSamples; std::vector<double> sortedPrioritySamples; int nBestSeenHeight; - // nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are - // nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc. + /** + * nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are + * nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc. + */ void seenTxConfirm(const CFeeRate& feeRate, const CFeeRate& minRelayFee, double dPriority, int nBlocksAgo) { // Last entry records "everything else". @@ -248,7 +254,9 @@ public: } } - // Can return CFeeRate(0) if we don't have any data for that many blocks back. nBlocksToConfirm is 1 based. + /** + * Can return CFeeRate(0) if we don't have any data for that many blocks back. nBlocksToConfirm is 1 based. + */ CFeeRate estimateFee(int nBlocksToConfirm) { nBlocksToConfirm--; @@ -332,7 +340,7 @@ public: size_t numEntries; filein >> numEntries; if (numEntries <= 0 || numEntries > 10000) - throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entires."); + throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entries."); std::vector<CBlockAverage> fileHistory; @@ -462,7 +470,9 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction> } } -// Called when a block is connected. Removes from mempool and updates the miner fee estimator. +/** + * Called when a block is connected. Removes from mempool and updates the miner fee estimator. + */ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, std::list<CTransaction>& conflicts) { diff --git a/src/txmempool.h b/src/txmempool.h index 2ec80cb860..0d3c8bba6a 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_TXMEMPOOL_H @@ -25,19 +25,19 @@ inline bool AllowFree(double dPriority) /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; -/* +/** * CTxMemPool stores these: */ class CTxMemPoolEntry { private: CTransaction tx; - CAmount nFee; // Cached to avoid expensive parent-transaction lookups - size_t nTxSize; // ... and avoid recomputing tx size - size_t nModSize; // ... and modified size for priority - int64_t nTime; // Local time when entering the mempool - double dPriority; // Priority when entering the mempool - unsigned int nHeight; // Chain height when entering the mempool + CAmount nFee; //! Cached to avoid expensive parent-transaction lookups + size_t nTxSize; //! ... and avoid recomputing tx size + size_t nModSize; //! ... and modified size for priority + int64_t nTime; //! Local time when entering the mempool + double dPriority; //! Priority when entering the mempool + unsigned int nHeight; //! Chain height when entering the mempool public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, @@ -68,7 +68,7 @@ public: bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } }; -/* +/** * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. * @@ -81,12 +81,12 @@ public: class CTxMemPool { private: - bool fSanityCheck; // Normally false, true if -checkmempool or -regtest + bool fSanityCheck; //! Normally false, true if -checkmempool or -regtest unsigned int nTransactionsUpdated; CMinerPolicyEstimator* minerPolicyEstimator; - CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main - uint64_t totalTxSize; // sum of all mempool tx' byte sizes + CFeeRate minRelayFee; //! Passed to constructor to avoid dependency on main + uint64_t totalTxSize; //! sum of all mempool tx' byte sizes public: mutable CCriticalSection cs; @@ -97,7 +97,7 @@ public: CTxMemPool(const CFeeRate& _minRelayFee); ~CTxMemPool(); - /* + /** * If sanity-checking is turned on, check makes sure the pool is * consistent (does not contain two transactions that spend the same inputs, * all inputs are in the mapNextTx array). If sanity-checking is turned off, @@ -141,19 +141,21 @@ public: bool lookup(uint256 hash, CTransaction& result) const; - // Estimate fee rate needed to get into the next - // nBlocks + /** Estimate fee rate needed to get into the next nBlocks */ CFeeRate estimateFee(int nBlocks) const; - // Estimate priority needed to get into the next - // nBlocks + + /** Estimate priority needed to get into the next nBlocks */ double estimatePriority(int nBlocks) const; - // Write/Read estimates to disk + + /** Write/Read estimates to disk */ bool WriteFeeEstimates(CAutoFile& fileout) const; bool ReadFeeEstimates(CAutoFile& filein); }; -/** CCoinsView that brings transactions from a memorypool into view. - It does not check for spendings by memory pool transactions. */ +/** + * CCoinsView that brings transactions from a memorypool into view. + * It does not check for spendings by memory pool transactions. + */ class CCoinsViewMemPool : public CCoinsViewBacked { protected: diff --git a/src/util.cpp b/src/util.cpp index 0f5c036352..0cdf4e614d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) @@ -105,7 +105,7 @@ bool fLogTimestamps = false; bool fLogIPs = false; volatile bool fReopenDebugLog = false; -// Init OpenSSL library multithreading support +/** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) { @@ -149,18 +149,22 @@ public: } instance_of_cinit; -// LogPrintf() has been broken a couple of times now -// by well-meaning people adding mutexes in the most straightforward way. -// It breaks because it may be called by global destructors during shutdown. -// Since the order of destruction of static/global objects is undefined, -// defining a mutex as a global object doesn't work (the mutex gets -// destroyed, and then some later destructor calls OutputDebugStringF, -// maybe indirectly, and you get a core dump at shutdown trying to lock -// the mutex). +/** + * LogPrintf() has been broken a couple of times now + * by well-meaning people adding mutexes in the most straightforward way. + * It breaks because it may be called by global destructors during shutdown. + * Since the order of destruction of static/global objects is undefined, + * defining a mutex as a global object doesn't work (the mutex gets + * destroyed, and then some later destructor calls OutputDebugStringF, + * maybe indirectly, and you get a core dump at shutdown trying to lock + * the mutex). + */ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; -// We use boost::call_once() to make sure these are initialized -// in a thread-safe manner the first time called: +/** + * We use boost::call_once() to make sure these are initialized + * in a thread-safe manner the first time called: + */ static FILE* fileout = NULL; static boost::mutex* mutexDebugLog = NULL; @@ -500,9 +504,11 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) #endif /* WIN32 */ } -// Ignores exceptions thrown by Boost's create_directory if the requested directory exists. -// Specifically handles case where path p exists, but it wasn't possible for the user to -// write to the parent directory. +/** + * Ignores exceptions thrown by Boost's create_directory if the requested directory exists. + * Specifically handles case where path p exists, but it wasn't possible for the user to + * write to the parent directory. + */ bool TryCreateDirectory(const boost::filesystem::path& p) { try @@ -542,8 +548,10 @@ bool TruncateFile(FILE *file, unsigned int length) { #endif } -// this function tries to raise the file descriptor limit to the requested number. -// It returns the actual file descriptor limit (which may be more or less than nMinFD) +/** + * this function tries to raise the file descriptor limit to the requested number. + * It returns the actual file descriptor limit (which may be more or less than nMinFD) + */ int RaiseFileDescriptorLimit(int nMinFD) { #if defined(WIN32) return 2048; @@ -563,8 +571,10 @@ int RaiseFileDescriptorLimit(int nMinFD) { #endif } -// this function tries to make a particular range of a file allocated (corresponding to disk space) -// it is advisory, and the range specified in the arguments will never contain live data +/** + * this function tries to make a particular range of a file allocated (corresponding to disk space) + * it is advisory, and the range specified in the arguments will never contain live data + */ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { #if defined(WIN32) // Windows-specific version diff --git a/src/util.h b/src/util.h index 4b2415278b..a4aaf29f91 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** @@ -40,25 +40,26 @@ extern volatile bool fReopenDebugLog; void SetupEnvironment(); -/* Return true if log accepts specified category */ +/** Return true if log accepts specified category */ bool LogAcceptCategory(const char* category); -/* Send a string to the log output */ +/** Send a string to the log output */ int LogPrintStr(const std::string &str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) -/* When we switch to C++11, this can be switched to variadic templates instead +/** + * When we switch to C++11, this can be switched to variadic templates instead * of this macro-based construction (see tinyformat.h). */ #define MAKE_ERROR_AND_LOG_FUNC(n) \ - /* Print to debug.log if -debug=category switch is given OR category is NULL. */ \ + /** Print to debug.log if -debug=category switch is given OR category is NULL. */ \ template<TINYFORMAT_ARGTYPES(n)> \ static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ { \ if(!LogAcceptCategory(category)) return 0; \ return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ } \ - /* Log error and return false */ \ + /** Log error and return false */ \ template<TINYFORMAT_ARGTYPES(n)> \ static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ { \ @@ -68,7 +69,8 @@ int LogPrintStr(const std::string &str); TINYFORMAT_FOREACH_ARGNUM(MAKE_ERROR_AND_LOG_FUNC) -/* Zero-arg versions of logging and error, these are not covered by +/** + * Zero-arg versions of logging and error, these are not covered by * TINYFORMAT_FOREACH_ARGNUM */ static inline int LogPrint(const char* category, const char* format) @@ -162,13 +164,15 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue); void SetThreadPriority(int nPriority); void RenameThread(const char* name); -// Standard wrapper for do-something-forever thread functions. -// "Forever" really means until the thread is interrupted. -// Use it like: -// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000)); -// or maybe: -// boost::function<void()> f = boost::bind(&FunctionWithArg, argument); -// threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds)); +/** + * Standard wrapper for do-something-forever thread functions. + * "Forever" really means until the thread is interrupted. + * Use it like: + * new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000)); + * or maybe: + * boost::function<void()> f = boost::bind(&FunctionWithArg, argument); + * threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds)); + */ template <typename Callable> void LoopForever(const char* name, Callable func, int64_t msecs) { std::string s = strprintf("bitcoin-%s", name); @@ -196,7 +200,10 @@ template <typename Callable> void LoopForever(const char* name, Callable func, throw; } } -// .. and a wrapper that just calls func once + +/** + * .. and a wrapper that just calls func once + */ template <typename Callable> void TraceThread(const char* name, Callable func) { std::string s = strprintf("bitcoin-%s", name); diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index 267a5b845c..085adae85e 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilmoneystr.h" diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h index 65415afd3f..6a153db5fa 100644 --- a/src/utilmoneystr.h +++ b/src/utilmoneystr.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 15094e5999..a961b3c5cd 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilstrencodings.h" @@ -14,8 +14,10 @@ using namespace std; -// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything -// even possibly remotely dangerous like & or > +/** + * safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything + * even possibly remotely dangerous like & or > + */ static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@()"); string SanitizeString(const string& str) { diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 0b8c1a1781..0c0171b894 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** @@ -19,7 +19,7 @@ #define UEND(a) ((unsigned char*)&((&(a))[1])) #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) -// This is needed because the foreach macro can't get over the comma in pair<t1, t2> +/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */ #define PAIRTYPE(t1, t2) std::pair<t1, t2> std::string SanitizeString(const std::string& str); @@ -45,7 +45,7 @@ int atoi(const std::string& str); /** * Convert string to signed 32-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, - * false if not the entire string could be parsed or when overflow or underflow occured. + * false if not the entire string could be parsed or when overflow or underflow occurred. */ bool ParseInt32(const std::string& str, int32_t *out); @@ -74,7 +74,8 @@ inline std::string HexStr(const T& vch, bool fSpaces=false) return HexStr(vch.begin(), vch.end(), fSpaces); } -/** Format a paragraph of text to a fixed width, adding spaces for +/** + * Format a paragraph of text to a fixed width, adding spaces for * indentation to any added line. */ std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0); diff --git a/src/utiltime.cpp b/src/utiltime.cpp index 78f0342cba..9c137e8aa0 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) @@ -14,7 +14,7 @@ using namespace std; -static int64_t nMockTime = 0; // For unit testing +static int64_t nMockTime = 0; //! For unit testing int64_t GetTime() { @@ -42,9 +42,12 @@ int64_t GetTimeMicros() void MilliSleep(int64_t n) { -// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 -// until fixed in 1.52. Use the deprecated sleep method for the broken case. -// See: https://svn.boost.org/trac/boost/ticket/7238 + +/** + * Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 + * until fixed in 1.52. Use the deprecated sleep method for the broken case. + * See: https://svn.boost.org/trac/boost/ticket/7238 + */ #if defined(HAVE_WORKING_BOOST_SLEEP_FOR) boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); #elif defined(HAVE_WORKING_BOOST_SLEEP) diff --git a/src/utiltime.h b/src/utiltime.h index 6f82e5a836..9d7d42fe47 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTILTIME_H |