aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--contrib/bitcoind.bash-completion10
-rw-r--r--doc/README_osx.txt8
-rw-r--r--doc/build-osx.md7
-rwxr-xr-xqa/pull-tester/rpc-tests.sh5
-rwxr-xr-xqa/rpc-tests/test_framework.py8
-rw-r--r--qa/rpc-tests/util.py41
-rw-r--r--src/Makefile.am3
-rw-r--r--src/qt/bitcoinamountfield.cpp1
-rw-r--r--src/qt/forms/coincontroldialog.ui12
-rw-r--r--src/qt/macnotificationhandler.mm24
-rw-r--r--src/rest.cpp206
-rw-r--r--src/rpcclient.cpp1
-rw-r--r--src/rpcmining.cpp30
-rw-r--r--src/rpcmisc.cpp20
-rw-r--r--src/rpcserver.cpp8
-rw-r--r--src/rpcserver.h7
-rw-r--r--src/rpcwallet.cpp4
-rw-r--r--src/script/interpreter.cpp297
-rw-r--r--src/script/interpreter.h6
-rw-r--r--src/script/script_error.cpp67
-rw-r--r--src/script/script_error.h53
-rw-r--r--src/test/multisig_tests.cpp37
-rw-r--r--src/test/script_P2SH_tests.cpp19
-rw-r--r--src/test/script_tests.cpp66
-rw-r--r--src/test/transaction_tests.cpp10
-rw-r--r--src/txmempool.cpp38
-rw-r--r--src/txmempool.h44
-rw-r--r--src/util.cpp48
-rw-r--r--src/util.h37
-rw-r--r--src/utilmoneystr.cpp2
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/utilstrencodings.cpp8
-rw-r--r--src/utilstrencodings.h9
-rw-r--r--src/utiltime.cpp13
-rw-r--r--src/utiltime.h2
36 files changed, 861 insertions, 294 deletions
diff --git a/.travis.yml b/.travis.yml
index f6b011ee1c..567428daf9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -40,7 +40,7 @@ matrix:
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-upgrade -qq $PACKAGES; fi
+ - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi
before_script:
- unset CC; unset CXX
- mkdir -p depends/SDKs depends/sdk-sources
diff --git a/contrib/bitcoind.bash-completion b/contrib/bitcoind.bash-completion
index 03ef173c09..37ece25899 100644
--- a/contrib/bitcoind.bash-completion
+++ b/contrib/bitcoind.bash-completion
@@ -39,6 +39,10 @@ _bitcoind() {
if ((cword > 4)); then
case ${words[cword-4]} in
+ listtransactions)
+ COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
+ return 0
+ ;;
signrawtransaction)
COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) )
return 0
@@ -52,7 +56,7 @@ _bitcoind() {
_bitcoin_accounts
return 0
;;
- gettxout|importprivkey)
+ getbalance|gettxout|importaddress|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
@@ -65,7 +69,7 @@ _bitcoind() {
COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) )
return 0
;;
- getblock|getrawtransaction|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction)
+ getblock|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
@@ -115,7 +119,7 @@ _bitcoind() {
# only parse help if senseful
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
- commands=$(_bitcoin_rpc help 2>/dev/null | awk '{ print $1; }')
+ commands=$(_bitcoin_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }')
fi
COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) )
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 f07c58fd17..c41820f2b1 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`.
@@ -112,9 +111,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 a0056c141b..0b5ad20642 100755
--- a/qa/pull-tester/rpc-tests.sh
+++ b/qa/pull-tester/rpc-tests.sh
@@ -8,6 +8,11 @@ CURDIR=$(cd $(dirname "$0"); pwd)
export BITCOINCLI=${BUILDDIR}/qa/pull-tester/run-bitcoin-cli
export BITCOIND=${REAL_BITCOIND}
+if [ "x${EXEEXT}" = "x.exe" ]; then
+ echo "Win tests currently disabled"
+ exit 0
+fi
+
#Run the tests
if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
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..c6d918a81c 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:
@@ -103,12 +103,17 @@ def initialize_chain(test_dir):
# Create a 200-block-long chain; each of the 4 nodes
# gets 25 mature blocks and 25 immature.
- for i in range(4):
- rpcs[i].setgenerate(True, 25)
- sync_blocks(rpcs)
- for i in range(4):
- rpcs[i].setgenerate(True, 25)
- sync_blocks(rpcs)
+ # blocks are created with timestamps 10 minutes apart, starting
+ # at 1 Jan 2014
+ block_time = 1388534400
+ for i in range(2):
+ for peer in range(4):
+ for j in range(25):
+ set_node_times(rpcs, block_time)
+ rpcs[peer].setgenerate(True, 1)
+ block_time += 10*60
+ # Must sync before next peer starts generating blocks
+ sync_blocks(rpcs)
# Shut them down, and clean up cache directories:
stop_nodes(rpcs)
@@ -145,11 +150,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 +168,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()
@@ -179,10 +184,14 @@ def stop_node(node, i):
del bitcoind_processes[i]
def stop_nodes(nodes):
- for i in range(len(nodes)):
- nodes[i].stop()
+ for node in nodes:
+ node.stop()
del nodes[:] # Emptying array closes connections as a side effect
+def set_node_times(nodes, t):
+ for node in nodes:
+ node.setmocktime(t)
+
def wait_bitcoinds():
# Wait for all bitcoinds to cleanly exit
for bitcoind in bitcoind_processes.values():
diff --git a/src/Makefile.am b/src/Makefile.am
index 8b5d009842..3da833d733 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 \
@@ -165,6 +166,7 @@ libbitcoin_server_a_SOURCES = \
net.cpp \
noui.cpp \
pow.cpp \
+ rest.cpp \
rpcblockchain.cpp \
rpcmining.cpp \
rpcmisc.cpp \
@@ -235,6 +237,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/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/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index cbe58fec65..c1fef6b9b1 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Coin Control Address Selection</string>
+ <string>Coin Selection</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
@@ -379,9 +379,6 @@
<property name="text">
<string>Tree mode</string>
</property>
- <property name="checked">
- <bool>true</bool>
- </property>
</widget>
</item>
<item>
@@ -395,6 +392,9 @@
<property name="text">
<string>List mode</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
@@ -451,12 +451,12 @@
</column>
<column>
<property name="text">
- <string notr="true">Label</string>
+ <string>Received with label</string>
</property>
</column>
<column>
<property name="text">
- <string>Address</string>
+ <string>Received with address</string>
</property>
</column>
<column>
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
index 8a4c94cc5c..aa50a0d9fb 100644
--- a/src/qt/macnotificationhandler.mm
+++ b/src/qt/macnotificationhandler.mm
@@ -5,8 +5,21 @@
#include "macnotificationhandler.h"
#undef slots
+#import <objc/runtime.h>
#include <Cocoa/Cocoa.h>
+// Add an obj-c category (extension) to return the expected bundle identifier
+@implementation NSBundle(returnCorrectIdentifier)
+- (NSString *)__bundleIdentifier
+{
+ if (self == [NSBundle mainBundle]) {
+ return @"org.bitcoinfoundation.Bitcoin-Qt";
+ } else {
+ return [self __bundleIdentifier];
+ }
+}
+@end
+
void MacNotificationHandler::showNotification(const QString &title, const QString &text)
{
// check if users OS has support for NSUserNotification
@@ -63,7 +76,16 @@ bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
MacNotificationHandler *MacNotificationHandler::instance()
{
static MacNotificationHandler *s_instance = NULL;
- if (!s_instance)
+ if (!s_instance) {
s_instance = new MacNotificationHandler();
+
+ Class aPossibleClass = objc_getClass("NSBundle");
+ if (aPossibleClass) {
+ // change NSBundle -bundleIdentifier method to return a correct bundle identifier
+ // a bundle identifier is required to use OSXs User Notification Center
+ method_exchangeImplementations(class_getInstanceMethod(aPossibleClass, @selector(bundleIdentifier)),
+ class_getInstanceMethod(aPossibleClass, @selector(__bundleIdentifier)));
+ }
+ }
return s_instance;
}
diff --git a/src/rest.cpp b/src/rest.cpp
new file mode 100644
index 0000000000..9a8793a517
--- /dev/null
+++ b/src/rest.cpp
@@ -0,0 +1,206 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <boost/algorithm/string.hpp>
+#include "rpcserver.h"
+#include "streams.h"
+#include "utilstrencodings.h"
+#include "core/block.h"
+#include "core/transaction.h"
+#include "version.h"
+#include "main.h"
+#include "sync.h"
+
+using namespace std;
+using namespace json_spirit;
+
+enum RetFormat {
+ RF_BINARY,
+ RF_HEX,
+ RF_JSON,
+};
+
+static const struct {
+ enum RetFormat rf;
+ const char *name;
+} rf_names[] = {
+ { RF_BINARY, "binary" }, // default, if match not found
+ { RF_HEX, "hex" },
+ { RF_JSON, "json" },
+};
+
+class RestErr {
+public:
+ enum HTTPStatusCode status;
+ string message;
+};
+
+extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
+extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex);
+
+static RestErr RESTERR(enum HTTPStatusCode status, string message)
+{
+ RestErr re;
+ re.status = status;
+ re.message = message;
+ return re;
+}
+
+static enum RetFormat ParseDataFormat(const string& format)
+{
+ for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
+ if (format == rf_names[i].name)
+ return rf_names[i].rf;
+
+ return rf_names[0].rf;
+}
+
+static bool ParseHashStr(const string& strReq, uint256& v)
+{
+ if (!IsHex(strReq) || (strReq.size() != 64))
+ return false;
+
+ v.SetHex(strReq);
+ return true;
+}
+
+static bool rest_block(AcceptedConnection *conn,
+ string& strReq,
+ map<string, string>& mapHeaders,
+ bool fRun)
+{
+ vector<string> params;
+ boost::split(params, strReq, boost::is_any_of("/"));
+
+ enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
+
+ string hashStr = params[0];
+ uint256 hash;
+ if (!ParseHashStr(hashStr, hash))
+ throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
+
+ CBlock block;
+ CBlockIndex* pblockindex = NULL;
+ {
+ LOCK(cs_main);
+ if (mapBlockIndex.count(hash) == 0)
+ throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+
+ pblockindex = mapBlockIndex[hash];
+ if (!ReadBlockFromDisk(block, pblockindex))
+ throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+ }
+
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ ssBlock << block;
+
+ switch (rf) {
+ case RF_BINARY: {
+ string binaryBlock = ssBlock.str();
+ conn->stream() << HTTPReply(HTTP_OK, binaryBlock, fRun, true, "application/octet-stream") << binaryBlock << std::flush;
+ return true;
+ }
+
+ case RF_HEX: {
+ string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";;
+ conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ return true;
+ }
+
+ case RF_JSON: {
+ Object objBlock = blockToJSON(block, pblockindex);
+ string strJSON = write_string(Value(objBlock), false) + "\n";
+ conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ return true;
+ }
+ }
+
+ // not reached
+ return true; // continue to process further HTTP reqs on this cxn
+}
+
+static bool rest_tx(AcceptedConnection *conn,
+ string& strReq,
+ map<string, string>& mapHeaders,
+ bool fRun)
+{
+ vector<string> params;
+ boost::split(params, strReq, boost::is_any_of("/"));
+
+ enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
+
+ string hashStr = params[0];
+ uint256 hash;
+ if (!ParseHashStr(hashStr, hash))
+ throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
+
+ CTransaction tx;
+ uint256 hashBlock = 0;
+ if (!GetTransaction(hash, tx, hashBlock, true))
+ throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << tx;
+
+ switch (rf) {
+ case RF_BINARY: {
+ string binaryTx = ssTx.str();
+ conn->stream() << HTTPReply(HTTP_OK, binaryTx, fRun, true, "application/octet-stream") << binaryTx << std::flush;
+ return true;
+ }
+
+ case RF_HEX: {
+ string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";;
+ conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ return true;
+ }
+
+ case RF_JSON: {
+ Object objTx;
+ TxToJSON(tx, hashBlock, objTx);
+ string strJSON = write_string(Value(objTx), false) + "\n";
+ conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ return true;
+ }
+ }
+
+ // not reached
+ return true; // continue to process further HTTP reqs on this cxn
+}
+
+static const struct {
+ const char *prefix;
+ bool (*handler)(AcceptedConnection *conn,
+ string& strURI,
+ map<string, string>& mapHeaders,
+ bool fRun);
+} uri_prefixes[] = {
+ { "/rest/tx/", rest_tx },
+ { "/rest/block/", rest_block },
+};
+
+bool HTTPReq_REST(AcceptedConnection *conn,
+ string& strURI,
+ map<string, string>& mapHeaders,
+ bool fRun)
+{
+ try {
+ for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++) {
+ unsigned int plen = strlen(uri_prefixes[i].prefix);
+ if (strURI.substr(0, plen) == uri_prefixes[i].prefix) {
+ string strReq = strURI.substr(plen);
+ return uri_prefixes[i].handler(conn, strReq, mapHeaders, fRun);
+ }
+ }
+ }
+ catch (RestErr& re) {
+ conn->stream() << HTTPReply(re.status, re.message + "\r\n", false, false, "text/plain") << std::flush;
+ return false;
+ }
+
+ conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
+ return false;
+}
+
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index a9c491cede..7a1f1918f6 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -25,6 +25,7 @@ public:
static const CRPCConvertParam vRPCConvertParams[] =
{
{ "stop", 0 },
+ { "setmocktime", 0 },
{ "getaddednodeinfo", 0 },
{ "setgenerate", 0 },
{ "setgenerate", 1 },
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/rpcmisc.cpp b/src/rpcmisc.cpp
index 08e956c961..31eaae6162 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -354,3 +354,23 @@ Value verifymessage(const Array& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
+
+Value setmocktime(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "setmocktime timestamp\n"
+ "\nSet the local time to given timestamp (-regtest only)\n"
+ "\nArguments:\n"
+ "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n"
+ " Pass 0 to go back to using the system time."
+ );
+
+ if (!Params().MineBlocksOnDemand())
+ throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+
+ RPCTypeCheck(params, boost::assign::list_of(int_type));
+ SetMockTime(params[0].get_int64());
+
+ return Value::null;
+}
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index cc80887ba4..01005c1cee 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -246,6 +246,7 @@ static const CRPCCommand vRPCCommands[] =
{ "control", "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
{ "control", "help", &help, true, true, false },
{ "control", "stop", &stop, true, true, false },
+ { "control", "setmocktime", &setmocktime, true, false, false },
/* P2P networking */
{ "network", "getnetworkinfo", &getnetworkinfo, true, false, false },
@@ -946,9 +947,16 @@ void ServiceConnection(AcceptedConnection *conn)
if (mapHeaders["connection"] == "close")
fRun = false;
+ // Process via JSON-RPC API
if (strURI == "/") {
if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
break;
+
+ // Process via HTTP REST API
+ } else if (strURI.substr(0, 6) == "/rest/") {
+ if (!HTTPReq_REST(conn, strURI, mapHeaders, fRun))
+ break;
+
} else {
conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
break;
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 2a258dd89a..b3234f65f2 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -194,6 +194,7 @@ extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
@@ -218,4 +219,10 @@ extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp)
extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
+// in rest.cpp
+extern bool HTTPReq_REST(AcceptedConnection *conn,
+ std::string& strURI,
+ std::map<std::string, std::string>& mapHeaders,
+ bool fRun);
+
#endif // BITCOIN_RPCSERVER_H
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 5fda6248c2..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++)
@@ -55,16 +72,23 @@ 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;
}
@@ -79,47 +103,74 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
*/
bool static IsDERSignature(const valtype &vchSig) {
- 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];
@@ -128,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;
}
@@ -139,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;
}
@@ -185,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();
@@ -194,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;
@@ -209,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 ||
@@ -232,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))
@@ -288,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)
@@ -302,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;
@@ -310,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;
@@ -320,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;
@@ -342,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);
}
@@ -351,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);
}
@@ -361,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);
}
@@ -371,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);
@@ -383,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);
@@ -397,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);
@@ -409,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);
@@ -422,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));
}
@@ -432,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);
@@ -451,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;
@@ -460,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);
}
@@ -470,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;
@@ -479,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);
}
@@ -491,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);
@@ -509,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));
}
@@ -519,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;
@@ -528,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);
}
@@ -539,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());
}
@@ -555,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);
@@ -572,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;
@@ -590,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)
{
@@ -623,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);
@@ -659,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;
@@ -668,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);
@@ -692,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)
@@ -722,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);
@@ -733,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);
@@ -747,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;
@@ -759,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);
@@ -796,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;
}
@@ -827,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);
@@ -839,29 +893,29 @@ 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 {
@@ -966,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;
}
}
@@ -1013,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
@@ -1047,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_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/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