aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.test.include9
-rw-r--r--src/alert.cpp266
-rw-r--r--src/alert.h113
-rw-r--r--src/amount.cpp6
-rw-r--r--src/amount.h12
-rw-r--r--src/base58.cpp11
-rw-r--r--src/bitcoin-cli.cpp21
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparams.cpp34
-rw-r--r--src/chainparams.h3
-rw-r--r--src/coincontrol.h5
-rw-r--r--src/consensus/consensus.h5
-rw-r--r--src/consensus/params.h30
-rw-r--r--src/httprpc.cpp7
-rw-r--r--src/init.cpp222
-rw-r--r--src/main.cpp577
-rw-r--r--src/main.h49
-rw-r--r--src/merkleblock.cpp14
-rw-r--r--src/merkleblock.h9
-rw-r--r--src/miner.cpp218
-rw-r--r--src/miner.h5
-rw-r--r--src/net.cpp36
-rw-r--r--src/net.h13
-rw-r--r--src/policy/fees.cpp19
-rw-r--r--src/policy/fees.h13
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/policy/policy.h6
-rw-r--r--src/primitives/block.cpp2
-rw-r--r--src/primitives/block.h3
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/primitives/transaction.h48
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h14
-rw-r--r--src/qt/clientmodel.cpp37
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/forms/debugwindow.ui103
-rw-r--r--src/qt/forms/sendcoinsdialog.ui55
-rw-r--r--src/qt/res/icons/about.pngbin4726 -> 3717 bytes
-rw-r--r--src/qt/res/icons/chevron.pngbin1923 -> 803 bytes
-rw-r--r--src/qt/rpcconsole.cpp35
-rw-r--r--src/qt/rpcconsole.h4
-rw-r--r--src/qt/sendcoinsdialog.cpp8
-rw-r--r--src/qt/transactiondesc.cpp3
-rw-r--r--src/qt/transactionrecord.cpp7
-rw-r--r--src/qt/transactionrecord.h4
-rw-r--r--src/qt/transactiontablemodel.cpp28
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp16
-rw-r--r--src/qt/transactionview.h1
-rw-r--r--src/rest.cpp3
-rw-r--r--src/rpc/blockchain.cpp53
-rw-r--r--src/rpc/client.cpp7
-rw-r--r--src/rpc/mining.cpp185
-rw-r--r--src/rpc/misc.cpp18
-rw-r--r--src/rpc/net.cpp22
-rw-r--r--src/rpc/rawtransaction.cpp28
-rw-r--r--src/rpc/register.h32
-rw-r--r--src/rpc/server.cpp76
-rw-r--r--src/rpc/server.h66
-rw-r--r--src/script/interpreter.cpp91
-rw-r--r--src/script/interpreter.h11
-rw-r--r--src/script/script.h12
-rw-r--r--src/script/script_error.h2
-rw-r--r--src/test/alert_tests.cpp183
-rw-r--r--src/test/amount_tests.cpp42
-rw-r--r--src/test/bctest.py2
-rwxr-xr-xsrc/test/bitcoin-util-test.py2
-rw-r--r--src/test/bloom_tests.cpp23
-rw-r--r--src/test/checkblock_tests.cpp66
-rw-r--r--src/test/data/alertTests.rawbin1279 -> 0 bytes
-rw-r--r--src/test/data/script_invalid.json1055
-rw-r--r--src/test/data/tx_invalid.json54
-rw-r--r--src/test/data/tx_valid.json84
-rw-r--r--src/test/mempool_tests.cpp146
-rw-r--r--src/test/miner_tests.cpp159
-rw-r--r--src/test/pmt_tests.cpp8
-rw-r--r--src/test/rpc_tests.cpp2
-rw-r--r--src/test/script_tests.cpp187
-rw-r--r--src/test/test_bitcoin.cpp12
-rw-r--r--src/test/test_bitcoin.h4
-rw-r--r--src/test/testutil.cpp33
-rw-r--r--src/test/testutil.h15
-rw-r--r--src/test/transaction_tests.cpp3
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/test/util_tests.cpp9
-rw-r--r--src/test/versionbits_tests.cpp316
-rw-r--r--src/timedata.cpp2
-rw-r--r--src/timedata.h2
-rw-r--r--src/torcontrol.cpp23
-rw-r--r--src/txmempool.cpp222
-rw-r--r--src/txmempool.h137
-rw-r--r--src/ui_interface.h5
-rw-r--r--src/uint256.h8
-rw-r--r--src/util.cpp22
-rw-r--r--src/util.h1
-rw-r--r--src/version.h9
-rw-r--r--src/versionbits.cpp133
-rw-r--r--src/versionbits.h59
-rw-r--r--src/wallet/db.cpp28
-rw-r--r--src/wallet/rpcdump.cpp107
-rw-r--r--src/wallet/rpcwallet.cpp39
-rw-r--r--src/wallet/rpcwallet.h4
-rw-r--r--src/wallet/wallet.cpp296
-rw-r--r--src/wallet/wallet.h11
-rw-r--r--src/wallet/walletdb.cpp57
-rw-r--r--src/wallet/walletdb.h3
-rw-r--r--src/zmq/zmqnotificationinterface.cpp1
-rw-r--r--src/zmq/zmqpublishnotifier.cpp1
111 files changed, 3736 insertions, 2546 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c4f7188971..1e54512cbd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,7 +87,6 @@ endif
# bitcoin core #
BITCOIN_CORE_H = \
addrman.h \
- alert.h \
base58.h \
bloom.h \
chain.h \
@@ -131,6 +130,7 @@ BITCOIN_CORE_H = \
rpc/client.h \
rpc/protocol.h \
rpc/server.h \
+ rpc/register.h \
scheduler.h \
script/sigcache.h \
script/sign.h \
@@ -152,6 +152,7 @@ BITCOIN_CORE_H = \
utilmoneystr.h \
utiltime.h \
validationinterface.h \
+ versionbits.h \
wallet/crypter.h \
wallet/db.h \
wallet/rpcwallet.h \
@@ -175,7 +176,6 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
- alert.cpp \
bloom.cpp \
chain.cpp \
checkpoints.cpp \
@@ -204,6 +204,7 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
validationinterface.cpp \
+ versionbits.cpp \
$(BITCOIN_CORE_H)
if ENABLE_ZMQ
@@ -430,6 +431,7 @@ endif
#
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a
+CLEANFILES += $(EXTRA_LIBRARIES)
CLEANFILES += *.gcda *.gcno
CLEANFILES += compat/*.gcda compat/*.gcno
CLEANFILES += consensus/*.gcda consensus/*.gcno
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index ca4e1e70d0..357e4c47ff 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -391,7 +391,7 @@ SECONDARY: $(QT_QM)
qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
- $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" ../share/qt/extract_strings_qt.py $^
+ $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 468d3043a7..d806fb219e 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -29,7 +29,7 @@ JSON_TEST_FILES = \
test/data/tx_valid.json \
test/data/sighash.json
-RAW_TEST_FILES = test/data/alertTests.raw
+RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
@@ -38,13 +38,13 @@ BITCOIN_TESTS =\
test/scriptnum10.h \
test/addrman_tests.cpp \
test/alert_tests.cpp \
+ test/amount_tests.cpp \
test/allocator_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
test/bip32_tests.cpp \
test/bloom_tests.cpp \
- test/checkblock_tests.cpp \
test/Checkpoints_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
@@ -79,9 +79,12 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
+ test/testutil.cpp \
+ test/testutil.h \
test/timedata_tests.cpp \
test/transaction_tests.cpp \
test/txvalidationcache_tests.cpp \
+ test/versionbits_tests.cpp \
test/uint256_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp
@@ -127,7 +130,7 @@ bitcoin_test_clean : FORCE
check-local:
@echo "Running test/bitcoin-util-test.py..."
- $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py
+ $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if EMBEDDED_UNIVALUE
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
diff --git a/src/alert.cpp b/src/alert.cpp
deleted file mode 100644
index eb1cd5e7f6..0000000000
--- a/src/alert.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "alert.h"
-
-#include "clientversion.h"
-#include "net.h"
-#include "pubkey.h"
-#include "timedata.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <map>
-
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/replace.hpp>
-#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-
-using namespace std;
-
-map<uint256, CAlert> mapAlerts;
-CCriticalSection cs_mapAlerts;
-
-void CUnsignedAlert::SetNull()
-{
- nVersion = 1;
- nRelayUntil = 0;
- nExpiration = 0;
- nID = 0;
- nCancel = 0;
- setCancel.clear();
- nMinVer = 0;
- nMaxVer = 0;
- setSubVer.clear();
- nPriority = 0;
-
- strComment.clear();
- strStatusBar.clear();
- strReserved.clear();
-}
-
-std::string CUnsignedAlert::ToString() const
-{
- std::string strSetCancel;
- BOOST_FOREACH(int n, setCancel)
- strSetCancel += strprintf("%d ", n);
- std::string strSetSubVer;
- BOOST_FOREACH(const std::string& str, setSubVer)
- strSetSubVer += "\"" + str + "\" ";
- return strprintf(
- "CAlert(\n"
- " nVersion = %d\n"
- " nRelayUntil = %d\n"
- " nExpiration = %d\n"
- " nID = %d\n"
- " nCancel = %d\n"
- " setCancel = %s\n"
- " nMinVer = %d\n"
- " nMaxVer = %d\n"
- " setSubVer = %s\n"
- " nPriority = %d\n"
- " strComment = \"%s\"\n"
- " strStatusBar = \"%s\"\n"
- ")\n",
- nVersion,
- nRelayUntil,
- nExpiration,
- nID,
- nCancel,
- strSetCancel,
- nMinVer,
- nMaxVer,
- strSetSubVer,
- nPriority,
- strComment,
- strStatusBar);
-}
-
-void CAlert::SetNull()
-{
- CUnsignedAlert::SetNull();
- vchMsg.clear();
- vchSig.clear();
-}
-
-bool CAlert::IsNull() const
-{
- return (nExpiration == 0);
-}
-
-uint256 CAlert::GetHash() const
-{
- return Hash(this->vchMsg.begin(), this->vchMsg.end());
-}
-
-bool CAlert::IsInEffect() const
-{
- return (GetAdjustedTime() < nExpiration);
-}
-
-bool CAlert::Cancels(const CAlert& alert) const
-{
- if (!IsInEffect())
- return false; // this was a no-op before 31403
- return (alert.nID <= nCancel || setCancel.count(alert.nID));
-}
-
-bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
-{
- // TODO: rework for client-version-embedded-in-strSubVer ?
- return (IsInEffect() &&
- nMinVer <= nVersion && nVersion <= nMaxVer &&
- (setSubVer.empty() || setSubVer.count(strSubVerIn)));
-}
-
-bool CAlert::AppliesToMe() const
-{
- return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
-}
-
-bool CAlert::RelayTo(CNode* pnode) const
-{
- if (!IsInEffect())
- return false;
- // don't relay to nodes which haven't sent their version message
- if (pnode->nVersion == 0)
- return false;
- // returns true if wasn't already contained in the set
- if (pnode->setKnown.insert(GetHash()).second)
- {
- if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
- AppliesToMe() ||
- GetAdjustedTime() < nRelayUntil)
- {
- pnode->PushMessage(NetMsgType::ALERT, *this);
- return true;
- }
- }
- return false;
-}
-
-bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
-{
- CPubKey key(alertKey);
- if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
- return error("CAlert::CheckSignature(): verify signature failed");
-
- // Now unserialize the data
- CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
- sMsg >> *(CUnsignedAlert*)this;
- return true;
-}
-
-CAlert CAlert::getAlertByHash(const uint256 &hash)
-{
- CAlert retval;
- {
- LOCK(cs_mapAlerts);
- map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
- if(mi != mapAlerts.end())
- retval = mi->second;
- }
- return retval;
-}
-
-bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
-{
- if (!CheckSignature(alertKey))
- return false;
- if (!IsInEffect())
- return false;
-
- // alert.nID=max is reserved for if the alert key is
- // compromised. It must have a pre-defined message,
- // must never expire, must apply to all versions,
- // and must cancel all previous
- // alerts or it will be ignored (so an attacker can't
- // send an "everything is OK, don't panic" version that
- // cannot be overridden):
- int maxInt = std::numeric_limits<int>::max();
- if (nID == maxInt)
- {
- if (!(
- nExpiration == maxInt &&
- nCancel == (maxInt-1) &&
- nMinVer == 0 &&
- nMaxVer == maxInt &&
- setSubVer.empty() &&
- nPriority == maxInt &&
- strStatusBar == "URGENT: Alert key compromised, upgrade required"
- ))
- return false;
- }
-
- {
- LOCK(cs_mapAlerts);
- // Cancel previous alerts
- for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
- {
- const CAlert& alert = (*mi).second;
- if (Cancels(alert))
- {
- LogPrint("alert", "cancelling alert %d\n", alert.nID);
- uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
- mapAlerts.erase(mi++);
- }
- else if (!alert.IsInEffect())
- {
- LogPrint("alert", "expiring alert %d\n", alert.nID);
- uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
- mapAlerts.erase(mi++);
- }
- else
- mi++;
- }
-
- // Check if this alert has been cancelled
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- {
- const CAlert& alert = item.second;
- if (alert.Cancels(*this))
- {
- LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
- return false;
- }
- }
-
- // Add to mapAlerts
- mapAlerts.insert(make_pair(GetHash(), *this));
- // Notify UI and -alertnotify if it applies to me
- if(AppliesToMe())
- {
- uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
- Notify(strStatusBar, fThread);
- }
- }
-
- LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
- return true;
-}
-
-void
-CAlert::Notify(const std::string& strMessage, bool fThread)
-{
- std::string strCmd = GetArg("-alertnotify", "");
- if (strCmd.empty()) return;
-
- // Alert text should be plain ascii coming from a trusted source, but to
- // be safe we first strip anything not in safeChars, then add single quotes around
- // the whole string before passing it to the shell:
- std::string singleQuote("'");
- std::string safeStatus = SanitizeString(strMessage);
- safeStatus = singleQuote+safeStatus+singleQuote;
- boost::replace_all(strCmd, "%s", safeStatus);
-
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
-}
diff --git a/src/alert.h b/src/alert.h
deleted file mode 100644
index 8cb86e338c..0000000000
--- a/src/alert.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_ALERT_H
-#define BITCOIN_ALERT_H
-
-#include "serialize.h"
-#include "sync.h"
-
-#include <map>
-#include <set>
-#include <stdint.h>
-#include <string>
-
-class CAlert;
-class CNode;
-class uint256;
-
-extern std::map<uint256, CAlert> mapAlerts;
-extern CCriticalSection cs_mapAlerts;
-
-/** Alerts are for notifying old versions if they become too obsolete and
- * need to upgrade. The message is displayed in the status bar.
- * Alert messages are broadcast as a vector of signed data. Unserializing may
- * not read the entire buffer if the alert is for a newer version, but older
- * versions can still relay the original data.
- */
-class CUnsignedAlert
-{
-public:
- int nVersion;
- int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes
- int64_t nExpiration;
- int nID;
- int nCancel;
- std::set<int> setCancel;
- int nMinVer; // lowest version inclusive
- int nMaxVer; // highest version inclusive
- std::set<std::string> setSubVer; // empty matches all
- int nPriority;
-
- // Actions
- std::string strComment;
- std::string strStatusBar;
- std::string strReserved;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(nRelayUntil);
- READWRITE(nExpiration);
- READWRITE(nID);
- READWRITE(nCancel);
- READWRITE(setCancel);
- READWRITE(nMinVer);
- READWRITE(nMaxVer);
- READWRITE(setSubVer);
- READWRITE(nPriority);
-
- READWRITE(LIMITED_STRING(strComment, 65536));
- READWRITE(LIMITED_STRING(strStatusBar, 256));
- READWRITE(LIMITED_STRING(strReserved, 256));
- }
-
- void SetNull();
-
- std::string ToString() const;
-};
-
-/** An alert is a combination of a serialized CUnsignedAlert and a signature. */
-class CAlert : public CUnsignedAlert
-{
-public:
- std::vector<unsigned char> vchMsg;
- std::vector<unsigned char> vchSig;
-
- CAlert()
- {
- SetNull();
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(vchMsg);
- READWRITE(vchSig);
- }
-
- void SetNull();
- bool IsNull() const;
- uint256 GetHash() const;
- bool IsInEffect() const;
- bool Cancels(const CAlert& alert) const;
- bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;
- bool AppliesToMe() const;
- bool RelayTo(CNode* pnode) const;
- bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
- bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread
- static void Notify(const std::string& strMessage, bool fThread);
-
- /*
- * Get copy of (active) alert object by hash. Returns a null alert if it is not found.
- */
- static CAlert getAlertByHash(const uint256 &hash);
-};
-
-#endif // BITCOIN_ALERT_H
diff --git a/src/amount.cpp b/src/amount.cpp
index a3abd8cd83..68806ff062 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -19,10 +19,10 @@ CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
CAmount CFeeRate::GetFee(size_t nSize) const
{
- CAmount nFee = nSatoshisPerK*nSize / 1000;
+ CAmount nFee = nSatoshisPerK * nSize / 1000;
- if (nFee == 0 && nSatoshisPerK > 0)
- nFee = nSatoshisPerK;
+ if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0)
+ nFee = CAmount(1);
return nFee;
}
diff --git a/src/amount.h b/src/amount.h
index a48b17d514..9aba6525c7 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -42,10 +42,14 @@ public:
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
CFeeRate(const CAmount& nFeePaid, size_t nSize);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
-
- CAmount GetFee(size_t size) const; // unit returned is satoshis
- CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
-
+ /**
+ * Return the fee in satoshis for the given size in bytes.
+ */
+ CAmount GetFee(size_t size) const;
+ /**
+ * Return the fee in satoshis for a size of 1000 bytes
+ */
+ CAmount GetFeePerK() const { return GetFee(1000); }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
diff --git a/src/base58.cpp b/src/base58.cpp
index 5e26cf8d47..d81c26092c 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -68,26 +68,31 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
// Skip & count leading zeroes.
int zeroes = 0;
+ int length = 0;
while (pbegin != pend && *pbegin == 0) {
pbegin++;
zeroes++;
}
// Allocate enough space in big-endian base58 representation.
- std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
+ int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.
+ std::vector<unsigned char> b58(size);
// Process the bytes.
while (pbegin != pend) {
int carry = *pbegin;
+ int i = 0;
// Apply "b58 = b58 * 256 + ch".
- for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
+ for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
carry += 256 * (*it);
*it = carry % 58;
carry /= 58;
}
+
assert(carry == 0);
+ length = i;
pbegin++;
}
// Skip leading zeroes in base58 result.
- std::vector<unsigned char>::iterator it = b58.begin();
+ std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
while (it != b58.end() && *it == 0)
it++;
// Translate the result into a string.
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 34980d9ca1..49935699fd 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -43,6 +43,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
+ strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
return strUsage;
}
@@ -232,15 +233,17 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
-
- // Method
- if (argc < 2)
- throw runtime_error("too few parameters");
- string strMethod = argv[1];
-
- // Parameters default to strings
- std::vector<std::string> strParams(&argv[2], &argv[argc]);
- UniValue params = RPCConvertValues(strMethod, strParams);
+ std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
+ if (GetBoolArg("-stdin", false)) {
+ // Read one arg per line from stdin and append
+ std::string line;
+ while (std::getline(std::cin,line))
+ args.push_back(line);
+ }
+ if (args.size() < 1)
+ throw runtime_error("too few parameters (need at least command)");
+ std::string strMethod = args[0];
+ UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
// Execute and handle connection failures with -rpcwait
const bool fWait = GetBoolArg("-rpcwait", false);
diff --git a/src/chain.h b/src/chain.h
index 9199983565..5b9605a80b 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -14,8 +14,6 @@
#include <vector>
-#include <boost/foreach.hpp>
-
struct CDiskBlockPos
{
int nFile;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index b962f6ac0a..965d131695 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -81,7 +81,18 @@ public:
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
- /**
+ consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
+ consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
+
+ // Deployment of BIP68, BIP112, and BIP113.
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
+
+ /**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
* a large 32-bit integer with any alignment.
@@ -90,7 +101,6 @@ public:
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;
- vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
nPruneAfterHeight = 100000;
@@ -162,11 +172,21 @@ public:
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false;
+ consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
+ consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
+
+ // Deployment of BIP68, BIP112, and BIP113.
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
+
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07;
- vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333;
nPruneAfterHeight = 1000;
@@ -225,6 +245,14 @@ public:
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = true;
+ consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
+ consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
diff --git a/src/chainparams.h b/src/chainparams.h
index 88bc666765..59202f548a 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -54,7 +54,6 @@ public:
const Consensus::Params& GetConsensus() const { return consensus; }
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
- const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
const CBlock& GenesisBlock() const { return genesis; }
@@ -80,8 +79,6 @@ protected:
Consensus::Params consensus;
CMessageHeader::MessageStartChars pchMessageStart;
- //! Raw pub key bytes for the broadcast alert signing key.
- std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
diff --git a/src/coincontrol.h b/src/coincontrol.h
index 9626ad2c5b..12fe9ce219 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -38,10 +38,9 @@ public:
return (setSelected.size() > 0);
}
- bool IsSelected(const uint256& hash, unsigned int n) const
+ bool IsSelected(const COutPoint& output) const
{
- COutPoint outpt(hash, n);
- return (setSelected.count(outpt) > 0);
+ return (setSelected.count(output) > 0);
}
void Select(const COutPoint& output)
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 5a099cf53c..ad9cc26175 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -13,8 +13,11 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
-/** Flags for LockTime() */
+/** Flags for nSequence and nLockTime locks */
enum {
+ /* Interpret sequence numbers as relative lock-time constraints. */
+ LOCKTIME_VERIFY_SEQUENCE = (1 << 0),
+
/* Use GetMedianTimePast() instead of nTime for end point timestamp. */
LOCKTIME_MEDIAN_TIME_PAST = (1 << 1),
};
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 335750fe80..4f3480b89b 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -7,8 +7,30 @@
#define BITCOIN_CONSENSUS_PARAMS_H
#include "uint256.h"
+#include <map>
+#include <string>
namespace Consensus {
+
+enum DeploymentPos
+{
+ DEPLOYMENT_TESTDUMMY,
+ DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
+ MAX_VERSION_BITS_DEPLOYMENTS
+};
+
+/**
+ * Struct for each individual consensus rule change using BIP9.
+ */
+struct BIP9Deployment {
+ /** Bit position to select the particular bit in nVersion. */
+ int bit;
+ /** Start MedianTime for version bits miner confirmation. Can be a date in the past */
+ int64_t nStartTime;
+ /** Timeout/expiry MedianTime for the deployment attempt. */
+ int64_t nTimeout;
+};
+
/**
* Parameters that influence chain consensus.
*/
@@ -22,6 +44,14 @@ struct Params {
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
+ /**
+ * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period,
+ * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
+ * Examples: 1916 for 95%, 1512 for testchains.
+ */
+ uint32_t nRuleChangeActivationThreshold;
+ uint32_t nMinerConfirmationWindow;
+ BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
/** Proof of work parameters */
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 432a5c0792..04d3386e9a 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -21,6 +21,9 @@
#include <boost/algorithm/string.hpp> // boost::trim
#include <boost/foreach.hpp> //BOOST_FOREACH
+/** WWW-Authenticate to present with 401 Unauthorized response */
+static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
+
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
* re-lock the wellet.
*/
@@ -151,6 +154,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
// Check authorization
std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
if (!authHeader.first) {
+ req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
req->WriteReply(HTTP_UNAUTHORIZED);
return false;
}
@@ -163,6 +167,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
shouldn't have their RPC port exposed. */
MilliSleep(250);
+ req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
req->WriteReply(HTTP_UNAUTHORIZED);
return false;
}
@@ -214,7 +219,7 @@ static bool InitRPCAuthentication()
return false;
}
} else {
- LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.");
+ LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n");
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
return true;
diff --git a/src/init.cpp b/src/init.cpp
index 9ca417b83a..a872abd16c 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -24,9 +24,11 @@
#include "net.h"
#include "policy/policy.h"
#include "rpc/server.h"
+#include "rpc/register.h"
#include "script/standard.h"
#include "script/sigcache.h"
#include "scheduler.h"
+#include "timedata.h"
#include "txdb.h"
#include "txmempool.h"
#include "torcontrol.h"
@@ -72,6 +74,7 @@ static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
+
#if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
#endif
@@ -194,7 +197,6 @@ void Shutdown()
if (pwalletMain)
pwalletMain->Flush(false);
#endif
- GenerateBitcoins(false, 0, Params());
StopNode();
StopTorControl();
UnregisterNodeSignals(GetNodeSignals());
@@ -315,7 +317,6 @@ std::string HelpMessage(HelpMessageMode mode)
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("Print this help message and exit"));
strUsage += HelpMessageOpt("-version", _("Print version and exit"));
- strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
if (showDebug)
@@ -331,6 +332,7 @@ std::string HelpMessage(HelpMessageMode mode)
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
+ strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
@@ -365,12 +367,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
+ strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
- strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), 1));
- if (showDebug)
- strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", 0));
+ strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS));
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
@@ -393,26 +394,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
- strUsage += HelpMessageGroup(_("Wallet options:"));
- strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
- strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
- strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
- CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
- strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
- strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat on startup"));
- strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
- strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
- strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
- strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
- strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
- strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
- strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
- strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
- " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
+ strUsage += CWallet::GetWalletHelpString(showDebug);
#endif
#if ENABLE_ZMQ
@@ -430,16 +412,10 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks()));
strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks()));
strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
-#ifdef ENABLE_WALLET
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
-#endif
strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
-#ifdef ENABLE_WALLET
- strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
-#endif
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
@@ -453,8 +429,6 @@ std::string HelpMessage(HelpMessageMode mode)
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
if (showDebug)
strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0");
- strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE));
- strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS));
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS));
@@ -475,9 +449,6 @@ std::string HelpMessage(HelpMessageMode mode)
if (showDebug)
{
strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
-#ifdef ENABLE_WALLET
- strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
-#endif
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
@@ -496,7 +467,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
if (showDebug)
- strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
+ strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
strUsage += HelpMessageGroup(_("RPC server options:"));
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands"));
@@ -945,10 +916,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fPruneMode = true;
}
+ RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
if (!fDisableWallet)
- walletRegisterRPCCommands();
+ RegisterWalletRPCCommands(tableRPC);
#endif
nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
@@ -1025,19 +997,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
- std::string strWalletFile = GetArg("-wallet", "wallet.dat");
+ std::string strWalletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
#endif // ENABLE_WALLET
fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
- fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
-
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
- if (GetBoolArg("-peerbloomfilters", true))
+ if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices |= NODE_BLOOM;
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
@@ -1089,12 +1059,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fPrintToDebugLog)
OpenDebugLog();
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
- LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
-#else
- LogPrintf("Using OpenSSL version %s\n", OpenSSL_version(OPENSSL_VERSION));
-#endif
-
#ifdef ENABLE_WALLET
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
#endif
@@ -1195,6 +1159,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// -proxy sets a proxy for all outgoing network traffic
// -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
std::string proxyArg = GetArg("-proxy", "");
+ SetLimited(NET_TOR);
if (proxyArg != "" && proxyArg != "0") {
proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize);
if (!addrProxy.IsValid())
@@ -1204,7 +1169,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
SetProxy(NET_IPV6, addrProxy);
SetProxy(NET_TOR, addrProxy);
SetNameProxy(addrProxy);
- SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later
+ SetLimited(NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later
}
// -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
@@ -1213,13 +1178,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
std::string onionArg = GetArg("-onion", "");
if (onionArg != "") {
if (onionArg == "0") { // Handle -noonion/-onion=0
- SetReachable(NET_TOR, false); // set onions as unreachable
+ SetLimited(NET_TOR); // set onions as unreachable
} else {
proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg));
SetProxy(NET_TOR, addrOnion);
- SetReachable(NET_TOR);
+ SetLimited(NET_TOR, false);
}
}
@@ -1456,149 +1421,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
} else {
-
- // needed to restore wallet transaction meta data after -zapwallettxes
- std::vector<CWalletTx> vWtx;
-
- if (GetBoolArg("-zapwallettxes", false)) {
- uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
-
- pwalletMain = new CWallet(strWalletFile);
- DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
- if (nZapWalletRet != DB_LOAD_OK) {
- uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
- return false;
- }
-
- delete pwalletMain;
- pwalletMain = NULL;
- }
-
- uiInterface.InitMessage(_("Loading wallet..."));
-
- nStart = GetTimeMillis();
- bool fFirstRun = true;
- pwalletMain = new CWallet(strWalletFile);
- DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
- if (nLoadWalletRet != DB_LOAD_OK)
- {
- if (nLoadWalletRet == DB_CORRUPT)
- strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
- else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
- {
- InitWarning(_("Error reading wallet.dat! All keys read correctly, but transaction data"
- " or address book entries might be missing or incorrect."));
- }
- else if (nLoadWalletRet == DB_TOO_NEW)
- strErrors << strprintf(_("Error loading wallet.dat: Wallet requires newer version of %s"), _(PACKAGE_NAME)) << "\n";
- else if (nLoadWalletRet == DB_NEED_REWRITE)
- {
- strErrors << strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)) << "\n";
- LogPrintf("%s", strErrors.str());
- return InitError(strErrors.str());
- }
- else
- strErrors << _("Error loading wallet.dat") << "\n";
- }
-
- if (GetBoolArg("-upgradewallet", fFirstRun))
- {
- int nMaxVersion = GetArg("-upgradewallet", 0);
- if (nMaxVersion == 0) // the -upgradewallet without argument case
- {
- LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
- nMaxVersion = CLIENT_VERSION;
- pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
- }
- else
- LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
- if (nMaxVersion < pwalletMain->GetVersion())
- strErrors << _("Cannot downgrade wallet") << "\n";
- pwalletMain->SetMaxVersion(nMaxVersion);
- }
-
- if (fFirstRun)
- {
- // Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
- CPubKey newDefaultKey;
- if (pwalletMain->GetKeyFromPool(newDefaultKey)) {
- pwalletMain->SetDefaultKey(newDefaultKey);
- if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive"))
- strErrors << _("Cannot write default address") << "\n";
- }
-
- pwalletMain->SetBestChain(chainActive.GetLocator());
- }
-
- LogPrintf("%s", strErrors.str());
- LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
-
- RegisterValidationInterface(pwalletMain);
-
- CBlockIndex *pindexRescan = chainActive.Tip();
- if (GetBoolArg("-rescan", false))
- pindexRescan = chainActive.Genesis();
- else
- {
- CWalletDB walletdb(strWalletFile);
- CBlockLocator locator;
- if (walletdb.ReadBestBlock(locator))
- pindexRescan = FindForkInGlobalIndex(chainActive, locator);
- else
- pindexRescan = chainActive.Genesis();
- }
- if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
+ std::string warningString;
+ std::string errorString;
+ pwalletMain = CWallet::InitLoadWallet(fDisableWallet, strWalletFile, warningString, errorString);
+ if (!warningString.empty())
+ InitWarning(warningString);
+ if (!errorString.empty())
{
- //We can't rescan beyond non-pruned blocks, stop and throw an error
- //this might happen if a user uses a old wallet within a pruned node
- // or if he ran -disablewallet for a longer time, then decided to re-enable
- if (fPruneMode)
- {
- CBlockIndex *block = chainActive.Tip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
- block = block->pprev;
-
- if (pindexRescan != block)
- return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
- }
-
- uiInterface.InitMessage(_("Rescanning..."));
- LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
- nStart = GetTimeMillis();
- pwalletMain->ScanForWalletTransactions(pindexRescan, true);
- LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
- pwalletMain->SetBestChain(chainActive.GetLocator());
- nWalletDBUpdated++;
-
- // Restore wallet transaction metadata after -zapwallettxes=1
- if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
- {
- CWalletDB walletdb(strWalletFile);
-
- BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
- {
- uint256 hash = wtxOld.GetHash();
- std::map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
- if (mi != pwalletMain->mapWallet.end())
- {
- const CWalletTx* copyFrom = &wtxOld;
- CWalletTx* copyTo = &mi->second;
- copyTo->mapValue = copyFrom->mapValue;
- copyTo->vOrderForm = copyFrom->vOrderForm;
- copyTo->nTimeReceived = copyFrom->nTimeReceived;
- copyTo->nTimeSmart = copyFrom->nTimeSmart;
- copyTo->fFromMe = copyFrom->fFromMe;
- copyTo->strFromAccount = copyFrom->strFromAccount;
- copyTo->nOrderPos = copyFrom->nOrderPos;
- copyTo->WriteToDisk(&walletdb);
- }
- }
- }
+ LogPrintf("%s", errorString);
+ return InitError(errorString);
}
- pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
- } // (!fDisableWallet)
+ if (!pwalletMain)
+ return false;
+ }
#else // ENABLE_WALLET
LogPrintf("No wallet support compiled in!\n");
#endif // !ENABLE_WALLET
@@ -1670,9 +1505,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing);
- // Generate coins in the background
- GenerateBitcoins(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams);
-
// ********************************************************* Step 12: finished
SetRPCWarmupFinished();
diff --git a/src/main.cpp b/src/main.cpp
index 89b4b2930c..2c0b3bfee7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,7 +6,6 @@
#include "main.h"
#include "addrman.h"
-#include "alert.h"
#include "arith_uint256.h"
#include "chainparams.h"
#include "checkpoints.h"
@@ -18,10 +17,12 @@
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
+#include "random.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
@@ -34,6 +35,7 @@
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include "versionbits.h"
#include <sstream>
@@ -74,7 +76,6 @@ bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
-bool fAlerts = DEFAULT_ALERTS;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
@@ -82,6 +83,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CTxMemPool mempool(::minRelayTxFee);
+FeeFilterRounder filterRounder(::minRelayTxFee);
struct COrphanTx {
CTransaction tx;
@@ -332,8 +334,10 @@ void FinalizeNode(NodeId nodeid) {
AddressCurrentlyConnected(state->address);
}
- BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight)
+ BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
+ nQueuedValidatedHeaders -= entry.fValidatedHeaders;
mapBlocksInFlight.erase(entry.hash);
+ }
EraseOrphansFor(nodeid);
nPreferredDownload -= state->fPreferredDownload;
@@ -374,7 +378,7 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
-/** Check whether the last unknown block a peer advertized is not yet known. */
+/** Check whether the last unknown block a peer advertised is not yet known. */
void ProcessBlockAvailability(NodeId nodeid) {
CNodeState *state = State(nodeid);
assert(state != NULL);
@@ -670,9 +674,10 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- if (!txin.IsFinal())
+ BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
return false;
+ }
return true;
}
@@ -708,6 +713,178 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
+/**
+ * Calculates the block height and previous block's median time past at
+ * which the transaction will be considered final in the context of BIP 68.
+ * Also removes from the vector of input heights any entries which did not
+ * correspond to sequence locked inputs as they do not affect the calculation.
+ */
+static std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
+{
+ assert(prevHeights->size() == tx.vin.size());
+
+ // Will be set to the equivalent height- and time-based nLockTime
+ // values that would be necessary to satisfy all relative lock-
+ // time constraints given our view of block chain history.
+ // The semantics of nLockTime are the last invalid height/time, so
+ // use -1 to have the effect of any height or time being valid.
+ int nMinHeight = -1;
+ int64_t nMinTime = -1;
+
+ // tx.nVersion is signed integer so requires cast to unsigned otherwise
+ // we would be doing a signed comparison and half the range of nVersion
+ // wouldn't support BIP 68.
+ bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
+ && flags & LOCKTIME_VERIFY_SEQUENCE;
+
+ // Do not enforce sequence numbers as a relative lock time
+ // unless we have been instructed to
+ if (!fEnforceBIP68) {
+ return std::make_pair(nMinHeight, nMinTime);
+ }
+
+ for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
+ const CTxIn& txin = tx.vin[txinIndex];
+
+ // Sequence numbers with the most significant bit set are not
+ // treated as relative lock-times, nor are they given any
+ // consensus-enforced meaning at this point.
+ if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
+ // The height of this input is not relevant for sequence locks
+ (*prevHeights)[txinIndex] = 0;
+ continue;
+ }
+
+ int nCoinHeight = (*prevHeights)[txinIndex];
+
+ if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
+ int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
+ // NOTE: Subtract 1 to maintain nLockTime semantics
+ // BIP 68 relative lock times have the semantics of calculating
+ // the first block or time at which the transaction would be
+ // valid. When calculating the effective block time or height
+ // for the entire transaction, we switch to using the
+ // semantics of nLockTime which is the last invalid block
+ // time or height. Thus we subtract 1 from the calculated
+ // time or height.
+
+ // Time-based relative lock-times are measured from the
+ // smallest allowed timestamp of the block containing the
+ // txout being spent, which is the median time past of the
+ // block prior.
+ nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
+ } else {
+ nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
+ }
+ }
+
+ return std::make_pair(nMinHeight, nMinTime);
+}
+
+static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
+{
+ assert(block.pprev);
+ int64_t nBlockTime = block.pprev->GetMedianTimePast();
+ if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
+ return false;
+
+ return true;
+}
+
+bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
+{
+ return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
+}
+
+bool TestLockPointValidity(const LockPoints* lp)
+{
+ AssertLockHeld(cs_main);
+ assert(lp);
+ // If there are relative lock times then the maxInputBlock will be set
+ // If there are no relative lock times, the LockPoints don't depend on the chain
+ if (lp->maxInputBlock) {
+ // Check whether chainActive is an extension of the block at which the LockPoints
+ // calculation was valid. If not LockPoints are no longer valid
+ if (!chainActive.Contains(lp->maxInputBlock)) {
+ return false;
+ }
+ }
+
+ // LockPoints still valid
+ return true;
+}
+
+bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints)
+{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(mempool.cs);
+
+ CBlockIndex* tip = chainActive.Tip();
+ CBlockIndex index;
+ index.pprev = tip;
+ // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
+ // height based locks because when SequenceLocks() is called within
+ // ConnectBlock(), the height of the block *being*
+ // evaluated is what is used.
+ // Thus if we want to know if a transaction can be part of the
+ // *next* block, we need to use one more than chainActive.Height()
+ index.nHeight = tip->nHeight + 1;
+
+ std::pair<int, int64_t> lockPair;
+ if (useExistingLockPoints) {
+ assert(lp);
+ lockPair.first = lp->height;
+ lockPair.second = lp->time;
+ }
+ else {
+ // pcoinsTip contains the UTXO set for chainActive.Tip()
+ CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
+ std::vector<int> prevheights;
+ prevheights.resize(tx.vin.size());
+ for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
+ const CTxIn& txin = tx.vin[txinIndex];
+ CCoins coins;
+ if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
+ return error("%s: Missing input", __func__);
+ }
+ if (coins.nHeight == MEMPOOL_HEIGHT) {
+ // Assume all mempool transaction confirm in the next block
+ prevheights[txinIndex] = tip->nHeight + 1;
+ } else {
+ prevheights[txinIndex] = coins.nHeight;
+ }
+ }
+ lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
+ if (lp) {
+ lp->height = lockPair.first;
+ lp->time = lockPair.second;
+ // Also store the hash of the block with the highest height of
+ // all the blocks which have sequence locked prevouts.
+ // This hash needs to still be on the chain
+ // for these LockPoint calculations to be valid
+ // Note: It is impossible to correctly calculate a maxInputBlock
+ // if any of the sequence locked inputs depend on unconfirmed txs,
+ // except in the special case where the relative lock time/height
+ // is 0, which is equivalent to no sequence lock. Since we assume
+ // input height of tip+1 for mempool txs and test the resulting
+ // lockPair from CalculateSequenceLocks against tip+1. We know
+ // EvaluateSequenceLocks will fail if there was a non-zero sequence
+ // lock on a mempool input, so we can use the return value of
+ // CheckSequenceLocks to indicate the LockPoints validity
+ int maxInputHeight = 0;
+ BOOST_FOREACH(int height, prevheights) {
+ // Can ignore mempool inputs since we'll fail if they had non-zero locks
+ if (height != tip->nHeight+1) {
+ maxInputHeight = std::max(maxInputHeight, height);
+ }
+ }
+ lp->maxInputBlock = tip->GetAncestor(maxInputHeight);
+ }
+ }
+ return EvaluateSequenceLocks(index, lockPair);
+}
+
+
unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
@@ -813,7 +990,7 @@ std::string FormatStateMessage(const CValidationState &state)
}
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee,
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
std::vector<uint256>& vHashTxnToUncache)
{
const uint256 hash = tx.GetHash();
@@ -822,7 +999,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))
- return error("%s: CheckTransaction: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+ return false; // state filled in by CheckTransaction
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
@@ -892,6 +1069,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CCoinsViewCache view(&dummy);
CAmount nValueIn = 0;
+ LockPoints lp;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
@@ -929,6 +1107,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
+
+ // Only accept BIP68 sequence locked transactions that can be mined in the next
+ // block; we don't want our mempool filled up with transactions that can't
+ // be mined yet.
+ // Must keep pool.cs for this unless we change CheckSequenceLocks to take a
+ // CoinsViewCache instead of create its own
+ if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
}
// Check for non-standard pay-to-script-hash in inputs
@@ -959,8 +1145,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
unsigned int nSize = entry.GetTxSize();
+ if (txFeeRate) {
+ *txFeeRate = CFeeRate(nFees, nSize);
+ }
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
@@ -1027,10 +1216,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
if (setConflicts.count(hashAncestor))
{
- return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s",
+ return state.DoS(10, false,
+ REJECT_INVALID, "bad-txns-spends-conflicting-tx", false,
+ strprintf("%s spends conflicting transaction %s",
hash.ToString(),
- hashAncestor.ToString()),
- REJECT_INVALID, "bad-txns-spends-conflicting-tx");
+ hashAncestor.ToString()));
}
}
@@ -1060,20 +1250,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Save these to avoid repeated lookups
setIterConflicting.insert(mi);
- // If this entry is "dirty", then we don't have descendant
- // state for this transaction, which means we probably have
- // lots of in-mempool descendants.
- // Don't allow replacements of dirty transactions, to ensure
- // that we don't spend too much time walking descendants.
- // This should be rare.
- if (mi->IsDirty()) {
- return state.DoS(0,
- error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants",
- hash.ToString(),
- mi->GetTx().GetHash().ToString()),
- REJECT_NONSTANDARD, "too many potential replacements");
- }
-
// Don't allow the replacement to reduce the feerate of the
// mempool.
//
@@ -1093,12 +1269,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate)
{
- return state.DoS(0,
- error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s",
+ return state.DoS(0, false,
+ REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
hash.ToString(),
newFeeRate.ToString(),
- oldFeeRate.ToString()),
- REJECT_INSUFFICIENTFEE, "insufficient fee");
+ oldFeeRate.ToString()));
}
BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin)
@@ -1122,12 +1298,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
nConflictingSize += it->GetTxSize();
}
} else {
- return state.DoS(0,
- error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n",
+ return state.DoS(0, false,
+ REJECT_NONSTANDARD, "too many potential replacements", false,
+ strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
hash.ToString(),
nConflictingCount,
- maxDescendantsToVisit),
- REJECT_NONSTANDARD, "too many potential replacements");
+ maxDescendantsToVisit));
}
for (unsigned int j = 0; j < tx.vin.size(); j++)
@@ -1142,9 +1318,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// it's cheaper to just check if the new input refers to a
// tx that's in the mempool.
if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end())
- return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d",
- hash.ToString(), j),
- REJECT_NONSTANDARD, "replacement-adds-unconfirmed");
+ return state.DoS(0, false,
+ REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false,
+ strprintf("replacement %s adds unconfirmed input, idx %d",
+ hash.ToString(), j));
}
}
@@ -1153,9 +1330,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// transactions would not be paid for.
if (nModifiedFees < nConflictingFees)
{
- return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s",
- hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)),
- REJECT_INSUFFICIENTFEE, "insufficient fee");
+ return state.DoS(0, false,
+ REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
+ hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));
}
// Finally in addition to paying more fees than the conflicts the
@@ -1163,19 +1341,19 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::minRelayTxFee.GetFee(nSize))
{
- return state.DoS(0,
- error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s",
+ return state.DoS(0, false,
+ REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
- FormatMoney(::minRelayTxFee.GetFee(nSize))),
- REJECT_INSUFFICIENTFEE, "insufficient fee");
+ FormatMoney(::minRelayTxFee.GetFee(nSize))));
}
}
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
- return error("%s: CheckInputs: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+ return false; // state filled in by CheckInputs
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
@@ -1201,7 +1379,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
FormatMoney(nModifiedFees - nConflictingFees),
(int)nSize - (int)nConflictingSize);
}
- pool.RemoveStaged(allConflicting);
+ pool.RemoveStaged(allConflicting, false);
// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
@@ -1220,10 +1398,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{
std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
if (!res) {
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
@@ -1392,6 +1570,26 @@ bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
+static void AlertNotify(const std::string& strMessage, bool fThread)
+{
+ uiInterface.NotifyAlertChanged();
+ std::string strCmd = GetArg("-alertnotify", "");
+ if (strCmd.empty()) return;
+
+ // Alert text should be plain ascii coming from a trusted source, but to
+ // be safe we first strip anything not in safeChars, then add single quotes around
+ // the whole string before passing it to the shell:
+ std::string singleQuote("'");
+ std::string safeStatus = SanitizeString(strMessage);
+ safeStatus = singleQuote+safeStatus+singleQuote;
+ boost::replace_all(strCmd, "%s", safeStatus);
+
+ if (fThread)
+ boost::thread t(runCommand, strCmd); // thread runs free
+ else
+ runCommand(strCmd);
+}
+
void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
@@ -1411,7 +1609,7 @@ void CheckForkWarningConditions()
{
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
- CAlert::Notify(warning, true);
+ AlertNotify(warning, true);
}
if (pindexBestForkTip && pindexBestForkBase)
{
@@ -1942,11 +2140,56 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
if (!strWarning.empty())
{
strMiscWarning = strWarning;
- CAlert::Notify(strWarning, true);
+ AlertNotify(strWarning, true);
lastAlertTime = now;
}
}
+// Protected by cs_main
+static VersionBitsCache versionbitscache;
+
+int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
+{
+ LOCK(cs_main);
+ int32_t nVersion = VERSIONBITS_TOP_BITS;
+
+ for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
+ ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache);
+ if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
+ nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);
+ }
+ }
+
+ return nVersion;
+}
+
+/**
+ * Threshold condition checker that triggers when unknown versionbits are seen on the network.
+ */
+class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
+{
+private:
+ int bit;
+
+public:
+ WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
+
+ int64_t BeginTime(const Consensus::Params& params) const { return 0; }
+ int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); }
+ int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
+ int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
+
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
+ {
+ return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
+ ((pindex->nVersion >> bit) & 1) != 0 &&
+ ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;
+ }
+};
+
+// Protected by cs_main
+static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
+
static int64_t nTimeCheck = 0;
static int64_t nTimeForks = 0;
static int64_t nTimeVerify = 0;
@@ -2043,6 +2286,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
+ // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
+ int nLockTimeFlags = 0;
+ if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
+ nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
+ }
+
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
@@ -2050,6 +2300,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
+ std::vector<int> prevheights;
CAmount nFees = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
@@ -2073,6 +2324,19 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent");
+ // Check that transaction is BIP68 final
+ // BIP68 lock checks (as opposed to nLockTime checks) must
+ // be in ConnectBlock because they require the UTXO set
+ prevheights.resize(tx.vin.size());
+ for (size_t j = 0; j < tx.vin.size(); j++) {
+ prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
+ }
+
+ if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
+ return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__),
+ REJECT_INVALID, "bad-txns-nonfinal");
+ }
+
if (fStrictPayToScriptHash)
{
// Add in sigops done by pay-to-script-hash inputs;
@@ -2260,7 +2524,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
return AbortNode(state, "Failed to write to coin database");
nLastFlush = nNow;
}
- if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) {
+ if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
// Update best block in wallet (so we can detect restored wallets).
GetMainSignals().SetBestChain(chainActive.GetLocator());
nLastSetChain = nNow;
@@ -2291,8 +2555,8 @@ void static UpdateTip(CBlockIndex *pindexNew) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("%s: new best=%s height=%d bits=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nBits,
+ LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)\n", __func__,
+ chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
@@ -2301,24 +2565,42 @@ void static UpdateTip(CBlockIndex *pindexNew) {
// Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false;
- if (!IsInitialBlockDownload() && !fWarned)
+ if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
const CBlockIndex* pindex = chainActive.Tip();
+ for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
+ WarningBitsConditionChecker checker(bit);
+ ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
+ if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
+ if (state == THRESHOLD_ACTIVE) {
+ strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
+ if (!fWarned) {
+ AlertNotify(strMiscWarning, true);
+ fWarned = true;
+ }
+ } else {
+ LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
+ }
+ }
+ }
for (int i = 0; i < 100 && pindex != NULL; i++)
{
- if (pindex->nVersion > CBlock::CURRENT_VERSION)
+ int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
+ if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
++nUpgraded;
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION);
+ LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded);
if (nUpgraded > 100/2)
{
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
- strMiscWarning = _("Warning: This version is obsolete; upgrade required!");
- CAlert::Notify(strMiscWarning, true);
- fWarned = true;
+ strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
+ if (!fWarned) {
+ AlertNotify(strMiscWarning, true);
+ fWarned = true;
+ }
}
}
}
@@ -2350,8 +2632,8 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
- mempool.remove(tx, removed, true);
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
+ mempool.removeRecursive(tx, removed);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
}
@@ -3008,8 +3290,8 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
for (int32_t version = 2; version < 5; ++version) // check for version 2, 3 and 4 upgrades
if (block.nVersion < version && IsSuperMajority(version, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
- return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(v%d)", version - 1),
- strprintf("rejected nVersion=%d block", version - 1));
+ return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", version - 1),
+ strprintf("rejected nVersion=0x%08x block", version - 1));
return true;
}
@@ -3019,12 +3301,18 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
const Consensus::Params& consensusParams = Params().GetConsensus();
+ // Start enforcing BIP113 (Median Time Past) using versionbits logic.
+ int nLockTimeFlags = 0;
+ if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
+ }
+
+ int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)
+ ? pindexPrev->GetMedianTimePast()
+ : block.GetBlockTime();
+
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- int nLockTimeFlags = 0;
- int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)
- ? pindexPrev->GetMedianTimePast()
- : block.GetBlockTime();
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) {
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction");
}
@@ -3612,6 +3900,10 @@ void UnloadBlockIndex()
setDirtyFileInfo.clear();
mapNodeState.clear();
recentRejects.reset(NULL);
+ versionbitscache.Clear();
+ for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
+ warningcache[b].clear();
+ }
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
delete entry.second;
@@ -3957,14 +4249,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(nNodes == forward.size());
}
-//////////////////////////////////////////////////////////////////////////////
-//
-// CAlert
-//
-
std::string GetWarnings(const std::string& strFor)
{
- int nPriority = 0;
string strStatusBar;
string strRPC;
string strGUI;
@@ -3980,37 +4266,20 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
- nPriority = 1000;
strStatusBar = strGUI = strMiscWarning;
}
if (fLargeWorkForkFound)
{
- nPriority = 2000;
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
- nPriority = 2000;
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
- // Alerts
- {
- LOCK(cs_mapAlerts);
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- {
- const CAlert& alert = item.second;
- if (alert.AppliesToMe() && alert.nPriority > nPriority)
- {
- nPriority = alert.nPriority;
- strStatusBar = strGUI = alert.strStatusBar;
- }
- }
- }
-
if (strFor == "gui")
return strGUI;
else if (strFor == "statusbar")
@@ -4226,7 +4495,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
Misbehaving(pfrom->GetId(), 100);
return false;
- } else if (GetBoolArg("-enforcenodebloom", false)) {
+ } else {
pfrom->fDisconnect = true;
return false;
}
@@ -4308,11 +4577,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
{
- LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
+ LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
- LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
+ LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
}
}
@@ -4332,13 +4601,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
- // Relay alerts
- {
- LOCK(cs_mapAlerts);
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- item.second.RelayTo(pfrom);
- }
-
pfrom->fSuccessfullyConnected = true;
string remoteAddr;
@@ -4672,10 +4934,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv);
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
- {
+ CFeeRate txFeeRate = CFeeRate(0);
+ if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
mempool.check(pcoinsTip);
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
vWorkQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
@@ -4706,10 +4968,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (setMisbehaving.count(fromPeer))
continue;
- if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
- {
+ CFeeRate orphanFeeRate = CFeeRate(0);
+ if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx);
+ RelayTransaction(orphanTx, orphanFeeRate);
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
}
@@ -4762,7 +5024,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@@ -4916,13 +5178,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- // This asymmetric behavior for inbound and outbound connections was introduced
- // to prevent a fingerprinting attack: an attacker can send specific fake addresses
- // to users' AddrMan and later request them by sending getaddr messages.
- // Making nodes which are behind NAT and can only make outgoing connections ignore
- // the getaddr message mitigates the attack.
- else if ((strCommand == NetMsgType::GETADDR) && (pfrom->fInbound))
+ else if (strCommand == NetMsgType::GETADDR)
{
+ // This asymmetric behavior for inbound and outbound connections was introduced
+ // to prevent a fingerprinting attack: an attacker can send specific fake addresses
+ // to users' AddrMan and later request them by sending getaddr messages.
+ // Making nodes which are behind NAT and can only make outgoing connections ignore
+ // the getaddr message mitigates the attack.
+ if (!pfrom->fInbound) {
+ LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id);
+ return true;
+ }
+
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
BOOST_FOREACH(const CAddress &addr, vAddr)
@@ -4951,6 +5218,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
}
+ if (pfrom->minFeeFilter) {
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(hash, feeRate);
+ LOCK(pfrom->cs_feeFilter);
+ if (feeRate.GetFeePerK() < pfrom->minFeeFilter)
+ continue;
+ }
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
pfrom->PushMessage(NetMsgType::INV, vInv);
@@ -5041,37 +5315,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (fAlerts && strCommand == NetMsgType::ALERT)
- {
- CAlert alert;
- vRecv >> alert;
-
- uint256 alertHash = alert.GetHash();
- if (pfrom->setKnown.count(alertHash) == 0)
- {
- if (alert.ProcessAlert(chainparams.AlertKey()))
- {
- // Relay
- pfrom->setKnown.insert(alertHash);
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- alert.RelayTo(pnode);
- }
- }
- else {
- // Small DoS penalty so peers that send us lots of
- // duplicate/expired/invalid-signature/whatever alerts
- // eventually get banned.
- // This isn't a Misbehaving(100) (immediate ban) because the
- // peer might be an older or different implementation with
- // a different signature key, etc.
- Misbehaving(pfrom->GetId(), 10);
- }
- }
- }
-
-
else if (strCommand == NetMsgType::FILTERLOAD)
{
CBloomFilter filter;
@@ -5144,8 +5387,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
- else
- {
+ else if (strCommand == NetMsgType::FEEFILTER) {
+ CAmount newFeeFilter = 0;
+ vRecv >> newFeeFilter;
+ if (MoneyRange(newFeeFilter)) {
+ {
+ LOCK(pfrom->cs_feeFilter);
+ pfrom->minFeeFilter = newFeeFilter;
+ }
+ LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id);
+ }
+ }
+
+ else {
// Ignore unknown commands for extensibility
LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
}
@@ -5321,7 +5575,7 @@ bool SendMessages(CNode* pto)
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
- AdvertizeLocal(pto);
+ AdvertiseLocal(pto);
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -5627,6 +5881,29 @@ bool SendMessages(CNode* pto)
if (!vGetData.empty())
pto->PushMessage(NetMsgType::GETDATA, vGetData);
+ //
+ // Message: feefilter
+ //
+ // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
+ if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
+ CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
+ int64_t timeNow = GetTimeMicros();
+ if (timeNow > pto->nextSendTimeFeeFilter) {
+ CAmount filterToSend = filterRounder.round(currentFilter);
+ if (filterToSend != pto->lastSentFeeFilter) {
+ pto->PushMessage(NetMsgType::FEEFILTER, filterToSend);
+ pto->lastSentFeeFilter = filterToSend;
+ }
+ pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ }
+ // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
+ // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
+ else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
+ (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
+ pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
+ }
+ }
}
return true;
}
@@ -5635,7 +5912,11 @@ bool SendMessages(CNode* pto)
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
}
-
+ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
+{
+ LOCK(cs_main);
+ return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
+}
class CMainCleanup
{
diff --git a/src/main.h b/src/main.h
index 4061daba3b..0bfcfab213 100644
--- a/src/main.h
+++ b/src/main.h
@@ -16,6 +16,7 @@
#include "net.h"
#include "script/script_error.h"
#include "sync.h"
+#include "versionbits.h"
#include <algorithm>
#include <exception>
@@ -39,9 +40,8 @@ class CValidationInterface;
class CValidationState;
struct CNodeStateStats;
+struct LockPoints;
-/** Default for accepting alerts from the P2P network. */
-static const bool DEFAULT_ALERTS = true;
/** Default for DEFAULT_WHITELISTRELAY. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for DEFAULT_WHITELISTFORCERELAY. */
@@ -102,6 +102,10 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
/** Average delay between trickled inventory broadcasts in seconds.
* Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
+/** Average delay between feefilter broadcasts in seconds. */
+static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
+/** Maximum feefilter broadcast delay after significant change. */
+static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
static const unsigned int DEFAULT_LIMITFREERELAY = 15;
static const bool DEFAULT_RELAYPRIORITY = true;
@@ -117,10 +121,14 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
static const bool DEFAULT_TESTSAFEMODE = false;
/** Default for -mempoolreplacement */
static const bool DEFAULT_ENABLE_REPLACEMENT = true;
+/** Default for using fee filter */
+static const bool DEFAULT_FEEFILTER = true;
/** Maximum number of headers to announce when relaying blocks with headers message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
+static const bool DEFAULT_PEERBLOOMFILTERS = true;
+
struct BlockHasher
{
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
@@ -150,7 +158,6 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
extern CAmount maxTxFee;
-extern bool fAlerts;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge;
extern bool fEnableReplacement;
@@ -281,11 +288,14 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
+/** Get the BIP9 state for a given deployment at the current tip. */
+ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
+
struct CNodeStateStats {
int nMisbehavior;
int nSyncHeight;
@@ -365,7 +375,31 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
*/
bool CheckFinalTx(const CTransaction &tx, int flags = -1);
-/**
+/**
+ * Test whether the LockPoints height and time are still valid on the current chain
+ */
+bool TestLockPointValidity(const LockPoints* lp);
+
+/**
+ * Check if transaction is final per BIP 68 sequence numbers and can be included in a block.
+ * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.
+ */
+bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
+
+/**
+ * Check if transaction will be BIP 68 final in the next block to be created.
+ *
+ * Simulates calling SequenceLocks() with data from the tip of the current active chain.
+ * Optionally stores in LockPoints the resulting height and time calculated and the hash
+ * of the block needed for calculation or skips the calculation and uses the LockPoints
+ * passed in for evaluation.
+ * The LockPoints should not be considered valid if CheckSequenceLocks returns false.
+ *
+ * See consensus/consensus.h for flag definitions.
+ */
+bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false);
+
+/**
* Closure representing one script verification
* Note that this stores references to the spending transaction
*/
@@ -519,6 +553,11 @@ extern CBlockTreeDB *pblocktree;
*/
int GetSpendHeight(const CCoinsViewCache& inputs);
+/**
+ * Determine what nVersion a new block should use.
+ */
+int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);
+
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
* for transactions, to signal internal conditions. They cannot and should not
* be sent over the P2P network.
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 8447f924e4..dca4973cc4 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -95,7 +95,7 @@ void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const st
}
}
-uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
+uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
if (nBitsUsed >= vBits.size()) {
// overflowed the bits array - failure
fBad = true;
@@ -110,14 +110,16 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns
return uint256();
}
const uint256 &hash = vHash[nHashUsed++];
- if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
+ if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid
vMatch.push_back(hash);
+ vnIndex.push_back(pos);
+ }
return hash;
} else {
// otherwise, descend into the subtrees to extract matched txids and hashes
- uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
+ uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;
if (pos*2+1 < CalcTreeWidth(height-1)) {
- right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
+ right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);
if (right == left) {
// The left and right branches should never be identical, as the transaction
// hashes covered by them must each be unique.
@@ -147,7 +149,7 @@ CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const
CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
-uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
+uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
vMatch.clear();
// An empty set will not work
if (nTransactions == 0)
@@ -167,7 +169,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
nHeight++;
// traverse the partial tree
unsigned int nBitsUsed = 0, nHashUsed = 0;
- uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
+ uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);
// verify that no problems occurred during the tree traversal
if (fBad)
return uint256();
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 996cd12624..835cbcce55 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -75,9 +75,9 @@ protected:
/**
* recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
- * it returns the hash of the respective node.
+ * it returns the hash of the respective node and its respective index.
*/
- uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
+ uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
public:
@@ -110,10 +110,11 @@ public:
CPartialMerkleTree();
/**
- * extract the matching txid's represented by this partial merkle tree.
+ * extract the matching txid's represented by this partial merkle tree
+ * and their respective indices within the partial tree.
* returns the merkle root, or 0 in case of failure
*/
- uint256 ExtractMatches(std::vector<uint256> &vMatch);
+ uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
};
diff --git a/src/miner.cpp b/src/miner.cpp
index c454c0279c..ef8fd4db43 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -79,11 +79,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
return NULL;
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
- // -regtest only: allow overriding block.nVersion with
- // -blockversion=N to test forking scenarios
- if (chainparams.MineBlocksOnDemand())
- pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
-
// Create coinbase tx
CMutableTransaction txNew;
txNew.vin.resize(1);
@@ -137,6 +132,12 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
+ pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
+ // -regtest only: allow overriding block.nVersion with
+ // -blockversion=N to test forking scenarios
+ if (chainparams.MineBlocksOnDemand())
+ pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: pblock->GetBlockTime();
@@ -155,10 +156,10 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
}
- CTxMemPool::indexed_transaction_set::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin();
+ CTxMemPool::indexed_transaction_set::index<mining_score>::type::iterator mi = mempool.mapTx.get<mining_score>().begin();
CTxMemPool::txiter iter;
- while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty())
+ while (mi != mempool.mapTx.get<mining_score>().end() || !clearedTxs.empty())
{
bool priorityTx = false;
if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize
@@ -315,206 +316,3 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Internal miner
-//
-
-//
-// ScanHash scans nonces looking for a hash with at least some zero bits.
-// The nonce is usually preserved between calls, but periodically or if the
-// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at
-// zero.
-//
-bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash)
-{
- // Write the first 76 bytes of the block header to a double-SHA256 state.
- CHash256 hasher;
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << *pblock;
- assert(ss.size() == 80);
- hasher.Write((unsigned char*)&ss[0], 76);
-
- while (true) {
- nNonce++;
-
- // Write the last 4 bytes of the block header (the nonce) to a copy of
- // the double-SHA256 state, and compute the result.
- CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);
-
- // Return the nonce if the hash has at least some zero bits,
- // caller will check if it has enough to reach the target
- if (((uint16_t*)phash)[15] == 0)
- return true;
-
- // If nothing found after trying for a while, return -1
- if ((nNonce & 0xfff) == 0)
- return false;
- }
-}
-
-static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
-{
- LogPrintf("%s\n", pblock->ToString());
- LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
-
- // Found a solution
- {
- LOCK(cs_main);
- if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
- return error("BitcoinMiner: generated block is stale");
- }
-
- // Inform about the new block
- GetMainSignals().BlockFound(pblock->GetHash());
-
- // Process this block the same as if we had received it from another node
- CValidationState state;
- if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL))
- return error("BitcoinMiner: ProcessNewBlock, block not accepted");
-
- return true;
-}
-
-void static BitcoinMiner(const CChainParams& chainparams)
-{
- LogPrintf("BitcoinMiner started\n");
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
- RenameThread("bitcoin-miner");
-
- unsigned int nExtraNonce = 0;
-
- boost::shared_ptr<CReserveScript> coinbaseScript;
- GetMainSignals().ScriptForMining(coinbaseScript);
-
- try {
- // Throw an error if no script was provided. This can happen
- // due to some internal error but also if the keypool is empty.
- // In the latter case, already the pointer is NULL.
- if (!coinbaseScript || coinbaseScript->reserveScript.empty())
- throw std::runtime_error("No coinbase script available (mining requires a wallet)");
-
- while (true) {
- if (chainparams.MiningRequiresPeers()) {
- // Busy-wait for the network to come online so we don't waste time mining
- // on an obsolete chain. In regtest mode we expect to fly solo.
- do {
- bool fvNodesEmpty;
- {
- LOCK(cs_vNodes);
- fvNodesEmpty = vNodes.empty();
- }
- if (!fvNodesEmpty && !IsInitialBlockDownload())
- break;
- MilliSleep(1000);
- } while (true);
- }
-
- //
- // Create new block
- //
- unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrev = chainActive.Tip();
-
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript));
- if (!pblocktemplate.get())
- {
- LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
- return;
- }
- CBlock *pblock = &pblocktemplate->block;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
-
- LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
- ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
-
- //
- // Search
- //
- int64_t nStart = GetTime();
- arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
- uint256 hash;
- uint32_t nNonce = 0;
- while (true) {
- // Check if something found
- if (ScanHash(pblock, nNonce, &hash))
- {
- if (UintToArith256(hash) <= hashTarget)
- {
- // Found a solution
- pblock->nNonce = nNonce;
- assert(hash == pblock->GetHash());
-
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
- LogPrintf("BitcoinMiner:\n");
- LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- ProcessBlockFound(pblock, chainparams);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
- coinbaseScript->KeepScript();
-
- // In regression test mode, stop mining after a block is found.
- if (chainparams.MineBlocksOnDemand())
- throw boost::thread_interrupted();
-
- break;
- }
- }
-
- // Check for stop or if block needs to be rebuilt
- boost::this_thread::interruption_point();
- // Regtest mode doesn't require peers
- if (vNodes.empty() && chainparams.MiningRequiresPeers())
- break;
- if (nNonce >= 0xffff0000)
- break;
- if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
- break;
- if (pindexPrev != chainActive.Tip())
- break;
-
- // Update nTime every few seconds
- if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0)
- break; // Recreate the block if the clock has run backwards,
- // so that we can use the correct time.
- if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
- {
- // Changing pblock->nTime can change work required on testnet:
- hashTarget.SetCompact(pblock->nBits);
- }
- }
- }
- }
- catch (const boost::thread_interrupted&)
- {
- LogPrintf("BitcoinMiner terminated\n");
- throw;
- }
- catch (const std::runtime_error &e)
- {
- LogPrintf("BitcoinMiner runtime error: %s\n", e.what());
- return;
- }
-}
-
-void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams)
-{
- static boost::thread_group* minerThreads = NULL;
-
- if (nThreads < 0)
- nThreads = GetNumCores();
-
- if (minerThreads != NULL)
- {
- minerThreads->interrupt_all();
- delete minerThreads;
- minerThreads = NULL;
- }
-
- if (nThreads == 0 || !fGenerate)
- return;
-
- minerThreads = new boost::thread_group();
- for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
-}
diff --git a/src/miner.h b/src/miner.h
index 512494198b..cd0f136625 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -17,9 +17,6 @@ class CScript;
class CWallet;
namespace Consensus { struct Params; };
-static const bool DEFAULT_GENERATE = false;
-static const int DEFAULT_GENERATE_THREADS = 1;
-
static const bool DEFAULT_PRINTPRIORITY = false;
struct CBlockTemplate
@@ -29,8 +26,6 @@ struct CBlockTemplate
std::vector<int64_t> vTxSigOps;
};
-/** Run the miner threads */
-void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn);
/** Modify the extranonce in a block */
diff --git a/src/net.cpp b/src/net.cpp
index d9c4c11737..e8cc753a48 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -79,7 +79,6 @@ bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
CCriticalSection cs_mapLocalHost;
map<CNetAddr, LocalServiceInfo> mapLocalHost;
-static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
@@ -205,7 +204,7 @@ bool IsPeerAddrLocalGood(CNode *pnode)
}
// pushes our own address to a peer
-void AdvertizeLocal(CNode *pnode)
+void AdvertiseLocal(CNode *pnode)
{
if (fListen && pnode->fSuccessfullyConnected)
{
@@ -220,20 +219,12 @@ void AdvertizeLocal(CNode *pnode)
}
if (addrLocal.IsRoutable())
{
- LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString());
+ LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
pnode->PushAddress(addrLocal);
}
}
}
-void SetReachable(enum Network net, bool fFlag)
-{
- LOCK(cs_mapLocalHost);
- vfReachable[net] = fFlag;
- if (net == NET_IPV6 && fFlag)
- vfReachable[NET_IPV4] = true;
-}
-
// learn a new local address
bool AddLocal(const CService& addr, int nScore)
{
@@ -256,7 +247,6 @@ bool AddLocal(const CService& addr, int nScore)
info.nScore = nScore + (fAlready ? 1 : 0);
info.nPort = addr.GetPort();
}
- SetReachable(addr.GetNetwork());
}
return true;
@@ -319,7 +309,7 @@ bool IsLocal(const CService& addr)
bool IsReachable(enum Network net)
{
LOCK(cs_mapLocalHost);
- return vfReachable[net] && !vfLimited[net];
+ return !vfLimited[net];
}
/** check whether a given address is in a network we can probably connect to */
@@ -2063,20 +2053,15 @@ public:
instance_of_cnetcleanup;
-
-
-
-
-
-void RelayTransaction(const CTransaction& tx)
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << tx;
- RelayTransaction(tx, ss);
+ RelayTransaction(tx, feerate, ss);
}
-void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss)
{
CInv inv(MSG_TX, tx.GetHash());
{
@@ -2097,6 +2082,11 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{
if(!pnode->fRelayTxes)
continue;
+ {
+ LOCK(pnode->cs_feeFilter);
+ if (feerate.GetFeePerK() < pnode->minFeeFilter)
+ continue;
+ }
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
@@ -2400,6 +2390,10 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nPingUsecTime = 0;
fPingQueued = false;
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
+ minFeeFilter = 0;
+ lastSentFeeFilter = 0;
+ nextSendTimeFeeFilter = 0;
+
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
diff --git a/src/net.h b/src/net.h
index 833c9cf07c..ab9eb68d85 100644
--- a/src/net.h
+++ b/src/net.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
+#include "amount.h"
#include "bloom.h"
#include "compat.h"
#include "limitedmap.h"
@@ -134,7 +135,7 @@ enum
};
bool IsPeerAddrLocalGood(CNode *pnode);
-void AdvertizeLocal(CNode *pnode);
+void AdvertiseLocal(CNode *pnode);
void SetLimited(enum Network net, bool fLimited = true);
bool IsLimited(enum Network net);
bool IsLimited(const CNetAddr& addr);
@@ -146,7 +147,6 @@ bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
-void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
@@ -416,6 +416,11 @@ public:
int64_t nMinPingUsecTime;
// Whether a ping is requested.
bool fPingQueued;
+ // Minimum fee rate with which to filter inv's to this node
+ CAmount minFeeFilter;
+ CCriticalSection cs_feeFilter;
+ CAmount lastSentFeeFilter;
+ int64_t nextSendTimeFeeFilter;
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
@@ -767,8 +772,8 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx);
-void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index de3c060d6a..7b0e8b7d08 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -8,6 +8,7 @@
#include "amount.h"
#include "primitives/transaction.h"
+#include "random.h"
#include "streams.h"
#include "txmempool.h"
#include "util.h"
@@ -580,3 +581,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein)
priStats.Read(filein);
nBestSeenHeight = nFileBestSeenHeight;
}
+
+FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
+{
+ CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2;
+ feeset.insert(0);
+ for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ feeset.insert(bucketBoundary);
+ }
+}
+
+CAmount FeeFilterRounder::round(CAmount currentMinFee)
+{
+ std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
+ if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) {
+ it--;
+ }
+ return *it;
+}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 3fa31c39e7..cdd984de7d 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -286,4 +286,17 @@ private:
CFeeRate feeLikely, feeUnlikely;
double priLikely, priUnlikely;
};
+
+class FeeFilterRounder
+{
+public:
+ /** Create new FeeFilterRounder */
+ FeeFilterRounder(const CFeeRate& minIncrementalFee);
+
+ /** Quantize a minimum fee for privacy purpose before broadcast **/
+ CAmount round(CAmount currentMinFee);
+
+private:
+ std::set<double> feeset;
+};
#endif /*BITCOIN_POLICYESTIMATOR_H */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 332abc430e..e3ed7be000 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -55,7 +55,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
bool IsStandardTx(const CTransaction& tx, std::string& reason)
{
- if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
+ if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
return false;
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 726864f190..4f9354e36f 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -40,13 +40,15 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
SCRIPT_VERIFY_CLEANSTACK |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
+ SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
SCRIPT_VERIFY_LOW_S;
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
-/** Used as the flags parameter to CheckFinalTx() in non-consensus code */
-static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_MEDIAN_TIME_PAST;
+/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
+static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
+ LOCKTIME_MEDIAN_TIME_PAST;
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
/**
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 59e949d71a..6fb33230a5 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -18,7 +18,7 @@ uint256 CBlockHeader::GetHash() const
std::string CBlock::ToString() const
{
std::stringstream s;
- s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
+ s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 0e93399c08..42276b2bc2 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -21,7 +21,6 @@ class CBlockHeader
{
public:
// header
- static const int32_t CURRENT_VERSION=4;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
@@ -49,7 +48,7 @@ public:
void SetNull()
{
- nVersion = CBlockHeader::CURRENT_VERSION;
+ nVersion = 0;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
nTime = 0;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index aea96d8a12..947f2e6a73 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -37,7 +37,7 @@ std::string CTxIn::ToString() const
str += strprintf(", coinbase %s", HexStr(scriptSig));
else
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
- if (nSequence != std::numeric_limits<unsigned int>::max())
+ if (nSequence != SEQUENCE_FINAL)
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 8bd6d00e2e..149816406a 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -34,7 +34,8 @@ public:
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
- return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
+ int cmp = a.hash.Compare(b.hash);
+ return cmp < 0 || (cmp == 0 && a.n < b.n);
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
@@ -61,13 +62,40 @@ public:
CScript scriptSig;
uint32_t nSequence;
+ /* Setting nSequence to this value for every input in a transaction
+ * disables nLockTime. */
+ static const uint32_t SEQUENCE_FINAL = 0xffffffff;
+
+ /* Below flags apply in the context of BIP 68*/
+ /* If this flag set, CTxIn::nSequence is NOT interpreted as a
+ * relative lock-time. */
+ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
+
+ /* If CTxIn::nSequence encodes a relative lock-time and this flag
+ * is set, the relative lock-time has units of 512 seconds,
+ * otherwise it specifies blocks with a granularity of 1. */
+ static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
+
+ /* If CTxIn::nSequence encodes a relative lock-time, this mask is
+ * applied to extract that lock-time from the sequence field. */
+ static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
+
+ /* In order to use the same number of bits to encode roughly the
+ * same wall-clock duration, and because blocks are naturally
+ * limited to occur every 600s on average, the minimum granularity
+ * for time-based relative lock-time is fixed at 512 seconds.
+ * Converting from CTxIn::nSequence to seconds is performed by
+ * multiplying by 512 = 2^9, or equivalently shifting up by
+ * 9 bits. */
+ static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
+
CTxIn()
{
- nSequence = std::numeric_limits<unsigned int>::max();
+ nSequence = SEQUENCE_FINAL;
}
- explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max());
- CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<uint32_t>::max());
+ explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
+ CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
ADD_SERIALIZE_METHODS;
@@ -78,11 +106,6 @@ public:
READWRITE(nSequence);
}
- bool IsFinal() const
- {
- return (nSequence == std::numeric_limits<uint32_t>::max());
- }
-
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
return (a.prevout == b.prevout &&
@@ -184,8 +207,15 @@ private:
void UpdateHash() const;
public:
+ // Default transaction version.
static const int32_t CURRENT_VERSION=1;
+ // Changing the default transaction version requires a two step process: first
+ // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date
+ // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and
+ // MAX_STANDARD_VERSION will be equal.
+ static const int32_t MAX_STANDARD_VERSION=2;
+
// The local variables are made const to prevent unintended modification
// without updating the cached hash value. However, CTransaction is not
// actually immutable; deserialization and assignment are implemented,
diff --git a/src/protocol.cpp b/src/protocol.cpp
index c1c7c0b96b..8c4bd05725 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -28,13 +28,13 @@ const char *GETADDR="getaddr";
const char *MEMPOOL="mempool";
const char *PING="ping";
const char *PONG="pong";
-const char *ALERT="alert";
const char *NOTFOUND="notfound";
const char *FILTERLOAD="filterload";
const char *FILTERADD="filteradd";
const char *FILTERCLEAR="filterclear";
const char *REJECT="reject";
const char *SENDHEADERS="sendheaders";
+const char *FEEFILTER="feefilter";
};
static const char* ppszTypeName[] =
@@ -64,13 +64,13 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::MEMPOOL,
NetMsgType::PING,
NetMsgType::PONG,
- NetMsgType::ALERT,
NetMsgType::NOTFOUND,
NetMsgType::FILTERLOAD,
NetMsgType::FILTERADD,
NetMsgType::FILTERCLEAR,
NetMsgType::REJECT,
- NetMsgType::SENDHEADERS
+ NetMsgType::SENDHEADERS,
+ NetMsgType::FEEFILTER
};
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
diff --git a/src/protocol.h b/src/protocol.h
index c8b8d20ead..1b049e52af 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -164,13 +164,6 @@ extern const char *PING;
*/
extern const char *PONG;
/**
- * The alert message warns nodes of problems that may affect them or the rest
- * of the network.
- * @since protocol version 311.
- * @see https://bitcoin.org/en/developer-reference#alert
- */
-extern const char *ALERT;
-/**
* The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay.
* @ince protocol version 70001.
@@ -218,7 +211,12 @@ extern const char *REJECT;
* @see https://bitcoin.org/en/developer-reference#sendheaders
*/
extern const char *SENDHEADERS;
-
+/**
+ * The feefilter message tells the receiving peer not to inv us any txs
+ * which do not meet the specified min fee rate.
+ * @since protocol version 70013 as described by BIP133
+ */
+extern const char *FEEFILTER;
};
/* Get a vector of all valid message types (see above) */
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index fb502b3c81..697736cc88 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -8,7 +8,6 @@
#include "guiconstants.h"
#include "peertablemodel.h"
-#include "alert.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
@@ -122,20 +121,8 @@ void ClientModel::updateNumConnections(int numConnections)
Q_EMIT numConnectionsChanged(numConnections);
}
-void ClientModel::updateAlert(const QString &hash, int status)
+void ClientModel::updateAlert()
{
- // Show error message notification for new alert
- if(status == CT_NEW)
- {
- uint256 hash_256;
- hash_256.SetHex(hash.toStdString());
- CAlert alert = CAlert::getAlertByHash(hash_256);
- if(!alert.IsNull())
- {
- Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
- }
- }
-
Q_EMIT alertsChanged(getStatusBarWarnings());
}
@@ -186,11 +173,6 @@ QString ClientModel::formatSubVersion() const
return QString::fromStdString(strSubVersion);
}
-QString ClientModel::formatBuildDate() const
-{
- return QString::fromStdString(CLIENT_DATE);
-}
-
bool ClientModel::isReleaseVersion() const
{
return CLIENT_VERSION_IS_RELEASE;
@@ -206,6 +188,11 @@ QString ClientModel::formatClientStartupTime() const
return QDateTime::fromTime_t(nClientStartupTime).toString();
}
+QString ClientModel::dataDir() const
+{
+ return QString::fromStdString(GetDataDir().string());
+}
+
void ClientModel::updateBanlist()
{
banTableModel->refresh();
@@ -227,12 +214,10 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn
Q_ARG(int, newNumConnections));
}
-static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
+static void NotifyAlertChanged(ClientModel *clientmodel)
{
- qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status);
- QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
- Q_ARG(QString, QString::fromStdString(hash.GetHex())),
- Q_ARG(int, status));
+ qDebug() << "NotifyAlertChanged";
+ QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
}
static void BannedListChanged(ClientModel *clientmodel)
@@ -266,7 +251,7 @@ void ClientModel::subscribeToCoreSignals()
// Connect signals to client
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
- uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
}
@@ -276,7 +261,7 @@ void ClientModel::unsubscribeFromCoreSignals()
// Disconnect signals from client
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
- uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 62c9f71ac7..109f95a2a7 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -72,10 +72,10 @@ public:
QString formatFullVersion() const;
QString formatSubVersion() const;
- QString formatBuildDate() const;
bool isReleaseVersion() const;
QString clientName() const;
QString formatClientStartupTime() const;
+ QString dataDir() const;
private:
OptionsModel *optionsModel;
@@ -103,7 +103,7 @@ Q_SIGNALS:
public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
- void updateAlert(const QString &hash, int status);
+ void updateAlert();
void updateBanlist();
};
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7393c83c7d..f909499952 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -796,7 +796,7 @@ void CoinControlDialog::updateView()
}
// set checkbox
- if (coinControl->IsSelected(txhash, out.i))
+ if (coinControl->IsSelected(COutPoint(txhash, out.i)))
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
}
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index febbaeda1b..c17efcf1b3 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>740</width>
- <height>450</height>
+ <height>430</height>
</rect>
</property>
<property name="windowTitle">
@@ -113,32 +113,6 @@
</widget>
</item>
<item row="4" column="0">
- <widget class="QLabel" name="label_14">
- <property name="text">
- <string>Using OpenSSL version</string>
- </property>
- <property name="indent">
- <number>10</number>
- </property>
- </widget>
- </item>
- <item row="4" column="1" colspan="2">
- <widget class="QLabel" name="openSSLVersion">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="text">
- <string>N/A</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
<widget class="QLabel" name="label_berkeleyDBVersion">
<property name="text">
<string>Using BerkeleyDB version</string>
@@ -148,7 +122,7 @@
</property>
</widget>
</item>
- <item row="5" column="1" colspan="2">
+ <item row="4" column="1" colspan="2">
<widget class="QLabel" name="berkeleyDBVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -164,15 +138,15 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="5" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
- <string>Build date</string>
+ <string>Datadir</string>
</property>
</widget>
</item>
- <item row="6" column="1" colspan="2">
- <widget class="QLabel" name="buildDate">
+ <item row="5" column="1" colspan="2">
+ <widget class="QLabel" name="dataDir">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -182,19 +156,22 @@
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
- <item row="7" column="1" colspan="2">
+ <item row="6" column="1" colspan="2">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -210,14 +187,27 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="7" column="0">
+ <widget class="QLabel" name="labelNetwork">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Network</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
- <item row="9" column="1" colspan="2">
+ <item row="8" column="1" colspan="2">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -233,14 +223,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
- <item row="10" column="1" colspan="2">
+ <item row="9" column="1" colspan="2">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -256,7 +246,7 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
@@ -269,14 +259,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
- <item row="12" column="1" colspan="2">
+ <item row="11" column="1" colspan="2">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -292,14 +282,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="labelLastBlockTime">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="13" column="1" colspan="2">
+ <item row="12" column="1" colspan="2">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -315,7 +305,7 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="labelMempoolTitle">
<property name="font">
<font>
@@ -328,14 +318,14 @@
</property>
</widget>
</item>
- <item row="15" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="labelNumberOfTransactions">
<property name="text">
<string>Current number of transactions</string>
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="14" column="1">
<widget class="QLabel" name="mempoolNumberTxs">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -351,27 +341,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
- <widget class="QLabel" name="labelNetwork">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Network</string>
- </property>
- </widget>
- </item>
- <item row="16" column="0">
+ <item row="15" column="0">
<widget class="QLabel" name="labelMemoryUsage">
<property name="text">
<string>Memory usage</string>
</property>
</widget>
</item>
- <item row="16" column="1">
+ <item row="15" column="1">
<widget class="QLabel" name="mempoolSize">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -387,7 +364,7 @@
</property>
</widget>
</item>
- <item row="14" column="2" rowspan="3">
+ <item row="13" column="2" rowspan="3">
<layout class="QVBoxLayout" name="verticalLayoutDebugButton">
<property name="spacing">
<number>3</number>
@@ -427,7 +404,7 @@
</item>
</layout>
</item>
- <item row="18" column="0">
+ <item row="16" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 8911b41cbf..12d6a62c08 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -617,7 +617,7 @@
<x>0</x>
<y>0</y>
<width>830</width>
- <height>68</height>
+ <height>104</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
@@ -1167,59 +1167,6 @@
</item>
</layout>
</item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayoutFee5" stretch="0,0,0">
- <property name="spacing">
- <number>8</number>
- </property>
- <property name="bottomMargin">
- <number>4</number>
- </property>
- <item>
- <widget class="QCheckBox" name="checkBoxFreeTx">
- <property name="text">
- <string>Send as zero-fee transaction if possible</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="labelFreeTx">
- <property name="text">
- <string>(confirmation may take longer)</string>
- </property>
- <property name="margin">
- <number>5</number>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacerFee5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>1</width>
- <height>1</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacerFee2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>1</width>
- <height>1</height>
- </size>
- </property>
- </spacer>
- </item>
</layout>
</widget>
</item>
diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png
index 83eb3c07ee..4143be8bac 100644
--- a/src/qt/res/icons/about.png
+++ b/src/qt/res/icons/about.png
Binary files differ
diff --git a/src/qt/res/icons/chevron.png b/src/qt/res/icons/chevron.png
index ac985052c1..2309fb38e2 100644
--- a/src/qt/res/icons/chevron.png
+++ b/src/qt/res/icons/chevron.png
Binary files differ
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index c18c405256..d8647d902a 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -36,6 +36,7 @@
#include <QThread>
#include <QTime>
#include <QTimer>
+#include <QStringList>
#if QT_VERSION < 0x050000
#include <QUrl>
@@ -275,13 +276,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear()));
// set library version labels
-
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
- ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
-#else
- ui->openSSLVersion->setText(OpenSSL_version(OPENSSL_VERSION));
-#endif
-
#ifdef ENABLE_WALLET
ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0));
#else
@@ -450,9 +444,23 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->clientVersion->setText(model->formatFullVersion());
ui->clientUserAgent->setText(model->formatSubVersion());
ui->clientName->setText(model->clientName());
- ui->buildDate->setText(model->formatBuildDate());
+ ui->dataDir->setText(model->dataDir());
ui->startupTime->setText(model->formatClientStartupTime());
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
+
+ //Setup autocomplete and attach it
+ QStringList wordList;
+ std::vector<std::string> commandList = tableRPC.listCommands();
+ for (size_t i = 0; i < commandList.size(); ++i)
+ {
+ wordList << commandList[i].c_str();
+ }
+
+ autoCompleter = new QCompleter(wordList, this);
+ ui->lineEdit->setCompleter(autoCompleter);
+
+ // clear the lineEdit after activating from QCompleter
+ connect(autoCompleter, SIGNAL(activated(const QString&)), ui->lineEdit, SLOT(clear()), Qt::QueuedConnection);
}
}
@@ -497,16 +505,19 @@ void RPCConsole::setFontSize(int newSize)
// clear console (reset icon sizes, default stylesheet) and re-add the content
float oldPosFactor = 1.0 / ui->messagesWidget->verticalScrollBar()->maximum() * ui->messagesWidget->verticalScrollBar()->value();
- clear();
+ clear(false);
ui->messagesWidget->setHtml(str);
ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
}
-void RPCConsole::clear()
+void RPCConsole::clear(bool clearHistory)
{
ui->messagesWidget->clear();
- history.clear();
- historyPtr = 0;
+ if(clearHistory)
+ {
+ history.clear();
+ historyPtr = 0;
+ }
ui->lineEdit->clear();
ui->lineEdit->setFocus();
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 648e32638f..2923587bc8 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -11,6 +11,7 @@
#include "net.h"
#include <QWidget>
+#include <QCompleter>
class ClientModel;
class PlatformStyle;
@@ -77,7 +78,7 @@ private Q_SLOTS:
void clearSelectedNode();
public Q_SLOTS:
- void clear();
+ void clear(bool clearHistory = true);
void fontBigger();
void fontSmaller();
void setFontSize(int newSize);
@@ -138,6 +139,7 @@ private:
QMenu *peersTableContextMenu;
QMenu *banTableContextMenu;
int consoleFontSize;
+ QCompleter *autoCompleter;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 5fc7b57a41..780a6c9709 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -104,8 +104,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
if (!settings.contains("fPayOnlyMinFee"))
settings.setValue("fPayOnlyMinFee", false);
- if (!settings.contains("fSendFreeTransactions"))
- settings.setValue("fSendFreeTransactions", false);
ui->groupFee->setId(ui->radioSmartFee, 0);
ui->groupFee->setId(ui->radioCustomFee, 1);
ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
@@ -115,7 +113,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
- ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool());
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}
@@ -170,8 +167,6 @@ void SendCoinsDialog::setModel(WalletModel *model)
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
- connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
@@ -189,7 +184,6 @@ SendCoinsDialog::~SendCoinsDialog()
settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
- settings.setValue("fSendFreeTransactions", ui->checkBoxFreeTx->isChecked());
delete ui;
}
@@ -605,8 +599,6 @@ void SendCoinsDialog::updateGlobalFeeVariables()
// set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB
CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0;
}
-
- fSendFreeTransactions = ui->checkBoxFreeTx->isChecked();
}
void SendCoinsDialog::updateFeeMinimizedLabel()
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 5cb4cd5af7..5abefc144e 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -240,7 +240,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
- strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
+ strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>";
+ strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 5b16b108e6..97b77cc93d 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -260,11 +260,10 @@ bool TransactionRecord::statusUpdateNeeded()
QString TransactionRecord::getTxID() const
{
- return formatSubTxId(hash, idx);
+ return QString::fromStdString(hash.ToString());
}
-QString TransactionRecord::formatSubTxId(const uint256 &hash, int vout)
+int TransactionRecord::getOutputIndex() const
{
- return QString::fromStdString(hash.ToString() + strprintf("-%03d", vout));
+ return idx;
}
-
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 49753ee31f..95ab98c10d 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -128,8 +128,8 @@ public:
/** Return the unique identifier for this transaction (part) */
QString getTxID() const;
- /** Format subtransaction id */
- static QString formatSubTxId(const uint256 &hash, int vout);
+ /** Return the output index of the subtransaction */
+ int getOutputIndex() const;
/** Update status from core wallet tx.
*/
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 1647b2a6fe..d2a52b3022 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -609,6 +609,34 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return QString::fromStdString(rec->hash.ToString());
case TxHexRole:
return priv->getTxHex(rec);
+ case TxPlainTextRole:
+ {
+ QString details;
+ QDateTime date = QDateTime::fromTime_t(static_cast<uint>(rec->time));
+ QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
+
+ details.append(date.toString("M/d/yy HH:mm"));
+ details.append(" ");
+ details.append(formatTxStatus(rec));
+ details.append(". ");
+ if(!formatTxType(rec).isEmpty()) {
+ details.append(formatTxType(rec));
+ details.append(" ");
+ }
+ if(!rec->address.empty()) {
+ if(txLabel.isEmpty())
+ details.append(tr("(no label)") + " ");
+ else {
+ details.append("(");
+ details.append(txLabel);
+ details.append(") ");
+ }
+ details.append(QString::fromStdString(rec->address));
+ details.append(" ");
+ }
+ details.append(formatTxAmount(rec, false, BitcoinUnits::separatorNever));
+ return details;
+ }
case ConfirmedRole:
return rec->status.countsForBalance;
case FormattedAmountRole:
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index fe59a15f6a..6932646e1e 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -62,6 +62,8 @@ public:
TxHashRole,
/** Transaction data, hex-encoded */
TxHexRole,
+ /** Whole transaction as plain text */
+ TxPlainTextRole,
/** Is transaction confirmed? */
ConfirmedRole,
/** Formatted amount, without brackets when unconfirmed */
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 4a9a198216..a4d4c7a35f 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -142,6 +142,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
+ QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
QAction *editLabelAction = new QAction(tr("Edit label"), this);
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
@@ -151,6 +152,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
contextMenu->addAction(copyAmountAction);
contextMenu->addAction(copyTxIDAction);
contextMenu->addAction(copyTxHexAction);
+ contextMenu->addAction(copyTxPlainText);
contextMenu->addAction(editLabelAction);
contextMenu->addAction(showDetailsAction);
@@ -173,6 +175,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID()));
connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex()));
+ connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText()));
connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
}
@@ -388,6 +391,11 @@ void TransactionView::copyTxHex()
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole);
}
+void TransactionView::copyTxPlainText()
+{
+ GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
+}
+
void TransactionView::editLabel()
{
if(!transactionView->selectionModel() ||!model)
@@ -526,12 +534,8 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event)
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier))
{
- QModelIndex i = this->transactionView->currentIndex();
- if (i.isValid() && i.column() == TransactionTableModel::Amount)
- {
- GUIUtil::setClipboard(i.data(TransactionTableModel::FormattedAmountRole).toString());
- return true;
- }
+ GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
+ return true;
}
}
return QWidget::eventFilter(obj, event);
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index cf2b8fbcd4..2cfbd471b0 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -94,6 +94,7 @@ private Q_SLOTS:
void copyAmount();
void copyTxID();
void copyTxHex();
+ void copyTxPlainText();
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
diff --git a/src/rest.cpp b/src/rest.cpp
index ebdccc9402..2dff8d7dad 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -273,6 +273,9 @@ static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPa
return rest_block(req, strURIPart, false);
}
+// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
+UniValue getblockchaininfo(const UniValue& params, bool fHelp);
+
static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index de6bda4ea1..f1c9d9f7ab 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -89,7 +89,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hash", block.GetHash().GetHex()));
+ result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
// Only report confirmations if the block is on the main chain
if (chainActive.Contains(blockindex))
@@ -604,6 +604,20 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
return rv;
}
+static UniValue BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
+{
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("id", name));
+ switch (VersionBitsTipState(consensusParams, id)) {
+ case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break;
+ case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break;
+ case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break;
+ case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break;
+ case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break;
+ }
+ return rv;
+}
+
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -634,6 +648,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" },\n"
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
+ " ],\n"
+ " \"bip9_softforks\": [ (array) status of BIP9 softforks in progress\n"
+ " {\n"
+ " \"id\": \"xxxx\", (string) name of the softfork\n"
+ " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n"
+ " }\n"
" ]\n"
"}\n"
"\nExamples:\n"
@@ -657,10 +677,13 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
UniValue softforks(UniValue::VARR);
+ UniValue bip9_softforks(UniValue::VARR);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
+ bip9_softforks.push_back(BIP9SoftForkDesc("csv", consensusParams, Consensus::DEPLOYMENT_CSV));
obj.push_back(Pair("softforks", softforks));
+ obj.push_back(Pair("bip9_softforks", bip9_softforks));
if (fPruneMode)
{
@@ -889,3 +912,31 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
return NullUniValue;
}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, true },
+ { "blockchain", "getbestblockhash", &getbestblockhash, true },
+ { "blockchain", "getblockcount", &getblockcount, true },
+ { "blockchain", "getblock", &getblock, true },
+ { "blockchain", "getblockhash", &getblockhash, true },
+ { "blockchain", "getblockheader", &getblockheader, true },
+ { "blockchain", "getchaintips", &getchaintips, true },
+ { "blockchain", "getdifficulty", &getdifficulty, true },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, true },
+ { "blockchain", "getrawmempool", &getrawmempool, true },
+ { "blockchain", "gettxout", &gettxout, true },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
+ { "blockchain", "verifychain", &verifychain, true },
+
+ /* Not shown in help */
+ { "hidden", "invalidateblock", &invalidateblock, true },
+ { "hidden", "reconsiderblock", &reconsiderblock, true },
+};
+
+void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index b0e9b6f153..89420b93d7 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -27,9 +27,11 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "stop", 0 },
{ "setmocktime", 0 },
{ "getaddednodeinfo", 0 },
- { "setgenerate", 0 },
- { "setgenerate", 1 },
{ "generate", 0 },
+ { "generate", 1 },
+ { "generatetoaddress", 0 },
+ { "generatetoaddress", 1 },
+ { "generatetoaddress", 2 },
{ "getnetworkhashps", 0 },
{ "getnetworkhashps", 1 },
{ "sendtoaddress", 1 },
@@ -160,4 +162,3 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
return params;
}
-
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 996b7f9cbd..b63ee22889 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "base58.h"
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
@@ -68,7 +69,7 @@ UniValue GetNetworkHashPS(int lookup, int height) {
arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
int64_t timeDiff = maxTime - minTime;
- return (int64_t)(workDiff.getdouble() / timeDiff);
+ return workDiff.getdouble() / timeDiff;
}
UniValue getnetworkhashps(const UniValue& params, bool fHelp)
@@ -93,59 +94,12 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
-UniValue getgenerate(const UniValue& params, bool fHelp)
+UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getgenerate\n"
- "\nReturn if the server is set to generate coins or not. The default is false.\n"
- "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n"
- "It can also be set with the setgenerate call.\n"
- "\nResult\n"
- "true|false (boolean) If the server is set to generate coins or not\n"
- "\nExamples:\n"
- + HelpExampleCli("getgenerate", "")
- + HelpExampleRpc("getgenerate", "")
- );
-
- LOCK(cs_main);
- return GetBoolArg("-gen", DEFAULT_GENERATE);
-}
-
-UniValue generate(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 1 || params.size() > 1)
- throw runtime_error(
- "generate numblocks\n"
- "\nMine blocks immediately (before the RPC call returns)\n"
- "\nNote: this function can only be used on the regtest network\n"
- "\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
- "\nResult\n"
- "[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
- "\nGenerate 11 blocks\n"
- + HelpExampleCli("generate", "11")
- );
-
- if (!Params().MineBlocksOnDemand())
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest");
-
+ static const int nInnerLoopCount = 0x10000;
int nHeightStart = 0;
int nHeightEnd = 0;
int nHeight = 0;
- int nGenerate = params[0].get_int();
-
- boost::shared_ptr<CReserveScript> coinbaseScript;
- GetMainSignals().ScriptForMining(coinbaseScript);
-
- // If the keypool is exhausted, no script is returned at all. Catch this.
- if (!coinbaseScript)
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
-
- //throw an error if no script was provided
- if (coinbaseScript->reserveScript.empty())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked
LOCK(cs_main);
@@ -165,10 +119,15 @@ UniValue generate(const UniValue& params, bool fHelp)
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
}
- while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
- // Yes, there is a chance every nonce could fail to satisfy the -regtest
- // target -- 1 in 2^(2^32). That ain't gonna happen.
+ while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
++pblock->nNonce;
+ --nMaxTries;
+ }
+ if (nMaxTries == 0) {
+ break;
+ }
+ if (pblock->nNonce == nInnerLoopCount) {
+ continue;
}
CValidationState state;
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
@@ -176,54 +135,82 @@ UniValue generate(const UniValue& params, bool fHelp)
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
- //mark script as important because it was used at least for one coinbase output
- coinbaseScript->KeepScript();
+ //mark script as important because it was used at least for one coinbase output if the script came from the wallet
+ if (keepScript)
+ {
+ coinbaseScript->KeepScript();
+ }
}
return blockHashes;
}
-UniValue setgenerate(const UniValue& params, bool fHelp)
+UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "setgenerate generate ( genproclimit )\n"
- "\nSet 'generate' true or false to turn generation on or off.\n"
- "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n"
- "See the getgenerate call for the current setting.\n"
+ "generate numblocks ( maxtries )\n"
+ "\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
"\nArguments:\n"
- "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"
+ "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
- "\nSet the generation on with a limit of one processor\n"
- + HelpExampleCli("setgenerate", "true 1") +
- "\nCheck the setting\n"
- + HelpExampleCli("getgenerate", "") +
- "\nTurn off generation\n"
- + HelpExampleCli("setgenerate", "false") +
- "\nUsing json rpc\n"
- + HelpExampleRpc("setgenerate", "true, 1")
+ "\nGenerate 11 blocks\n"
+ + HelpExampleCli("generate", "11")
);
- if (Params().MineBlocksOnDemand())
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network");
+ int nGenerate = params[0].get_int();
+ uint64_t nMaxTries = 1000000;
+ if (params.size() > 1) {
+ nMaxTries = params[1].get_int();
+ }
- bool fGenerate = true;
- if (params.size() > 0)
- fGenerate = params[0].get_bool();
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
- int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS);
- if (params.size() > 1)
- {
- nGenProcLimit = params[1].get_int();
- if (nGenProcLimit == 0)
- fGenerate = false;
+ // If the keypool is exhausted, no script is returned at all. Catch this.
+ if (!coinbaseScript)
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+
+ //throw an error if no script was provided
+ if (coinbaseScript->reserveScript.empty())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
+
+ return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
+}
+
+UniValue generatetoaddress(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ throw runtime_error(
+ "generatetoaddress numblocks address (maxtries)\n"
+ "\nMine blocks immediately to a specified address (before the RPC call returns)\n"
+ "\nArguments:\n"
+ "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. address (string, required) The address to send the newly generated bitcoin to.\n"
+ "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
+ "\nExamples:\n"
+ "\nGenerate 11 blocks to myaddress\n"
+ + HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
+ );
+
+ int nGenerate = params[0].get_int();
+ uint64_t nMaxTries = 1000000;
+ if (params.size() > 2) {
+ nMaxTries = params[2].get_int();
}
- mapArgs["-gen"] = (fGenerate ? "1" : "0");
- mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
- GenerateBitcoins(fGenerate, nGenProcLimit, Params());
+ CBitcoinAddress address(params[1].get_str());
+ if (!address.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
+
+ boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
+ coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
- return NullUniValue;
+ return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
UniValue getmininginfo(const UniValue& params, bool fHelp)
@@ -239,8 +226,6 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
" \"errors\": \"...\" (string) Current errors\n"
- " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n"
- " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
@@ -259,12 +244,10 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
- obj.push_back(Pair("generate", getgenerate(params, false)));
return obj;
}
@@ -798,3 +781,27 @@ UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
result.push_back(Pair("blocks", answerFound));
return result;
}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "mining", "getnetworkhashps", &getnetworkhashps, true },
+ { "mining", "getmininginfo", &getmininginfo, true },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true },
+ { "mining", "getblocktemplate", &getblocktemplate, true },
+ { "mining", "submitblock", &submitblock, true },
+
+ { "generating", "generate", &generate, true },
+ { "generating", "generatetoaddress", &generatetoaddress, true },
+
+ { "util", "estimatefee", &estimatefee, true },
+ { "util", "estimatepriority", &estimatepriority, true },
+ { "util", "estimatesmartfee", &estimatesmartfee, true },
+ { "util", "estimatesmartpriority", &estimatesmartpriority, true },
+};
+
+void RegisterMiningRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 0aab9c3043..e8a099b445 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -396,3 +396,21 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
return NullUniValue;
}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */
+ { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, true },
+ { "util", "verifymessage", &verifymessage, true },
+
+ /* Not shown in help */
+ { "hidden", "setmocktime", &setmocktime, true },
+};
+
+void RegisterMiscRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 065214a98a..017cd6ca32 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -626,3 +626,25 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
return NullUniValue;
}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "network", "getconnectioncount", &getconnectioncount, true },
+ { "network", "ping", &ping, true },
+ { "network", "getpeerinfo", &getpeerinfo, true },
+ { "network", "addnode", &addnode, true },
+ { "network", "disconnectnode", &disconnectnode, true },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, true },
+ { "network", "getnettotals", &getnettotals, true },
+ { "network", "getnetworkinfo", &getnetworkinfo, true },
+ { "network", "setban", &setban, true },
+ { "network", "listbanned", &listbanned, true },
+ { "network", "clearbanned", &clearbanned, true },
+};
+
+void RegisterNetRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index de89fdeb0f..de8cd68f66 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -303,7 +303,8 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
UniValue res(UniValue::VARR);
vector<uint256> vMatch;
- if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
+ vector<unsigned int> vIndex;
+ if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
LOCK(cs_main);
@@ -818,11 +819,12 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
+ CFeeRate txFeeRate = CFeeRate(0);
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -835,7 +837,27 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
return hashTx.GetHex();
}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, true },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true },
+ { "rawtransactions", "decodescript", &decodescript, true },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, true },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, true },
+};
+
+void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/register.h b/src/rpc/register.h
new file mode 100644
index 0000000000..01aa58a25d
--- /dev/null
+++ b/src/rpc/register.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPCREGISTER_H
+#define BITCOIN_RPCREGISTER_H
+
+/** These are in one header file to avoid creating tons of single-function
+ * headers for everything under src/rpc/ */
+class CRPCTable;
+
+/** Register block chain RPC commands */
+void RegisterBlockchainRPCCommands(CRPCTable &tableRPC);
+/** Register P2P networking RPC commands */
+void RegisterNetRPCCommands(CRPCTable &tableRPC);
+/** Register miscellaneous RPC commands */
+void RegisterMiscRPCCommands(CRPCTable &tableRPC);
+/** Register mining RPC commands */
+void RegisterMiningRPCCommands(CRPCTable &tableRPC);
+/** Register raw transaction RPC commands */
+void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
+
+static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
+{
+ RegisterBlockchainRPCCommands(tableRPC);
+ RegisterNetRPCCommands(tableRPC);
+ RegisterMiscRPCCommands(tableRPC);
+ RegisterMiningRPCCommands(tableRPC);
+ RegisterRawTransactionRPCCommands(tableRPC);
+}
+
+#endif
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index b2d4559ccd..8326fe14d2 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -256,73 +256,8 @@ static const CRPCCommand vRPCCommands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
- { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */
{ "control", "help", &help, true },
{ "control", "stop", &stop, true },
-
- /* P2P networking */
- { "network", "getnetworkinfo", &getnetworkinfo, true },
- { "network", "addnode", &addnode, true },
- { "network", "disconnectnode", &disconnectnode, true },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true },
- { "network", "getconnectioncount", &getconnectioncount, true },
- { "network", "getnettotals", &getnettotals, true },
- { "network", "getpeerinfo", &getpeerinfo, true },
- { "network", "ping", &ping, true },
- { "network", "setban", &setban, true },
- { "network", "listbanned", &listbanned, true },
- { "network", "clearbanned", &clearbanned, true },
-
- /* Block chain and UTXO */
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true },
- { "blockchain", "getbestblockhash", &getbestblockhash, true },
- { "blockchain", "getblockcount", &getblockcount, true },
- { "blockchain", "getblock", &getblock, true },
- { "blockchain", "getblockhash", &getblockhash, true },
- { "blockchain", "getblockheader", &getblockheader, true },
- { "blockchain", "getchaintips", &getchaintips, true },
- { "blockchain", "getdifficulty", &getdifficulty, true },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true },
- { "blockchain", "getrawmempool", &getrawmempool, true },
- { "blockchain", "gettxout", &gettxout, true },
- { "blockchain", "gettxoutproof", &gettxoutproof, true },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
- { "blockchain", "verifychain", &verifychain, true },
-
- /* Mining */
- { "mining", "getblocktemplate", &getblocktemplate, true },
- { "mining", "getmininginfo", &getmininginfo, true },
- { "mining", "getnetworkhashps", &getnetworkhashps, true },
- { "mining", "prioritisetransaction", &prioritisetransaction, true },
- { "mining", "submitblock", &submitblock, true },
-
- /* Coin generation */
- { "generating", "getgenerate", &getgenerate, true },
- { "generating", "setgenerate", &setgenerate, true },
- { "generating", "generate", &generate, true },
-
- /* Raw transactions */
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true },
- { "rawtransactions", "decodescript", &decodescript, true },
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
-
- /* Utility functions */
- { "util", "createmultisig", &createmultisig, true },
- { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
- { "util", "verifymessage", &verifymessage, true },
- { "util", "estimatefee", &estimatefee, true },
- { "util", "estimatepriority", &estimatepriority, true },
- { "util", "estimatesmartfee", &estimatesmartfee, true },
- { "util", "estimatesmartpriority", &estimatesmartpriority, true },
-
- /* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true },
- { "hidden", "reconsiderblock", &reconsiderblock, true },
- { "hidden", "setmocktime", &setmocktime, true },
};
CRPCTable::CRPCTable()
@@ -499,6 +434,17 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
g_rpcSignals.PostCommand(*pcmd);
}
+std::vector<std::string> CRPCTable::listCommands() const
+{
+ std::vector<std::string> commandList;
+ typedef std::map<std::string, const CRPCCommand*> commandMap;
+
+ std::transform( mapCommands.begin(), mapCommands.end(),
+ std::back_inserter(commandList),
+ boost::bind(&commandMap::value_type::first,_1) );
+ return commandList;
+}
+
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
{
return "> bitcoin-cli " + methodname + " " + args + "\n";
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 99ffad5d40..a7ed710ce6 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -145,6 +145,12 @@ public:
*/
UniValue execute(const std::string &method, const UniValue &params) const;
+ /**
+ * Returns a list of registered commands
+ * @returns List of registered commands.
+ */
+ std::vector<std::string> listCommands() const;
+
/**
* Appends a CRPCCommand to the dispatch table.
@@ -175,66 +181,6 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri
extern void EnsureWalletIsUnlocked();
-extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpc/net.cpp
-extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
-extern UniValue ping(const UniValue& params, bool fHelp);
-extern UniValue addnode(const UniValue& params, bool fHelp);
-extern UniValue disconnectnode(const UniValue& params, bool fHelp);
-extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
-extern UniValue getnettotals(const UniValue& params, bool fHelp);
-extern UniValue setban(const UniValue& params, bool fHelp);
-extern UniValue listbanned(const UniValue& params, bool fHelp);
-extern UniValue clearbanned(const UniValue& params, bool fHelp);
-
-extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpc/mining.cpp
-extern UniValue setgenerate(const UniValue& params, bool fHelp);
-extern UniValue generate(const UniValue& params, bool fHelp);
-extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
-extern UniValue getmininginfo(const UniValue& params, bool fHelp);
-extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
-extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
-extern UniValue submitblock(const UniValue& params, bool fHelp);
-extern UniValue estimatefee(const UniValue& params, bool fHelp);
-extern UniValue estimatepriority(const UniValue& params, bool fHelp);
-extern UniValue estimatesmartfee(const UniValue& params, bool fHelp);
-extern UniValue estimatesmartpriority(const UniValue& params, bool fHelp);
-
-extern UniValue verifymessage(const UniValue& params, bool fHelp);
-extern UniValue createmultisig(const UniValue& params, bool fHelp);
-extern UniValue validateaddress(const UniValue& params, bool fHelp);
-extern UniValue getinfo(const UniValue& params, bool fHelp);
-extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
-extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
-extern UniValue setmocktime(const UniValue& params, bool fHelp);
-
-extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rpc/rawtransaction.cpp
-extern UniValue listunspent(const UniValue& params, bool fHelp);
-extern UniValue lockunspent(const UniValue& params, bool fHelp);
-extern UniValue listlockunspent(const UniValue& params, bool fHelp);
-extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
-extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
-extern UniValue decodescript(const UniValue& params, bool fHelp);
-extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
-extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
-extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
-extern UniValue verifytxoutproof(const UniValue& params, bool fHelp);
-
-extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp
-extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
-extern UniValue getdifficulty(const UniValue& params, bool fHelp);
-extern UniValue settxfee(const UniValue& params, bool fHelp);
-extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
-extern UniValue getrawmempool(const UniValue& params, bool fHelp);
-extern UniValue getblockhash(const UniValue& params, bool fHelp);
-extern UniValue getblockheader(const UniValue& params, bool fHelp);
-extern UniValue getblock(const UniValue& params, bool fHelp);
-extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
-extern UniValue gettxout(const UniValue& params, bool fHelp);
-extern UniValue verifychain(const UniValue& params, bool fHelp);
-extern UniValue getchaintips(const UniValue& params, bool fHelp);
-extern UniValue invalidateblock(const UniValue& params, bool fHelp);
-extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
-
bool StartRPC();
void InterruptRPC();
void StopRPC();
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index a928223268..149a4f0156 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -165,7 +165,10 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);
- return CPubKey::CheckLowS(vchSigCopy);
+ if (!CPubKey::CheckLowS(vchSigCopy)) {
+ return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
+ }
+ return true;
}
bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
@@ -370,7 +373,44 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
break;
}
- case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+ case OP_CHECKSEQUENCEVERIFY:
+ {
+ if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
+ // not enabled; treat as a NOP3
+ if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
+ return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
+ }
+ break;
+ }
+
+ if (stack.size() < 1)
+ return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
+
+ // nSequence, like nLockTime, is a 32-bit unsigned integer
+ // field. See the comment in CHECKLOCKTIMEVERIFY regarding
+ // 5-byte numeric operands.
+ const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);
+
+ // In the rare event that the argument may be < 0 due to
+ // some arithmetic being done first, you can always use
+ // 0 MAX CHECKSEQUENCEVERIFY.
+ if (nSequence < 0)
+ return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
+
+ // To provide for future soft-fork extensibility, if the
+ // operand has the disabled lock-time flag set,
+ // CHECKSEQUENCEVERIFY behaves as a NOP.
+ if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
+ break;
+
+ // Compare the specified sequence number with the input.
+ if (!checker.CheckSequence(nSequence))
+ return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
+
+ break;
+ }
+
+ case OP_NOP1: case OP_NOP4: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -1147,12 +1187,57 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
- if (txTo->vin[nIn].IsFinal())
+ if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence)
return false;
return true;
}
+bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
+{
+ // Relative lock times are supported by comparing the passed
+ // in operand to the sequence number of the input.
+ const int64_t txToSequence = (int64_t)txTo->vin[nIn].nSequence;
+
+ // Fail if the transaction's version number is not set high
+ // enough to trigger BIP 68 rules.
+ if (static_cast<uint32_t>(txTo->nVersion) < 2)
+ return false;
+
+ // Sequence numbers with their most significant bit set are not
+ // consensus constrained. Testing that the transaction's sequence
+ // number do not have this bit set prevents using this property
+ // to get around a CHECKSEQUENCEVERIFY check.
+ if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG)
+ return false;
+
+ // Mask off any bits that do not have consensus-enforced meaning
+ // before doing the integer comparisons
+ const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;
+ const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;
+ const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;
+
+ // There are two kinds of nSequence: lock-by-blockheight
+ // and lock-by-blocktime, distinguished by whether
+ // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
+ //
+ // We want to compare apples to apples, so fail the script
+ // unless the type of nSequenceMasked being tested is the same as
+ // the nSequenceMasked in the transaction.
+ if (!(
+ (txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) ||
+ (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)
+ )) {
+ return false;
+ }
+
+ // Now that we know we're comparing apples-to-apples, the
+ // comparison is a simple numeric one.
+ if (nSequenceMasked > txToSequenceMasked)
+ return false;
+
+ return true;
+}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 7b34547ffb..e5cb7290f2 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -81,6 +81,11 @@ enum
//
// See BIP65 for details.
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
+
+ // support CHECKSEQUENCEVERIFY opcode
+ //
+ // See BIP112 for details
+ SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
};
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
@@ -100,6 +105,11 @@ public:
return false;
}
+ virtual bool CheckSequence(const CScriptNum& nSequence) const
+ {
+ return false;
+ }
+
virtual ~BaseSignatureChecker() {}
};
@@ -116,6 +126,7 @@ public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
+ bool CheckSequence(const CScriptNum& nSequence) const;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
diff --git a/src/script/script.h b/src/script/script.h
index 6551eea30d..d2a68a07ba 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -165,6 +165,7 @@ enum opcodetype
OP_CHECKLOCKTIMEVERIFY = 0xb1,
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
OP_NOP3 = 0xb2,
+ OP_CHECKSEQUENCEVERIFY = OP_NOP3,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
OP_NOP6 = 0xb5,
@@ -259,6 +260,11 @@ public:
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
+ inline CScriptNum operator&( const int64_t& rhs) const { return CScriptNum(m_value & rhs);}
+ inline CScriptNum operator&( const CScriptNum& rhs) const { return operator&(rhs.m_value); }
+
+ inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); }
+
inline CScriptNum operator-() const
{
assert(m_value != std::numeric_limits<int64_t>::min());
@@ -287,6 +293,12 @@ public:
return *this;
}
+ inline CScriptNum& operator&=( const int64_t& rhs)
+ {
+ m_value &= rhs;
+ return *this;
+ }
+
int getint() const
{
if (m_value > std::numeric_limits<int>::max())
diff --git a/src/script/script_error.h b/src/script/script_error.h
index bb10b8a293..26df33932f 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -35,7 +35,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
- /* OP_CHECKLOCKTIMEVERIFY */
+ /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */
SCRIPT_ERR_NEGATIVE_LOCKTIME,
SCRIPT_ERR_UNSATISFIED_LOCKTIME,
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 0895ef3326..70f1f12273 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -4,193 +4,16 @@
// Unit tests for alert system
-#include "alert.h"
-#include "chain.h"
#include "chainparams.h"
-#include "clientversion.h"
-#include "data/alertTests.raw.h"
#include "main.h" // For PartitionCheck
-#include "serialize.h"
-#include "streams.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include "test/testutil.h"
#include "test/test_bitcoin.h"
-#include <fstream>
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#if 0
-//
-// alertTests contains 7 alerts, generated with this code:
-// (SignAndSave code not shown, alert signing key is secret)
-//
-{
- CAlert alert;
- alert.nRelayUntil = 60;
- alert.nExpiration = 24 * 60 * 60;
- alert.nID = 1;
- alert.nCancel = 0; // cancels previous messages up to this ID number
- alert.nMinVer = 0; // These versions are protocol versions
- alert.nMaxVer = 999001;
- alert.nPriority = 1;
- alert.strComment = "Alert comment";
- alert.strStatusBar = "Alert 1";
-
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
- alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
- alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.clear();
- ++alert.nID;
- alert.nCancel = 1;
- alert.nPriority = 100;
- alert.strStatusBar = "Alert 2, cancels 1";
- SignAndSave(alert, "test/alertTests");
-
- alert.nExpiration += 60;
- ++alert.nID;
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.nMinVer = 11;
- alert.nMaxVer = 22;
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
- alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.nMinVer = 0;
- alert.nMaxVer = 999999;
- alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
- alert.setSubVer.clear();
- SignAndSave(alert, "test/alertTests");
-}
-#endif
-
-struct ReadAlerts : public TestingSetup
-{
- ReadAlerts()
- {
- std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
- CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
- try {
- while (!stream.eof())
- {
- CAlert alert;
- stream >> alert;
- alerts.push_back(alert);
- }
- }
- catch (const std::exception&) { }
- }
- ~ReadAlerts() { }
-
- static std::vector<std::string> read_lines(boost::filesystem::path filepath)
- {
- std::vector<std::string> result;
-
- std::ifstream f(filepath.string().c_str());
- std::string line;
- while (std::getline(f,line))
- result.push_back(line);
-
- return result;
- }
-
- std::vector<CAlert> alerts;
-};
-
-BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
-
-
-BOOST_AUTO_TEST_CASE(AlertApplies)
-{
- SetMockTime(11);
- const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
+BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup)
- BOOST_FOREACH(const CAlert& alert, alerts)
- {
- BOOST_CHECK(alert.CheckSignature(alertKey));
- }
-
- BOOST_CHECK(alerts.size() >= 3);
-
- // Matches:
- BOOST_CHECK(alerts[0].AppliesTo(1, ""));
- BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
- BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
-
- BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
-
- BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
-
- // Don't match:
- BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
- BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
-
- BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
-
- BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
-
- SetMockTime(0);
-}
-
-
-BOOST_AUTO_TEST_CASE(AlertNotify)
-{
- SetMockTime(11);
- const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
-
- boost::filesystem::path temp = GetTempPath() /
- boost::filesystem::unique_path("alertnotify-%%%%.txt");
-
- mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
-
- BOOST_FOREACH(CAlert alert, alerts)
- alert.ProcessAlert(alertKey, false);
-
- std::vector<std::string> r = read_lines(temp);
- BOOST_CHECK_EQUAL(r.size(), 4u);
-
-// Windows built-in echo semantics are different than posixy shells. Quotes and
-// whitespace are printed literally.
-
-#ifndef WIN32
- BOOST_CHECK_EQUAL(r[0], "Alert 1");
- BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
- BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
- BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
-#else
- BOOST_CHECK_EQUAL(r[0], "'Alert 1' ");
- BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' ");
- BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' ");
- BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' ");
-#endif
- boost::filesystem::remove(temp);
-
- SetMockTime(0);
-}
static bool falseFunc() { return false; }
@@ -253,4 +76,4 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
SetMockTime(0);
}
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
new file mode 100644
index 0000000000..59dab20633
--- /dev/null
+++ b/src/test/amount_tests.cpp
@@ -0,0 +1,42 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "amount.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(GetFeeTest)
+{
+ CFeeRate feeRate;
+
+ feeRate = CFeeRate(0);
+ // Must always return 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0);
+
+ feeRate = CFeeRate(1000);
+ // Must always just return the arg
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3);
+
+ feeRate = CFeeRate(123);
+ // Truncates the result, if not integer
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bctest.py b/src/test/bctest.py
index 3a8d0ea51b..8105b87ffa 100644
--- a/src/test/bctest.py
+++ b/src/test/bctest.py
@@ -1,7 +1,7 @@
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
+from __future__ import division,print_function,unicode_literals
import subprocess
import os
import json
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 20afb16a9e..95dd3e81b4 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -2,7 +2,7 @@
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
+from __future__ import division,print_function,unicode_literals
import os
import bctest
import buildenv
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 98f9de7673..9557000ddc 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -204,7 +204,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -249,7 +250,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -275,7 +277,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -303,7 +305,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -326,7 +329,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -353,7 +356,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -392,7 +396,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -409,7 +414,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
deleted file mode 100644
index c945a95adc..0000000000
--- a/src/test/checkblock_tests.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "clientversion.h"
-#include "consensus/validation.h"
-#include "main.h" // For CheckBlock
-#include "primitives/block.h"
-#include "test/test_bitcoin.h"
-#include "utiltime.h"
-
-#include <cstdio>
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-#include <boost/test/unit_test.hpp>
-
-
-BOOST_FIXTURE_TEST_SUITE(CheckBlock_tests, BasicTestingSetup)
-
-bool read_block(const std::string& filename, CBlock& block)
-{
- namespace fs = boost::filesystem;
- fs::path testFile = fs::current_path() / "data" / filename;
-#ifdef TEST_DATA_DIR
- if (!fs::exists(testFile))
- {
- testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename;
- }
-#endif
- FILE* fp = fopen(testFile.string().c_str(), "rb");
- if (!fp) return false;
-
- fseek(fp, 8, SEEK_SET); // skip msgheader/size
-
- CAutoFile filein(fp, SER_DISK, CLIENT_VERSION);
- if (filein.IsNull()) return false;
-
- filein >> block;
-
- return true;
-}
-
-BOOST_AUTO_TEST_CASE(May15)
-{
- // Putting a 1MB binary file in the git repository is not a great
- // idea, so this test is only run if you manually download
- // test/data/Mar12Fork.dat from
- // http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download
- unsigned int tMay15 = 1368576000;
- SetMockTime(tMay15); // Test as if it was right at May 15
-
- CBlock forkingBlock;
- if (read_block("Mar12Fork.dat", forkingBlock))
- {
- CValidationState state;
-
- // After May 15'th, big blocks are OK:
- forkingBlock.nTime = tMay15; // Invalidates PoW
- BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
- }
-
- SetMockTime(0);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw
deleted file mode 100644
index 01f50680b9..0000000000
--- a/src/test/data/alertTests.raw
+++ /dev/null
Binary files differ
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 7ce7e0879c..9e91132984 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -6,504 +6,519 @@
["correct prevout hash), using the given scriptSig. All nLockTimes are 0, all"],
["nSequences are max."],
-["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"],
-[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."],
-[" ", "DEPTH", "P2SH,STRICTENC"],
-[" ", "DEPTH", "P2SH,STRICTENC"],
-
-["", "", "P2SH,STRICTENC"],
-["", "NOP", "P2SH,STRICTENC"],
-["", "NOP DEPTH", "P2SH,STRICTENC"],
-["NOP", "", "P2SH,STRICTENC"],
-["NOP", "DEPTH", "P2SH,STRICTENC"],
-["NOP","NOP", "P2SH,STRICTENC"],
-["NOP","NOP DEPTH", "P2SH,STRICTENC"],
-
-["DEPTH", "", "P2SH,STRICTENC"],
-
-["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"],
-["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"],
-["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"],
-
-["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"],
-["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"],
-["0","NOP", "P2SH,STRICTENC"],
-["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"],
-["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"],
-["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"],
-["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"],
-["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"],
-
-["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"],
-["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"],
-["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"],
-["0 NOTIF", "123", "P2SH,STRICTENC"],
-
-["0", "DUP IF ENDIF", "P2SH,STRICTENC"],
-["0", "IF 1 ENDIF", "P2SH,STRICTENC"],
-["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"],
-["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"],
-["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"],
-
-["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],
-["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],
-["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],
-["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],
-
-["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],
-["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],
-["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],
-["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],
-
-["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"],
-["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"],
-
-["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"],
-["1", "ELSE ENDIF", "P2SH,STRICTENC"],
-["1", "ENDIF ELSE", "P2SH,STRICTENC"],
-["1", "ENDIF ELSE IF", "P2SH,STRICTENC"],
-["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"],
-["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"],
-["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"],
-["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"],
-
-["1", "RETURN", "P2SH,STRICTENC"],
-["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"],
-
-["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"],
-["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"],
-
-["0", "VERIFY 1", "P2SH,STRICTENC"],
-["1", "VERIFY", "P2SH,STRICTENC"],
-["1", "VERIFY 0", "P2SH,STRICTENC"],
-
-["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"],
-
-["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],
-["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],
-["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],
-["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"],
-["NOP", "NIP", "P2SH,STRICTENC"],
-["NOP", "1 NIP", "P2SH,STRICTENC"],
-["NOP", "1 0 NIP", "P2SH,STRICTENC"],
-["NOP", "OVER 1", "P2SH,STRICTENC"],
-["1", "OVER", "P2SH,STRICTENC"],
-["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"],
-["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],
-["NOP", "0 PICK", "P2SH,STRICTENC"],
-["1", "-1 PICK", "P2SH,STRICTENC"],
-["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],
-["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],
-["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],
-["NOP", "0 ROLL", "P2SH,STRICTENC"],
-["1", "-1 ROLL", "P2SH,STRICTENC"],
-["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],
-["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],
-["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],
-["NOP", "ROT 1", "P2SH,STRICTENC"],
-["NOP", "1 ROT 1", "P2SH,STRICTENC"],
-["NOP", "1 2 ROT 1", "P2SH,STRICTENC"],
-["NOP", "0 1 2 ROT", "P2SH,STRICTENC"],
-["NOP", "SWAP 1", "P2SH,STRICTENC"],
-["1", "SWAP 1", "P2SH,STRICTENC"],
-["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"],
-["NOP", "TUCK 1", "P2SH,STRICTENC"],
-["1", "TUCK 1", "P2SH,STRICTENC"],
-["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"],
-["NOP", "2DUP 1", "P2SH,STRICTENC"],
-["1", "2DUP 1", "P2SH,STRICTENC"],
-["NOP", "3DUP 1", "P2SH,STRICTENC"],
-["1", "3DUP 1", "P2SH,STRICTENC"],
-["1 2", "3DUP 1", "P2SH,STRICTENC"],
-["NOP", "2OVER 1", "P2SH,STRICTENC"],
-["1", "2 3 2OVER 1", "P2SH,STRICTENC"],
-["NOP", "2SWAP 1", "P2SH,STRICTENC"],
-["1", "2 3 2SWAP 1", "P2SH,STRICTENC"],
-
-["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"],
-["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"],
-["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"],
-["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"],
-["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"],
-["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"],
-
-["NOP", "SIZE 1", "P2SH,STRICTENC"],
-
-["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"],
-["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"],
-["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"],
-["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"],
-["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"],
-["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"],
-["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"],
-["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"],
-["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"],
-["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"],
-["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"],
-
-["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items"],
-["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items"],
-["0 1","EQUAL", "P2SH,STRICTENC"],
-["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"],
-["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"],
-
-["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "],
-["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "],
-["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"],
-["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"],
-
-["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"],
-["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"],
-["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"],
-["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-
-["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],
-["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],
+["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation", "EVAL_FALSE"],
+[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that.", "EVAL_FALSE"],
+[" ", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+[" ", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["", "", "P2SH,STRICTENC","", "EVAL_FALSE"],
+["", "NOP", "P2SH,STRICTENC","", "EVAL_FALSE"],
+["", "NOP DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP","NOP", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP","NOP DEPTH", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["DEPTH", "", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes","BAD_OPCODE"],
+["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes","BAD_OPCODE"],
+["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes","BAD_OPCODE"],
+
+["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved","BAD_OPCODE"],
+["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack","EVAL_FALSE"],
+["0","NOP", "P2SH,STRICTENC","","EVAL_FALSE"],
+["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional", "BAD_OPCODE"],
+["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere", "BAD_OPCODE"],
+["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere", "BAD_OPCODE"],
+["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere", "BAD_OPCODE"],
+["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere", "BAD_OPCODE"],
+
+["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey", "UNBALANCED_CONDITIONAL"],
+["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["0 NOTIF", "123", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+
+["0", "DUP IF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0", "IF 1 ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs", "OP_RETURN"],
+["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC", "", "OP_RETURN"],
+
+["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence", "UNBALANCED_CONDITIONAL"],
+["1", "ELSE ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "ENDIF ELSE", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "ENDIF ELSE IF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "IF ENDIF ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC", "", "UNBALANCED_CONDITIONAL"],
+
+["1", "RETURN", "P2SH,STRICTENC", "", "OP_RETURN"],
+["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC", "", "OP_RETURN"],
+
+["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format", "OP_RETURN"],
+["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey", "UNBALANCED_CONDITIONAL"],
+
+["0", "VERIFY 1", "P2SH,STRICTENC", "", "VERIFY"],
+["1", "VERIFY", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["1", "VERIFY 0", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey", "INVALID_ALTSTACK_OPERATION"],
+
+["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "1 NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "1 0 NIP", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "0 PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "-1 PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["NOP", "0 ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "-1 ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["NOP", "ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "1 ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "1 2 ROT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "0 1 2 ROT", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC", "", "EQUALVERIFY"],
+["NOP", "TUCK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "TUCK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["NOP", "2DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "2DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 2", "3DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "2OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "2 3 2OVER 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "2SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "2 3 2SWAP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled", "DISABLED_OPCODE"],
+["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled", "DISABLED_OPCODE"],
+["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled", "DISABLED_OPCODE"],
+["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled", "DISABLED_OPCODE"],
+["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled", "DISABLED_OPCODE"],
+["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled", "DISABLED_OPCODE"],
+
+["NOP", "SIZE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled", "DISABLED_OPCODE"],
+["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled", "DISABLED_OPCODE"],
+["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled", "DISABLED_OPCODE"],
+["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled", "DISABLED_OPCODE"],
+["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled", "DISABLED_OPCODE"],
+["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled", "DISABLED_OPCODE"],
+["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled", "DISABLED_OPCODE"],
+["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled", "DISABLED_OPCODE"],
+["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled", "DISABLED_OPCODE"],
+["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled", "DISABLED_OPCODE"],
+["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled", "DISABLED_OPCODE"],
+
+["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items", "INVALID_STACK_OPERATION"],
+["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items", "INVALID_STACK_OPERATION"],
+["0 1","EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] ", "UNKNOWN_ERROR"],
+["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] ", "UNKNOWN_ERROR"],
+["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range", "UNKNOWN_ERROR"],
+["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand", "UNKNOWN_ERROR"],
+
+["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled", "DISABLED_OPCODE"],
+
+["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "", "EVAL_FALSE"],
["Ensure 100% coverage of discouraged NOPS"],
-["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-
-["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"],
+["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "", "DISCOURAGE_UPGRADABLE_NOPS"],
+
+["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig", "DISCOURAGE_UPGRADABLE_NOPS"],
["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL",
- "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"],
-
-["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"],
-["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"],
-["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"],
-["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"],
-
-["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"],
-
-["NOP", "RIPEMD160", "P2SH,STRICTENC"],
-["NOP", "SHA1", "P2SH,STRICTENC"],
-["NOP", "SHA256", "P2SH,STRICTENC"],
-["NOP", "HASH160", "P2SH,STRICTENC"],
-["NOP", "HASH256", "P2SH,STRICTENC"],
+ "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript", "DISCOURAGE_UPGRADABLE_NOPS"],
+
+["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved", "BAD_OPCODE"],
+["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed", "BAD_OPCODE"],
+["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC", "", "BAD_OPCODE"],
+
+["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately", "UNBALANCED_CONDITIONAL"],
+
+["NOP", "RIPEMD160", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "SHA1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "SHA256", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "HASH160", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "HASH256", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
["NOP",
"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",
"P2SH,STRICTENC",
-">520 byte push"],
+">520 byte push",
+"PUSH_SIZE"],
["0",
"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1",
"P2SH,STRICTENC",
-">520 byte push in non-executed IF branch"],
+">520 byte push in non-executed IF branch",
+"PUSH_SIZE"],
["1",
"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
"P2SH,STRICTENC",
-">201 opcodes executed. 0x61 is NOP"],
+">201 opcodes executed. 0x61 is NOP",
+"OP_COUNT"],
["0",
"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1",
"P2SH,STRICTENC",
-">201 opcodes including non-executed IF branch. 0x61 is NOP"],
+">201 opcodes including non-executed IF branch. 0x61 is NOP",
+"OP_COUNT"],
["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
"P2SH,STRICTENC",
-">1,000 stack size (0x6f is 3DUP)"],
+">1,000 stack size (0x6f is 3DUP)",
+"STACK_SIZE"],
["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",
"P2SH,STRICTENC",
-">1,000 stack+altstack size"],
+">1,000 stack+altstack size",
+"STACK_SIZE"],
["NOP",
"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
"P2SH,STRICTENC",
-"10,001-byte scriptPubKey"],
-
-["NOP1","NOP10", "P2SH,STRICTENC"],
-
-["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"],
-["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"],
-["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"],
-["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"],
-["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"],
-["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"],
-["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"],
-
-["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"],
-["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"],
-["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"],
-["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"],
-["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"],
-
-["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"],
-["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"],
-
-["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"],
-["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"],
-["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"],
-
-["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"],
-["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"],
-["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"],
-
-["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"],
-["1", "FROMALTSTACK", "P2SH,STRICTENC"],
-["1", "2DROP 1", "P2SH,STRICTENC"],
-["1", "2DUP", "P2SH,STRICTENC"],
-["1 1", "3DUP", "P2SH,STRICTENC"],
-["1 1 1", "2OVER", "P2SH,STRICTENC"],
-["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"],
-["1 1 1", "2SWAP", "P2SH,STRICTENC"],
-["NOP", "IFDUP 1", "P2SH,STRICTENC"],
-["NOP", "DROP 1", "P2SH,STRICTENC"],
-["NOP", "DUP 1", "P2SH,STRICTENC"],
-["1", "NIP", "P2SH,STRICTENC"],
-["1", "OVER", "P2SH,STRICTENC"],
-["1 1 1 3", "PICK", "P2SH,STRICTENC"],
-["0", "PICK 1", "P2SH,STRICTENC"],
-["1 1 1 3", "ROLL", "P2SH,STRICTENC"],
-["0", "ROLL 1", "P2SH,STRICTENC"],
-["1 1", "ROT", "P2SH,STRICTENC"],
-["1", "SWAP", "P2SH,STRICTENC"],
-["1", "TUCK", "P2SH,STRICTENC"],
-
-["NOP", "SIZE 1", "P2SH,STRICTENC"],
-
-["1", "EQUAL 1", "P2SH,STRICTENC"],
-["1", "EQUALVERIFY 1", "P2SH,STRICTENC"],
-
-["NOP", "1ADD 1", "P2SH,STRICTENC"],
-["NOP", "1SUB 1", "P2SH,STRICTENC"],
-["NOP", "NEGATE 1", "P2SH,STRICTENC"],
-["NOP", "ABS 1", "P2SH,STRICTENC"],
-["NOP", "NOT 1", "P2SH,STRICTENC"],
-["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"],
-
-["1", "ADD", "P2SH,STRICTENC"],
-["1", "SUB", "P2SH,STRICTENC"],
-["1", "BOOLAND", "P2SH,STRICTENC"],
-["1", "BOOLOR", "P2SH,STRICTENC"],
-["1", "NUMEQUAL", "P2SH,STRICTENC"],
-["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"],
-["1", "NUMNOTEQUAL", "P2SH,STRICTENC"],
-["1", "LESSTHAN", "P2SH,STRICTENC"],
-["1", "GREATERTHAN", "P2SH,STRICTENC"],
-["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"],
-["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"],
-["1", "MIN", "P2SH,STRICTENC"],
-["1", "MAX", "P2SH,STRICTENC"],
-["1 1", "WITHIN", "P2SH,STRICTENC"],
-
-["NOP", "RIPEMD160 1", "P2SH,STRICTENC"],
-["NOP", "SHA1 1", "P2SH,STRICTENC"],
-["NOP", "SHA256 1", "P2SH,STRICTENC"],
-["NOP", "HASH160 1", "P2SH,STRICTENC"],
-["NOP", "HASH256 1", "P2SH,STRICTENC"],
+"10,001-byte scriptPubKey",
+"SCRIPT_SIZE"],
+
+["NOP1","NOP10", "P2SH,STRICTENC", "", "EVAL_FALSE"],
+
+["1","VER", "P2SH,STRICTENC", "OP_VER is reserved", "BAD_OPCODE"],
+["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved", "BAD_OPCODE"],
+["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved", "BAD_OPCODE"],
+["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved", "BAD_OPCODE"],
+["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved", "BAD_OPCODE"],
+["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved", "BAD_OPCODE"],
+["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1", "BAD_OPCODE"],
+
+["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers", "UNKNOWN_ERROR"],
+["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers", "UNKNOWN_ERROR"],
+["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes", "UNKNOWN_ERROR"],
+["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes", "UNKNOWN_ERROR"],
+["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes", "UNKNOWN_ERROR"],
+
+["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)", "UNKNOWN_ERROR"],
+["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers", "UNKNOWN_ERROR"],
+
+["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF", "UNBALANCED_CONDITIONAL"],
+["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF", "UNBALANCED_CONDITIONAL"],
+["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over", "UNBALANCED_CONDITIONAL"],
+
+["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode", "UNBALANCED_CONDITIONAL"],
+["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors", "UNBALANCED_CONDITIONAL"],
+["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,", "INVALID_STACK_OPERATION"],
+
+["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?", "INVALID_STACK_OPERATION"],
+["1", "FROMALTSTACK", "P2SH,STRICTENC", "", "INVALID_ALTSTACK_OPERATION"],
+["1", "2DROP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "2DUP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1", "3DUP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1 1", "2OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1 1 1 1", "2ROT", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1 1", "2SWAP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "IFDUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "DROP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "DUP 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "NIP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "OVER", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1 1 3", "PICK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["0", "PICK 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1 1 3", "ROLL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["0", "ROLL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1", "ROT", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "SWAP", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "TUCK", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["NOP", "SIZE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["1", "EQUAL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "EQUALVERIFY 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["NOP", "1ADD 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "1SUB 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "NEGATE 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "ABS 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "NOT 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["1", "ADD", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "SUB", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "BOOLAND", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "BOOLOR", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "NUMEQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "NUMNOTEQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "LESSTHAN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "GREATERTHAN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "LESSTHANOREQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "MIN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1", "MAX", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["1 1", "WITHIN", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+
+["NOP", "RIPEMD160 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "SHA1 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "SHA256 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "HASH160 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
+["NOP", "HASH256 1", "P2SH,STRICTENC", "", "INVALID_STACK_OPERATION"],
["Increase CHECKSIG and CHECKMULTISIG negative test coverage"],
-["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items"],
-["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items"],
-["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items"],
-["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative"],
-["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"],
-["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative"],
-["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack"],
-["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"],
+["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items", "INVALID_STACK_OPERATION"],
+["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items", "INVALID_STACK_OPERATION"],
+["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items", "INVALID_STACK_OPERATION"],
+["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative", "PUBKEY_COUNT"],
+["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack", "INVALID_STACK_OPERATION"],
+["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative", "SIG_COUNT"],
+["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack", "INVALID_STACK_OPERATION"],
+["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode","EVAL_FALSE"],
["",
"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG",
"P2SH,STRICTENC",
-"202 CHECKMULTISIGS, fails due to 201 op limit"],
+"202 CHECKMULTISIGS, fails due to 201 op limit",
+"OP_COUNT"],
["1",
"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY",
-"P2SH,STRICTENC"],
+"P2SH,STRICTENC",
+"",
+"INVALID_STACK_OPERATION"],
["",
"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG",
"P2SH,STRICTENC",
-"Fails due to 201 sig op limit"],
+"Fails due to 201 sig op limit",
+"OP_COUNT"],
["1",
"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY",
-"P2SH,STRICTENC"],
+"P2SH,STRICTENC",
+"",
+"OP_COUNT"],
-["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20"],
-["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"],
+["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20", "PUBKEY_COUNT"],
+["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys", "SIG_COUNT"],
-["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"],
-["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"],
+["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()", "SIG_PUSHONLY"],
+["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "", "SIG_PUSHONLY"],
-["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"],
-["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"],
+["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail", "BAD_OPCODE"],
+["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail", "BAD_OPCODE"],
-["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
+["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution", "EVAL_FALSE"],
["MINIMALDATA enforcement for PUSHDATAs"],
-["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"],
-["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"],
-["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"],
-["0x01 0x02", "DROP 1", "MINIMALDATA"],
-["0x01 0x03", "DROP 1", "MINIMALDATA"],
-["0x01 0x04", "DROP 1", "MINIMALDATA"],
-["0x01 0x05", "DROP 1", "MINIMALDATA"],
-["0x01 0x06", "DROP 1", "MINIMALDATA"],
-["0x01 0x07", "DROP 1", "MINIMALDATA"],
-["0x01 0x08", "DROP 1", "MINIMALDATA"],
-["0x01 0x09", "DROP 1", "MINIMALDATA"],
-["0x01 0x0a", "DROP 1", "MINIMALDATA"],
-["0x01 0x0b", "DROP 1", "MINIMALDATA"],
-["0x01 0x0c", "DROP 1", "MINIMALDATA"],
-["0x01 0x0d", "DROP 1", "MINIMALDATA"],
-["0x01 0x0e", "DROP 1", "MINIMALDATA"],
-["0x01 0x0f", "DROP 1", "MINIMALDATA"],
-["0x01 0x10", "DROP 1", "MINIMALDATA"],
+["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0", "MINIMALDATA"],
+["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE", "MINIMALDATA"],
+["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16", "MINIMALDATA"],
+["0x01 0x02", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x03", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x04", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x05", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x06", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x07", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x08", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x09", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0a", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0b", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0c", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0d", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0e", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x0f", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
+["0x01 0x10", "DROP 1", "MINIMALDATA", "", "MINIMALDATA"],
["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
- "PUSHDATA1 of 72 bytes minimally represented by direct push"],
+ "PUSHDATA1 of 72 bytes minimally represented by direct push",
+ "MINIMALDATA"],
["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
- "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"],
+ "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1",
+ "MINIMALDATA"],
["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
- "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"],
-
+ "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2",
+ "MINIMALDATA"],
["MINIMALDATA enforcement for numeric arguments"],
-["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
-["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
-["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],
-["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
-["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
-["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
-["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
-["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
-["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"],
-["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"],
-["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"],
-["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"],
+["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"],
+["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0", "UNKNOWN_ERROR"],
+["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0", "UNKNOWN_ERROR"],
+["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5", "UNKNOWN_ERROR"],
+["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5", "UNKNOWN_ERROR"],
+["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5", "UNKNOWN_ERROR"],
+["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5", "UNKNOWN_ERROR"],
+["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff", "UNKNOWN_ERROR"],
+["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f", "UNKNOWN_ERROR"],
+["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff", "UNKNOWN_ERROR"],
+["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f", "UNKNOWN_ERROR"],
["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"],
-["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"],
-["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"],
-["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"],
-
-["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"],
-["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"],
-["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"],
-["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"],
-["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"],
-
-["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"],
-["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"],
-
-["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
-["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
-["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
-["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+["1 0x02 0x0000", "PICK DROP", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "ABS DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+
+["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+
+["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+
+["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "", "UNKNOWN_ERROR"],
["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"],
@@ -513,301 +528,349 @@
"0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT",
"STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded."
+ "2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded.",
+ "PUBKEYTYPE"
],
[
"0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1",
"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
"STRICTENC",
- "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."
+ "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid.",
+ "SIG_DER"
+],
+[
+ "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f",
+ "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG",
+ "P2SH,STRICTENC",
+ "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs",
+ "SIG_DER"
],
["Increase DERSIG test coverage"],
-["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG"],
-["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG"],
-["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG"],
-["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG"],
-["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG"],
-["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG"],
-["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG"],
-["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG"],
+["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG", "SIG_DER"],
+["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG", "SIG_DER"],
["Automatically generated test cases"],
[
"0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"",
- "P2PK, bad sig"
+ "P2PK, bad sig",
+ "EVAL_FALSE"
],
[
"0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
"DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",
"",
- "P2PKH, bad pubkey"
+ "P2PKH, bad pubkey",
+ "EQUALVERIFY"
],
[
"0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"",
- "P2PK anyonecanpay marked with normal hashtype"
+ "P2PK anyonecanpay marked with normal hashtype",
+ "EVAL_FALSE"
],
[
"0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
"P2SH",
- "P2SH(P2PK), bad redeemscript"
+ "P2SH(P2PK), bad redeemscript",
+ "EVAL_FALSE"
],
[
"0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"P2SH",
- "P2SH(P2PKH), bad sig"
+ "P2SH(P2PKH), bad sig",
+ "EQUALVERIFY"
],
[
"0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
- "3-of-3, 2 sigs"
+ "3-of-3, 2 sigs",
+ "EVAL_FALSE"
],
[
"0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
"P2SH",
- "P2SH(2-of-3), 1 sig"
+ "P2SH(2-of-3), 1 sig",
+ "EVAL_FALSE"
],
[
"0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "P2PK with too much R padding"
+ "P2PK with too much R padding",
+ "SIG_DER"
],
[
"0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "P2PK with too much S padding"
+ "P2PK with too much S padding",
+ "SIG_DER"
],
[
"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "P2PK with too little R padding"
+ "P2PK with too little R padding",
+ "SIG_DER"
],
[
"0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
- "P2PK NOT with bad sig with too much R padding"
+ "P2PK NOT with bad sig with too much R padding",
+ "SIG_DER"
],
[
"0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"",
- "P2PK NOT with too much R padding but no DERSIG"
+ "P2PK NOT with too much R padding but no DERSIG",
+ "EVAL_FALSE"
],
[
"0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
"DERSIG",
- "P2PK NOT with too much R padding"
+ "P2PK NOT with too much R padding",
+ "SIG_DER"
],
[
"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "BIP66 example 1, with DERSIG"
+ "BIP66 example 1, with DERSIG",
+ "SIG_DER"
],
[
"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
"",
- "BIP66 example 2, without DERSIG"
+ "BIP66 example 2, without DERSIG",
+ "EVAL_FALSE"
],
[
"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
"DERSIG",
- "BIP66 example 2, with DERSIG"
+ "BIP66 example 2, with DERSIG",
+ "SIG_DER"
],
[
"0",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
- "BIP66 example 3, without DERSIG"
+ "BIP66 example 3, without DERSIG",
+ "EVAL_FALSE"
],
[
"0",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "BIP66 example 3, with DERSIG"
+ "BIP66 example 3, with DERSIG",
+ "EVAL_FALSE"
],
[
"1",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
- "BIP66 example 5, without DERSIG"
+ "BIP66 example 5, without DERSIG",
+ "EVAL_FALSE"
],
[
"1",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"DERSIG",
- "BIP66 example 5, with DERSIG"
+ "BIP66 example 5, with DERSIG",
+ "SIG_DER"
],
[
"1",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
"DERSIG",
- "BIP66 example 6, with DERSIG"
+ "BIP66 example 6, with DERSIG",
+ "SIG_DER"
],
[
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"DERSIG",
- "BIP66 example 7, with DERSIG"
+ "BIP66 example 7, with DERSIG",
+ "SIG_DER"
],
[
"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"",
- "BIP66 example 8, without DERSIG"
+ "BIP66 example 8, without DERSIG",
+ "EVAL_FALSE"
],
[
"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"DERSIG",
- "BIP66 example 8, with DERSIG"
+ "BIP66 example 8, with DERSIG",
+ "SIG_DER"
],
[
"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"",
- "BIP66 example 9, without DERSIG"
+ "BIP66 example 9, without DERSIG",
+ "EVAL_FALSE"
],
[
"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"DERSIG",
- "BIP66 example 9, with DERSIG"
+ "BIP66 example 9, with DERSIG",
+ "SIG_DER"
],
[
"0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
"DERSIG",
- "BIP66 example 10, with DERSIG"
+ "BIP66 example 10, with DERSIG",
+ "SIG_DER"
],
[
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"",
- "BIP66 example 11, without DERSIG"
+ "BIP66 example 11, without DERSIG",
+ "EVAL_FALSE"
],
[
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
"DERSIG",
- "BIP66 example 11, with DERSIG"
+ "BIP66 example 11, with DERSIG",
+ "EVAL_FALSE"
],
[
"0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"DERSIG",
- "P2PK with multi-byte hashtype, with DERSIG"
+ "P2PK with multi-byte hashtype, with DERSIG",
+ "SIG_DER"
],
[
"0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"LOW_S",
- "P2PK with high S"
+ "P2PK with high S",
+ "SIG_HIGH_S"
],
[
"0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"STRICTENC",
- "P2PK with hybrid pubkey"
+ "P2PK with hybrid pubkey",
+ "PUBKEYTYPE"
],
[
"0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"",
- "P2PK NOT with hybrid pubkey but no STRICTENC"
+ "P2PK NOT with hybrid pubkey but no STRICTENC",
+ "EVAL_FALSE"
],
[
"0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
- "P2PK NOT with hybrid pubkey"
+ "P2PK NOT with hybrid pubkey",
+ "PUBKEYTYPE"
],
[
"0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101",
"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
"STRICTENC",
- "P2PK NOT with invalid hybrid pubkey"
+ "P2PK NOT with invalid hybrid pubkey",
+ "PUBKEYTYPE"
],
[
"0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201",
"1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG",
"STRICTENC",
- "1-of-2 with the first 1 hybrid pubkey"
+ "1-of-2 with the first 1 hybrid pubkey",
+ "PUBKEYTYPE"
],
[
"0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
"STRICTENC",
- "P2PK with undefined hashtype"
+ "P2PK with undefined hashtype",
+ "SIG_HASHTYPE"
],
[
"0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05",
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
"STRICTENC",
- "P2PK NOT with invalid sig and undefined hashtype"
+ "P2PK NOT with invalid sig and undefined hashtype",
+ "SIG_HASHTYPE"
],
[
"1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"NULLDUMMY",
- "3-of-3 with nonzero dummy"
+ "3-of-3 with nonzero dummy",
+ "SIG_NULLDUMMY"
],
[
"1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
"NULLDUMMY",
- "3-of-3 NOT with invalid sig with nonzero dummy"
+ "3-of-3 NOT with invalid sig with nonzero dummy",
+ "SIG_NULLDUMMY"
],
[
"0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP",
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
"SIGPUSHONLY",
- "2-of-2 with two identical keys and sigs pushed using OP_DUP"
+ "2-of-2 with two identical keys and sigs pushed using OP_DUP",
+ "SIG_PUSHONLY"
],
[
"0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"",
- "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"
+ "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY",
+ "EVAL_FALSE"
],
[
"0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"SIGPUSHONLY",
- "P2SH(P2PK) with non-push scriptSig"
-],
-[
- "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f",
- "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG",
- "P2SH,STRICTENC",
- "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs"
+ "P2SH(P2PK) with non-push scriptSig",
+ "EVAL_FALSE"
],
[
"11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"CLEANSTACK,P2SH",
- "P2PK with unnecessary input"
+ "P2PK with unnecessary input",
+ "CLEANSTACK"
],
[
"11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",
"HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL",
"CLEANSTACK,P2SH",
- "P2SH with unnecessary input"
+ "P2SH with unnecessary input",
+ "CLEANSTACK"
],
["The End"]
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 9025841949..2d7d9b9585 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -201,5 +201,59 @@
[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"],
+["CHECKSEQUENCEVERIFY tests"],
+
+["By-height locks, with argument just beyond txin.nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument missing"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument negative with by-blockheight txin.nSequence=0"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument/tx height/time mismatch, both versions"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
+"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Failure due to insufficient tx.nVersion (<2)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 76d29bcf26..717ad19549 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -233,5 +233,89 @@
[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"],
+["CHECKSEQUENCEVERIFY tests"],
+
+["By-height locks, with argument == 0 and == txin.nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["By-time locks, with argument == 0 and == txin.nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Upper sequence with upper sequence is fine"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 2^31 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 2^32-1 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 3<<31 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["5 byte non-minimally-encoded operandss are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["The argument can be calculated rather than created directly by a PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Valid CHECKSEQUENCEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Valid CHECKSEQUENCEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
+"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 1347d23656..c8b43df26c 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -57,12 +57,12 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
std::list<CTransaction> removed;
// Nothing in pool, remove should do nothing:
- testPool.remove(txParent, removed, true);
+ testPool.removeRecursive(txParent, removed);
BOOST_CHECK_EQUAL(removed.size(), 0);
// Just the parent:
testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
- testPool.remove(txParent, removed, true);
+ testPool.removeRecursive(txParent, removed);
BOOST_CHECK_EQUAL(removed.size(), 1);
removed.clear();
@@ -74,16 +74,16 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));
}
// Remove Child[0], GrandChild[0] should be removed:
- testPool.remove(txChild[0], removed, true);
+ testPool.removeRecursive(txChild[0], removed);
BOOST_CHECK_EQUAL(removed.size(), 2);
removed.clear();
// ... make sure grandchild and child are gone:
- testPool.remove(txGrandChild[0], removed, true);
+ testPool.removeRecursive(txGrandChild[0], removed);
BOOST_CHECK_EQUAL(removed.size(), 0);
- testPool.remove(txChild[0], removed, true);
+ testPool.removeRecursive(txChild[0], removed);
BOOST_CHECK_EQUAL(removed.size(), 0);
// Remove parent, all children/grandchildren should go:
- testPool.remove(txParent, removed, true);
+ testPool.removeRecursive(txParent, removed);
BOOST_CHECK_EQUAL(removed.size(), 5);
BOOST_CHECK_EQUAL(testPool.size(), 0);
removed.clear();
@@ -96,19 +96,19 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
// Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
// put into the mempool (maybe because it is non-standard):
- testPool.remove(txParent, removed, true);
+ testPool.removeRecursive(txParent, removed);
BOOST_CHECK_EQUAL(removed.size(), 6);
BOOST_CHECK_EQUAL(testPool.size(), 0);
removed.clear();
}
-template<int index>
+template<typename name>
void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
{
BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
- typename CTxMemPool::indexed_transaction_set::nth_index<index>::type::iterator it = pool.mapTx.get<index>().begin();
+ typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();
int count=0;
- for (; it != pool.mapTx.get<index>().end(); ++it, ++count) {
+ for (; it != pool.mapTx.get<name>().end(); ++it, ++count) {
BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
}
}
@@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
sortedOrder[3] = tx4.GetHash().ToString(); // 15000
sortedOrder[4] = tx2.GetHash().ToString(); // 20000
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
/* low fee but with high fee child */
/* tx6 -> tx7 -> tx8, tx9 -> tx10 */
@@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_CHECK_EQUAL(pool.size(), 6);
// Check that at this point, tx6 is sorted low
sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
CTxMemPool::setEntries setAncestors;
setAncestors.insert(pool.mapTx.find(tx6.GetHash()));
@@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder.erase(sortedOrder.begin());
sortedOrder.push_back(tx6.GetHash().ToString());
sortedOrder.push_back(tx7.GetHash().ToString());
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
/* low fee child of tx7 */
CMutableTransaction tx8 = CMutableTransaction();
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
// Now tx8 should be sorted low, but tx6/tx both high
sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
/* low fee child of tx7 */
CMutableTransaction tx9 = CMutableTransaction();
@@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
// tx9 should be sorted low
BOOST_CHECK_EQUAL(pool.size(), 9);
sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
std::vector<std::string> snapshotOrder = sortedOrder;
@@ -274,18 +274,18 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
- CheckSort<1>(pool, sortedOrder);
+ CheckSort<descendant_score>(pool, sortedOrder);
// there should be 10 transactions in the mempool
BOOST_CHECK_EQUAL(pool.size(), 10);
// Now try removing tx10 and verify the sort order returns to normal
std::list<CTransaction> removed;
- pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true);
- CheckSort<1>(pool, snapshotOrder);
+ pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed);
+ CheckSort<descendant_score>(pool, snapshotOrder);
- pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true);
- pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true);
+ pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed);
+ pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed);
/* Now check the sort on the mining score index.
* Final order should be:
*
@@ -314,7 +314,111 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder.push_back(tx3.GetHash().ToString());
sortedOrder.push_back(tx6.GetHash().ToString());
}
- CheckSort<3>(pool, sortedOrder);
+ CheckSort<mining_score>(pool, sortedOrder);
+}
+
+BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
+{
+ CTxMemPool pool(CFeeRate(0));
+ TestMemPoolEntryHelper entry;
+ entry.hadNoDependencies = true;
+
+ /* 3rd highest fee */
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vout.resize(1);
+ tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx1.vout[0].nValue = 10 * COIN;
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+
+ /* highest fee */
+ CMutableTransaction tx2 = CMutableTransaction();
+ tx2.vout.resize(1);
+ tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx2.vout[0].nValue = 2 * COIN;
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+ uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION);
+
+ /* lowest fee */
+ CMutableTransaction tx3 = CMutableTransaction();
+ tx3.vout.resize(1);
+ tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx3.vout[0].nValue = 5 * COIN;
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+
+ /* 2nd highest fee */
+ CMutableTransaction tx4 = CMutableTransaction();
+ tx4.vout.resize(1);
+ tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx4.vout[0].nValue = 6 * COIN;
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+
+ /* equal fee rate to tx1, but newer */
+ CMutableTransaction tx5 = CMutableTransaction();
+ tx5.vout.resize(1);
+ tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx5.vout[0].nValue = 11 * COIN;
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
+ BOOST_CHECK_EQUAL(pool.size(), 5);
+
+ std::vector<std::string> sortedOrder;
+ sortedOrder.resize(5);
+ sortedOrder[0] = tx2.GetHash().ToString(); // 20000
+ sortedOrder[1] = tx4.GetHash().ToString(); // 15000
+ // tx1 and tx5 are both 10000
+ // Ties are broken by hash, not timestamp, so determine which
+ // hash comes first.
+ if (tx1.GetHash() < tx5.GetHash()) {
+ sortedOrder[2] = tx1.GetHash().ToString();
+ sortedOrder[3] = tx5.GetHash().ToString();
+ } else {
+ sortedOrder[2] = tx5.GetHash().ToString();
+ sortedOrder[3] = tx1.GetHash().ToString();
+ }
+ sortedOrder[4] = tx3.GetHash().ToString(); // 0
+
+ CheckSort<ancestor_score>(pool, sortedOrder);
+
+ /* low fee parent with high fee child */
+ /* tx6 (0) -> tx7 (high) */
+ CMutableTransaction tx6 = CMutableTransaction();
+ tx6.vout.resize(1);
+ tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx6.vout[0].nValue = 20 * COIN;
+ uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION);
+
+ pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));
+ BOOST_CHECK_EQUAL(pool.size(), 6);
+ sortedOrder.push_back(tx6.GetHash().ToString());
+ CheckSort<ancestor_score>(pool, sortedOrder);
+
+ CMutableTransaction tx7 = CMutableTransaction();
+ tx7.vin.resize(1);
+ tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
+ tx7.vin[0].scriptSig = CScript() << OP_11;
+ tx7.vout.resize(1);
+ tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+ uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION);
+
+ /* set the fee to just below tx2's feerate when including ancestor */
+ CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
+
+ //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true);
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
+ BOOST_CHECK_EQUAL(pool.size(), 7);
+ sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
+ CheckSort<ancestor_score>(pool, sortedOrder);
+
+ /* after tx6 is mined, tx7 should move up in the sort */
+ std::vector<CTransaction> vtx;
+ vtx.push_back(tx6);
+ std::list<CTransaction> dummy;
+ pool.removeForBlock(vtx, 1, dummy, false);
+
+ sortedOrder.erase(sortedOrder.begin()+1);
+ sortedOrder.pop_back();
+ sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
+ CheckSort<ancestor_score>(pool, sortedOrder);
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 71b52409b3..ab6485081c 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -57,6 +57,20 @@ struct {
{2, 0xbbbeb305}, {2, 0xfe1c810a},
};
+CBlockIndex CreateBlockIndex(int nHeight)
+{
+ CBlockIndex index;
+ index.nHeight = nHeight;
+ index.pprev = chainActive.Tip();
+ return index;
+}
+
+bool TestSequenceLocks(const CTransaction &tx, int flags)
+{
+ LOCK(mempool.cs);
+ return CheckSequenceLocks(tx, flags);
+}
+
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
@@ -79,6 +93,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// We can't make transactions until we have inputs
// Therefore, load 100 blocks :)
+ int baseheight = 0;
std::vector<CTransaction*>txFirst;
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
{
@@ -92,7 +107,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = CTransaction(txCoinbase);
- if (txFirst.size() < 2)
+ if (txFirst.size() == 0)
+ baseheight = chainActive.Height();
+ if (txFirst.size() < 4)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
@@ -230,59 +247,133 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// subsidy changing
int nHeight = chainActive.Height();
- chainActive.Tip()->nHeight = 209999;
+ // Create an actual 209999-long block chain (without valid blocks).
+ while (chainActive.Tip()->nHeight < 209999) {
+ CBlockIndex* prev = chainActive.Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(GetRandHash());
+ pcoinsTip->SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ chainActive.SetTip(next);
+ }
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
delete pblocktemplate;
- chainActive.Tip()->nHeight = 210000;
+ // Extend to a 210000-long block chain.
+ while (chainActive.Tip()->nHeight < 210000) {
+ CBlockIndex* prev = chainActive.Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(GetRandHash());
+ pcoinsTip->SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ chainActive.SetTip(next);
+ }
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
delete pblocktemplate;
- chainActive.Tip()->nHeight = nHeight;
+ // Delete the dummy blocks again.
+ while (chainActive.Tip()->nHeight > nHeight) {
+ CBlockIndex* del = chainActive.Tip();
+ chainActive.SetTip(del->pprev);
+ pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
+ delete del->phashBlock;
+ delete del;
+ }
// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
+ int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST;
+ // height map
+ std::vector<int> prevheights;
- // height locked
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ // relative height locked
+ tx.nVersion = 2;
+ tx.vin.resize(1);
+ prevheights.resize(1);
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction
+ tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vin[0].nSequence = 0;
+ tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block
+ prevheights[0] = baseheight + 1;
+ tx.vout.resize(1);
tx.vout[0].nValue = 4900000000LL;
tx.vout[0].scriptPubKey = CScript() << OP_1;
- tx.nLockTime = chainActive.Tip()->nHeight+1;
+ tx.nLockTime = 0;
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST));
-
- // time locked
- tx2.vin.resize(1);
- tx2.vin[0].prevout.hash = txFirst[1]->GetHash();
- tx2.vin[0].prevout.n = 0;
- tx2.vin[0].scriptSig = CScript() << OP_1;
- tx2.vin[0].nSequence = 0;
- tx2.vout.resize(1);
- tx2.vout[0].nValue = 4900000000LL;
- tx2.vout[0].scriptPubKey = CScript() << OP_1;
- tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
- hash = tx2.GetHash();
- mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx2));
- BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
+ BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes
+ BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
+ BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block
+
+ // relative time locked
+ tx.vin[0].prevout.hash = txFirst[1]->GetHash();
+ tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block
+ prevheights[0] = baseheight + 2;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
+ BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes
+ BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
+
+ for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
+ chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
+ BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later
+ for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
+ chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP
+
+ // absolute height locked
+ tx.vin[0].prevout.hash = txFirst[2]->GetHash();
+ tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1;
+ prevheights[0] = baseheight + 3;
+ tx.nLockTime = chainActive.Tip()->nHeight + 1;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
+ BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails
+ BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass
+ BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
+
+ // absolute time locked
+ tx.vin[0].prevout.hash = txFirst[3]->GetHash();
+ tx.nLockTime = chainActive.Tip()->GetMedianTimePast();
+ prevheights.resize(1);
+ prevheights[0] = baseheight + 4;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
+ BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails
+ BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass
+ BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
+
+ // mempool-dependent transactions (not added)
+ tx.vin[0].prevout.hash = hash;
+ prevheights[0] = chainActive.Tip()->nHeight + 1;
+ tx.nLockTime = 0;
+ tx.vin[0].nSequence = 0;
+ BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes
+ BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass
+ tx.vin[0].nSequence = 1;
+ BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
+ tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
+ BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass
+ tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
+ BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
- // Neither tx should have make it into the template.
- BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1);
+ // None of the of the absolute height/time locked tx should have made
+ // it into the template because we still check IsFinalTx in CreateNewBlock,
+ // but relative locked txs will if inconsistently added to mempool.
+ // For now these will still generate a valid template until BIP68 soft fork
+ BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
delete pblocktemplate;
-
- // However if we advance height and time by one, both will.
+ // However if we advance height by 1 and time by 512, all of them should be mined
+ for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
+ chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
chainActive.Tip()->nHeight++;
- SetMockTime(chainActive.Tip()->GetMedianTimePast()+2);
-
- // FIXME: we should *actually* create a new block so the following test
- // works; CheckFinalTx() isn't fooled by monkey-patching nHeight.
- //BOOST_CHECK(CheckFinalTx(tx));
- //BOOST_CHECK(CheckFinalTx(tx2));
+ SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
- BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2);
+ BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5);
delete pblocktemplate;
chainActive.Tip()->nHeight--;
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 113b9437e0..2f3f607889 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -88,7 +88,8 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// extract merkle root and matched txids from copy
std::vector<uint256> vMatchTxid2;
- uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2);
+ std::vector<unsigned int> vIndex;
+ uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex);
// check that it has the same merkle root as the original, and a valid one
BOOST_CHECK(merkleRoot1 == merkleRoot2);
@@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
CPartialMerkleTreeTester pmt3(pmt2);
pmt3.Damage();
std::vector<uint256> vMatchTxid3;
- uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3);
+ uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex);
BOOST_CHECK(merkleRoot3 != merkleRoot1);
}
}
@@ -122,7 +123,8 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
CPartialMerkleTree tree(vTxid, vMatch);
std::vector<uint256> vTxid2;
- BOOST_CHECK(tree.ExtractMatches(vTxid).IsNull());
+ std::vector<unsigned int> vIndex;
+ BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index d6309ca384..1976ee2cb6 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -36,7 +36,7 @@ UniValue CallRPC(string args)
string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
UniValue params = RPCConvertValues(strMethod, vArgs);
-
+ BOOST_CHECK(tableRPC[strMethod]);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
UniValue result = (*method)(params, false);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 10175ebe8e..30e3f37e14 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -52,6 +52,64 @@ read_json(const std::string& jsondata)
return v.get_array();
}
+struct ScriptErrorDesc
+{
+ ScriptError_t err;
+ const char *name;
+};
+
+static ScriptErrorDesc script_errors[]={
+ {SCRIPT_ERR_OK, "OK"},
+ {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"},
+ {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"},
+ {SCRIPT_ERR_OP_RETURN, "OP_RETURN"},
+ {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"},
+ {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"},
+ {SCRIPT_ERR_OP_COUNT, "OP_COUNT"},
+ {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"},
+ {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"},
+ {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"},
+ {SCRIPT_ERR_VERIFY, "VERIFY"},
+ {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"},
+ {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"},
+ {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"},
+ {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"},
+ {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"},
+ {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"},
+ {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"},
+ {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"},
+ {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"},
+ {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"},
+ {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"},
+ {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"},
+ {SCRIPT_ERR_SIG_DER, "SIG_DER"},
+ {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"},
+ {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"},
+ {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"},
+ {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"},
+ {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"},
+ {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"},
+ {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"}
+};
+
+const char *FormatScriptError(ScriptError_t err)
+{
+ for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i)
+ if (script_errors[i].err == err)
+ return script_errors[i].name;
+ BOOST_ERROR("Unknown scripterror enumeration value, update script_errors in script_tests.cpp.");
+ return "";
+}
+
+ScriptError_t ParseScriptError(const std::string &name)
+{
+ for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i)
+ if (script_errors[i].name == name)
+ return script_errors[i].err;
+ BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description");
+ return SCRIPT_ERR_UNKNOWN_ERROR;
+}
+
BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup)
CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
@@ -63,7 +121,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
txCredit.vout.resize(1);
txCredit.vin[0].prevout.SetNull();
txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
- txCredit.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
+ txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
txCredit.vout[0].scriptPubKey = scriptPubKey;
txCredit.vout[0].nValue = 0;
@@ -80,20 +138,20 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu
txSpend.vin[0].prevout.hash = txCredit.GetHash();
txSpend.vin[0].prevout.n = 0;
txSpend.vin[0].scriptSig = scriptSig;
- txSpend.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
+ txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
txSpend.vout[0].scriptPubKey = CScript();
txSpend.vout[0].nValue = 0;
return txSpend;
}
-void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message)
+void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message, int scriptError)
{
ScriptError err;
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message);
- BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
+ BOOST_CHECK_MESSAGE(scriptError == -1 || err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message);
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
@@ -187,6 +245,7 @@ private:
std::vector<unsigned char> push;
std::string comment;
int flags;
+ int scriptError;
void DoPush()
{
@@ -204,7 +263,7 @@ private:
}
public:
- TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_)
+ TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), scriptError(-1)
{
if (P2SH) {
creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL);
@@ -214,6 +273,12 @@ public:
spendTx = BuildSpendingTransaction(CScript(), creditTx);
}
+ TestBuilder& ScriptError(ScriptError_t err)
+ {
+ scriptError = err;
+ return *this;
+ }
+
TestBuilder& Add(const CScript& script)
{
DoPush();
@@ -288,7 +353,7 @@ public:
{
TestBuilder copy = *this; // Make a copy so we can rollback the push.
DoPush();
- DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment);
+ DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment, expect ? SCRIPT_ERR_OK : scriptError);
*this = copy;
return *this;
}
@@ -301,6 +366,8 @@ public:
array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
array.push_back(comment);
+ if (scriptError != -1)
+ array.push_back(FormatScriptError((ScriptError_t)scriptError));
return array;
}
@@ -328,99 +395,99 @@ BOOST_AUTO_TEST_CASE(script_build)
).PushSig(keys.key0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK, bad sig", 0
- ).PushSig(keys.key0).DamagePush(10));
+ ).PushSig(keys.key0).DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2PKH", 0
).PushSig(keys.key1).Push(keys.pubkey1C));
bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2PKH, bad pubkey", 0
- ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5));
+ ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5).ScriptError(SCRIPT_ERR_EQUALVERIFY));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay marked with normal hashtype", 0
- ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01"));
+ ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01").ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true
- ).PushSig(keys.key0).PushRedeem().DamagePush(10));
+ ).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true
).PushSig(keys.key0).DamagePush(10).PushRedeem());
bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true
- ).PushSig(keys.key0).DamagePush(10).PushRedeem());
+ ).PushSig(keys.key0).DamagePush(10).PushRedeem().ScriptError(SCRIPT_ERR_EQUALVERIFY));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3", 0
).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3, 2 sigs", 0
- ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0));
+ ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true
).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem());
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true
- ).Num(0).PushSig(keys.key1).Num(0).PushRedeem());
+ ).Num(0).PushSig(keys.key1).Num(0).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much R padding", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
+ ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much S padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much S padding", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
+ ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too little R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too little R padding", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with bad sig with too much R padding but no DERSIG", 0
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
+ ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10).ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with too much R padding but no DERSIG", 0
- ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
+ ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
+ ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 1, without DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 2, without DERSIG", 0
- ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 3, without DERSIG", 0
- ).Num(0));
+ ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0));
+ ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 4, without DERSIG", 0
).Num(0));
@@ -429,46 +496,46 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 5, without DERSIG", 0
- ).Num(1));
+ ).Num(1).ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(1));
+ ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 6, without DERSIG", 0
).Num(1));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(1));
+ ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 7, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 8, without DERSIG", 0
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 9, without DERSIG", 0
- ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 10, without DERSIG", 0
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 11, without DERSIG", 0
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 12, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
@@ -480,33 +547,33 @@ BOOST_AUTO_TEST_CASE(script_build)
).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG
- ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101"));
+ ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101").ScriptError(SCRIPT_ERR_SIG_DER));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S", SCRIPT_VERIFY_LOW_S
- ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
+ ).PushSig(keys.key2, SIGHASH_ALL, 32, 33).ScriptError(SCRIPT_ERR_SIG_HIGH_S));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key0, SIGHASH_ALL));
+ ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey but no STRICTENC", 0
- ).PushSig(keys.key0, SIGHASH_ALL));
+ ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key0, SIGHASH_ALL));
+ ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
+ ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10).ScriptError(SCRIPT_ERR_PUBKEYTYPE));
good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL));
@@ -515,62 +582,61 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key1, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC
- ).Num(0).PushSig(keys.key1, SIGHASH_ALL));
+ ).Num(0).PushSig(keys.key1, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key1, 5));
+ ).PushSig(keys.key1, 5).ScriptError(SCRIPT_ERR_SIG_HASHTYPE));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key1, 5).DamagePush(10));
+ ).PushSig(keys.key1, 5).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_HASHTYPE));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3 with nonzero dummy but no NULLDUMMY", 0
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
- ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
+ ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT,
"3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT,
"3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
- ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
+ ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY
- ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
+ ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0
- ).PushSig(keys.key2).PushRedeem());
+ ).PushSig(keys.key2).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY
- ).PushSig(keys.key2).PushRedeem());
+ ).PushSig(keys.key2).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).PushSig(keys.key1));
-
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH
).Num(11).PushSig(keys.key0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH
- ).Num(11).PushSig(keys.key0));
+ ).Num(11).PushSig(keys.key0).ScriptError(SCRIPT_ERR_CLEANSTACK));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true
).Num(11).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
- ).Num(11).PushSig(keys.key0).PushRedeem());
+ ).Num(11).PushSig(keys.key0).PushRedeem().ScriptError(SCRIPT_ERR_CLEANSTACK));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem());
@@ -585,11 +651,11 @@ BOOST_AUTO_TEST_CASE(script_build)
for (unsigned int idx = 0; idx < json_good.size(); idx++) {
const UniValue& tv = json_good[idx];
- tests_good.insert(tv.get_array().write());
+ tests_good.insert(tv.get_array().write(1,4));
}
for (unsigned int idx = 0; idx < json_bad.size(); idx++) {
const UniValue& tv = json_bad[idx];
- tests_bad.insert(tv.get_array().write());
+ tests_bad.insert(tv.get_array().write(1,4));
}
}
@@ -598,7 +664,7 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- std::string str = test.GetJSON().write();
+ std::string str = test.GetJSON().write(1,4);
#ifndef UPDATE_JSON_TESTS
if (tests_good.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
@@ -608,7 +674,7 @@ BOOST_AUTO_TEST_CASE(script_build)
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- std::string str = test.GetJSON().write();
+ std::string str = test.GetJSON().write(1,4);
#ifndef UPDATE_JSON_TESTS
if (tests_bad.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
@@ -652,7 +718,7 @@ BOOST_AUTO_TEST_CASE(script_valid)
CScript scriptPubKey = ParseScript(scriptPubKeyString);
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
- DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest);
+ DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest, SCRIPT_ERR_OK);
}
}
@@ -660,7 +726,6 @@ BOOST_AUTO_TEST_CASE(script_invalid)
{
// Scripts that should evaluate as invalid
UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
-
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
string strTest = test.write();
@@ -676,8 +741,12 @@ BOOST_AUTO_TEST_CASE(script_invalid)
string scriptPubKeyString = test[1].get_str();
CScript scriptPubKey = ParseScript(scriptPubKeyString);
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
+ int scriptError = -1; // Expected script error is optional, and follows comment
+ if (test.size() >= 5 && test[4].get_str() != "") {
+ scriptError = ParseScriptError(test[4].get_str());
+ }
- DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest);
+ DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest, scriptError);
}
}
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 0416d0c926..1f2e034b01 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -17,12 +17,15 @@
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
-#include "util.h"
+#include "rpc/server.h"
+#include "rpc/register.h"
#ifdef ENABLE_WALLET
#include "wallet/db.h"
#include "wallet/wallet.h"
#endif
+#include "test/testutil.h"
+
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
@@ -52,9 +55,12 @@ BasicTestingSetup::~BasicTestingSetup()
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
const CChainParams& chainparams = Params();
+ // Ideally we'd move all the RPC tests to the functional testing framework
+ // instead of unit tests, but for now we need these here.
+ RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
bitdb.MakeMock();
- walletRegisterRPCCommands();
+ RegisterWalletRPCCommands(tableRPC);
#endif
ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
@@ -151,7 +157,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
- hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount);
+ hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp);
}
void Shutdown(void* parg)
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index c623920880..769ae5a132 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -9,6 +9,7 @@
#include "key.h"
#include "pubkey.h"
#include "txdb.h"
+#include "txmempool.h"
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
@@ -71,7 +72,8 @@ struct TestMemPoolEntryHelper
bool hadNoDependencies;
bool spendsCoinbase;
unsigned int sigOpCount;
-
+ LockPoints lp;
+
TestMemPoolEntryHelper() :
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { }
diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp
new file mode 100644
index 0000000000..304cffb798
--- /dev/null
+++ b/src/test/testutil.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "testutil.h"
+
+#ifdef WIN32
+#include <shlobj.h>
+#endif
+
+#include <boost/filesystem.hpp>
+
+boost::filesystem::path GetTempPath() {
+#if BOOST_FILESYSTEM_VERSION == 3
+ return boost::filesystem::temp_directory_path();
+#else
+ // TODO: remove when we don't support filesystem v2 anymore
+ boost::filesystem::path path;
+#ifdef WIN32
+ char pszPath[MAX_PATH] = "";
+
+ if (GetTempPathA(MAX_PATH, pszPath))
+ path = boost::filesystem::path(pszPath);
+#else
+ path = boost::filesystem::path("/tmp");
+#endif
+ if (path.empty() || !boost::filesystem::is_directory(path)) {
+ LogPrintf("GetTempPath(): failed to find temp path\n");
+ return boost::filesystem::path("");
+ }
+ return path;
+#endif
+}
diff --git a/src/test/testutil.h b/src/test/testutil.h
new file mode 100644
index 0000000000..5875dc50e6
--- /dev/null
+++ b/src/test/testutil.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+/**
+ * Utility functions shared by unit tests
+ */
+#ifndef BITCOIN_TEST_TESTUTIL_H
+#define BITCOIN_TEST_TESTUTIL_H
+
+#include <boost/filesystem/path.hpp>
+
+boost::filesystem::path GetTempPath();
+
+#endif // BITCOIN_TEST_TESTUTIL_H
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index c27f194b55..d9195bf345 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -44,7 +44,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
(string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
(string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
- (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY);
+ (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
+ (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY);
unsigned int ParseScriptFlags(string strFlags)
{
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index c29e30792a..237b26329b 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 01bc2032d0..b99f952a0d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -60,6 +60,10 @@ BOOST_AUTO_TEST_CASE(util_ParseHex)
result = ParseHex("12 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
+ // Leading space must be supported (used in CDBEnv::Salvage)
+ result = ParseHex(" 89 34 56 78");
+ BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
+
// Stop parsing at invalid value
result = ParseHex("1234 invalid 1234");
BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
@@ -196,6 +200,8 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
BOOST_CHECK_EQUAL(ret, COIN*10);
BOOST_CHECK(ParseMoney("1.00", ret));
BOOST_CHECK_EQUAL(ret, COIN);
+ BOOST_CHECK(ParseMoney("1", ret));
+ BOOST_CHECK_EQUAL(ret, COIN);
BOOST_CHECK(ParseMoney("0.1", ret));
BOOST_CHECK_EQUAL(ret, COIN/10);
BOOST_CHECK(ParseMoney("0.01", ret));
@@ -215,6 +221,9 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
// Attempted 63 bit overflow should fail
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
+
+ // Parsing negative amounts must fail
+ BOOST_CHECK(!ParseMoney("-1", ret));
}
BOOST_AUTO_TEST_CASE(util_IsHex)
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
new file mode 100644
index 0000000000..1f86a06a3f
--- /dev/null
+++ b/src/test/versionbits_tests.cpp
@@ -0,0 +1,316 @@
+// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "chain.h"
+#include "random.h"
+#include "versionbits.h"
+#include "test/test_bitcoin.h"
+#include "chainparams.h"
+#include "main.h"
+#include "consensus/params.h"
+
+#include <boost/test/unit_test.hpp>
+
+/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */
+int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }
+
+static const Consensus::Params paramsDummy = Consensus::Params();
+
+class TestConditionChecker : public AbstractThresholdConditionChecker
+{
+private:
+ mutable ThresholdConditionCache cache;
+
+public:
+ int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); }
+ int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); }
+ int Period(const Consensus::Params& params) const { return 1000; }
+ int Threshold(const Consensus::Params& params) const { return 900; }
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }
+
+ ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }
+};
+
+#define CHECKERS 6
+
+class VersionBitsTester
+{
+ // A fake blockchain
+ std::vector<CBlockIndex*> vpblock;
+
+ // 6 independent checkers for the same bit.
+ // The first one performs all checks, the second only 50%, the third only 25%, etc...
+ // This is to test whether lack of cached information leads to the same results.
+ TestConditionChecker checker[CHECKERS];
+
+ // Test counter (to identify failures)
+ int num;
+
+public:
+ VersionBitsTester() : num(0) {}
+
+ VersionBitsTester& Reset() {
+ for (unsigned int i = 0; i < vpblock.size(); i++) {
+ delete vpblock[i];
+ }
+ for (unsigned int i = 0; i < CHECKERS; i++) {
+ checker[i] = TestConditionChecker();
+ }
+ vpblock.clear();
+ return *this;
+ }
+
+ ~VersionBitsTester() {
+ Reset();
+ }
+
+ VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) {
+ while (vpblock.size() < height) {
+ CBlockIndex* pindex = new CBlockIndex();
+ pindex->nHeight = vpblock.size();
+ pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL;
+ pindex->nTime = nTime;
+ pindex->nVersion = nVersion;
+ pindex->BuildSkip();
+ vpblock.push_back(pindex);
+ }
+ return *this;
+ }
+
+ VersionBitsTester& TestDefined() {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
+ VersionBitsTester& TestStarted() {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
+ VersionBitsTester& TestLockedIn() {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
+ VersionBitsTester& TestActive() {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
+ VersionBitsTester& TestFailed() {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
+ CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; }
+};
+
+BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup)
+
+BOOST_AUTO_TEST_CASE(versionbits_test)
+{
+ for (int i = 0; i < 64; i++) {
+ // DEFINED -> FAILED
+ VersionBitsTester().TestDefined()
+ .Mine(1, TestTime(1), 0x100).TestDefined()
+ .Mine(11, TestTime(11), 0x100).TestDefined()
+ .Mine(989, TestTime(989), 0x100).TestDefined()
+ .Mine(999, TestTime(20000), 0x100).TestDefined()
+ .Mine(1000, TestTime(20000), 0x100).TestFailed()
+ .Mine(1999, TestTime(30001), 0x100).TestFailed()
+ .Mine(2000, TestTime(30002), 0x100).TestFailed()
+ .Mine(2001, TestTime(30003), 0x100).TestFailed()
+ .Mine(2999, TestTime(30004), 0x100).TestFailed()
+ .Mine(3000, TestTime(30005), 0x100).TestFailed()
+
+ // DEFINED -> STARTED -> FAILED
+ .Reset().TestDefined()
+ .Mine(1, TestTime(1), 0).TestDefined()
+ .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period
+ .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks
+ .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000)
+ .Mine(4000, TestTime(20010), 0x100).TestFailed()
+
+ // DEFINED -> STARTED -> FAILED while threshold reached
+ .Reset().TestDefined()
+ .Mine(1, TestTime(1), 0).TestDefined()
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
+ .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks
+ .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new)
+ .Mine(3999, TestTime(30001), 0).TestFailed()
+ .Mine(4000, TestTime(30002), 0).TestFailed()
+ .Mine(14333, TestTime(30003), 0).TestFailed()
+ .Mine(24000, TestTime(40000), 0).TestFailed()
+
+ // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
+ .Reset().TestDefined()
+ .Mine(1, TestTime(1), 0).TestDefined()
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
+ .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks
+ .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks
+ .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000)
+ .Mine(3999, TestTime(30001), 0).TestLockedIn()
+ .Mine(4000, TestTime(30002), 0).TestActive()
+ .Mine(14333, TestTime(30003), 0).TestActive()
+ .Mine(24000, TestTime(40000), 0).TestActive();
+ }
+
+ // Sanity checks of version bit deployments
+ const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
+ for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
+ uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i);
+ // Make sure that no deployment tries to set an invalid bit.
+ BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);
+
+ // Verify that the deployment windows of different deployment using the
+ // same bit are disjoint.
+ // This test may need modification at such time as a new deployment
+ // is proposed that reuses the bit of an activated soft fork, before the
+ // end time of that soft fork. (Alternatively, the end time of that
+ // activated soft fork could be later changed to be earlier to avoid
+ // overlap.)
+ for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {
+ if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) {
+ BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||
+ mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
+{
+ // Check that ComputeBlockVersion will set the appropriate bit correctly
+ // on mainnet.
+ const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
+
+ // Use the TESTDUMMY deployment for testing purposes.
+ int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit;
+ int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime;
+ int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout;
+
+ assert(nStartTime < nTimeout);
+
+ // In the first chain, test that the bit is set by CBV until it has failed.
+ // In the second chain, test the bit is set by CBV while STARTED and
+ // LOCKED-IN, and then no longer set while ACTIVE.
+ VersionBitsTester firstChain, secondChain;
+
+ // Start generating blocks before nStartTime
+ int64_t nTime = nStartTime - 1;
+
+ // Before MedianTimePast of the chain has crossed nStartTime, the bit
+ // should not be set.
+ CBlockIndex *lastBlock = NULL;
+ lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
+
+ // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet.
+ for (int i=1; i<2012; i++) {
+ lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ // This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens
+ // to be 4, and the bit we're testing happens to be bit 28.
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
+ }
+ // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
+ // CBV should still not yet set the bit.
+ nTime = nStartTime;
+ for (int i=2012; i<=2016; i++) {
+ lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
+ }
+
+ // Advance to the next period and transition to STARTED,
+ lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ // so ComputeBlockVersion should now set the bit,
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+ // and should also be using the VERSIONBITS_TOP_BITS.
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
+
+ // Check that ComputeBlockVersion will set the bit until nTimeout
+ nTime += 600;
+ int blocksToMine = 4032; // test blocks for up to 2 time periods
+ int nHeight = 6048;
+ // These blocks are all before nTimeout is reached.
+ while (nTime < nTimeout && blocksToMine > 0) {
+ lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
+ blocksToMine--;
+ nTime += 600;
+ nHeight += 1;
+ };
+
+ nTime = nTimeout;
+ // FAILED is only triggered at the end of a period, so CBV should be setting
+ // the bit until the period transition.
+ for (int i=0; i<2015; i++) {
+ lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+ nHeight += 1;
+ }
+ // The next block should trigger no longer setting the bit.
+ lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
+
+ // On a new chain:
+ // verify that the bit will be set after lock-in, and then stop being set
+ // after activation.
+ nTime = nStartTime;
+
+ // Mine one period worth of blocks, and check that the bit will be on for the
+ // next period.
+ lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+
+ // Mine another period worth of blocks, signaling the new bit.
+ lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ // After one period of setting the bit on each block, it should have locked in.
+ // We keep setting the bit for one more period though, until activation.
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+
+ // Now check that we keep mining the block until the end of this period, and
+ // then stop at the beginning of the next period.
+ lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
+ lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
+
+ // Finally, verify that after a soft fork has activated, CBV no longer uses
+ // VERSIONBITS_LAST_OLD_BLOCK_VERSION.
+ //BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 4d2f8d1e3b..b6bcf86fbf 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -83,7 +83,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
int64_t nMedian = vTimeOffsets.median();
std::vector<int64_t> vSorted = vTimeOffsets.sorted();
// Only let other nodes change our time by so much
- if (abs64(nMedian) < 70 * 60)
+ if (abs64(nMedian) <= std::max<int64_t>(0, GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)))
{
nTimeOffset = nMedian;
}
diff --git a/src/timedata.h b/src/timedata.h
index 2296baf11b..9f2499c85c 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -10,6 +10,8 @@
#include <stdint.h>
#include <vector>
+static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60;
+
class CNetAddr;
/**
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 2c68526df4..1c7bc2dbee 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -393,11 +393,14 @@ private:
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
-TorController::TorController(struct event_base* base, const std::string& target):
- base(base),
+TorController::TorController(struct event_base* baseIn, const std::string& target):
+ base(baseIn),
target(target), conn(base), reconnect(true), reconnect_ev(0),
reconnect_timeout(RECONNECT_TIMEOUT_START)
{
+ reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
+ if (!reconnect_ev)
+ LogPrintf("tor: Failed to create event for reconnection: out of memory?\n");
// Start connection attempts immediately
if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),
boost::bind(&TorController::disconnected_cb, this, _1) )) {
@@ -413,8 +416,10 @@ TorController::TorController(struct event_base* base, const std::string& target)
TorController::~TorController()
{
- if (reconnect_ev)
- event_del(reconnect_ev);
+ if (reconnect_ev) {
+ event_free(reconnect_ev);
+ reconnect_ev = 0;
+ }
if (service.IsValid()) {
RemoveLocal(service);
}
@@ -434,7 +439,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep
}
service = CService(service_id+".onion", GetListenPort(), false);
- LogPrintf("tor: Got service ID %s, advertizing service %s\n", service_id, service.ToString());
+ LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile());
} else {
@@ -459,7 +464,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r
if (GetArg("-onion", "") == "") {
proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true);
SetProxy(NET_TOR, addrOnion);
- SetReachable(NET_TOR);
+ SetLimited(NET_TOR, false);
}
// Finally - now create the service
@@ -615,7 +620,7 @@ void TorController::connected_cb(TorControlConnection& conn)
void TorController::disconnected_cb(TorControlConnection& conn)
{
- // Stop advertizing service when disconnected
+ // Stop advertising service when disconnected
if (service.IsValid())
RemoveLocal(service);
service = CService();
@@ -626,8 +631,8 @@ void TorController::disconnected_cb(TorControlConnection& conn)
// Single-shot timer for reconnect. Use exponential backoff.
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
- reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
- event_add(reconnect_ev, &time);
+ if (reconnect_ev)
+ event_add(reconnect_ev, &time);
reconnect_timeout *= RECONNECT_TIMEOUT_EXP;
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index f8e03c2533..52c7793118 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -22,10 +22,10 @@ using namespace std;
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
bool poolHasNoInputsOf, CAmount _inChainInputValue,
- bool _spendsCoinbase, unsigned int _sigOps):
+ bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp):
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
- spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps)
+ spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp)
{
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
nModSize = tx.CalculateModifiedSize(nTxSize);
@@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
assert(inChainInputValue <= nValueIn);
feeDelta = 0;
+
+ nCountWithAncestors = 1;
+ nSizeWithAncestors = nTxSize;
+ nModFeesWithAncestors = nFee;
+ nSigOpCountWithAncestors = sigOpCount;
}
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
@@ -58,27 +63,25 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
+ nModFeesWithAncestors += newFeeDelta - feeDelta;
feeDelta = newFeeDelta;
}
+void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
+{
+ lockPoints = lp;
+}
+
// Update the given tx for any in-mempool descendants.
// Assumes that setMemPoolChildren is correct for the given tx and all
// descendants.
-bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
+void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
{
- // Track the number of entries (outside setExclude) that we'd need to visit
- // (will bail out if it exceeds maxDescendantsToVisit)
- int nChildrenToVisit = 0;
-
setEntries stageEntries, setAllDescendants;
stageEntries = GetMemPoolChildren(updateIt);
while (!stageEntries.empty()) {
const txiter cit = *stageEntries.begin();
- if (cit->IsDirty()) {
- // Don't consider any more children if any descendant is dirty
- return false;
- }
setAllDescendants.insert(cit);
stageEntries.erase(cit);
const setEntries &setChildren = GetMemPoolChildren(cit);
@@ -88,22 +91,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
// We've already calculated this one, just add the entries for this set
// but don't traverse again.
BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) {
- // update visit count only for new child transactions
- // (outside of setExclude and stageEntries)
- if (setAllDescendants.insert(cacheEntry).second &&
- !setExclude.count(cacheEntry->GetTx().GetHash()) &&
- !stageEntries.count(cacheEntry)) {
- nChildrenToVisit++;
- }
+ setAllDescendants.insert(cacheEntry);
}
} else if (!setAllDescendants.count(childEntry)) {
- // Schedule for later processing and update our visit count
- if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) {
- nChildrenToVisit++;
- }
- }
- if (nChildrenToVisit > maxDescendantsToVisit) {
- return false;
+ // Schedule for later processing
+ stageEntries.insert(childEntry);
}
}
}
@@ -118,16 +110,18 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
modifyFee += cit->GetModifiedFee();
modifyCount++;
cachedDescendants[updateIt].insert(cit);
+ // Update ancestor state for each descendant
+ mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount()));
}
}
mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
- return true;
}
// vHashesToUpdate is the set of transaction hashes from a disconnected block
// which has been re-added to the mempool.
// for each entry, look for descendants that are outside hashesToUpdate, and
// add fee/size information for such descendants to the parent.
+// for each such descendant, also update the ancestor state to include the parent.
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate)
{
LOCK(cs);
@@ -167,14 +161,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
UpdateParent(childIter, it, true);
}
}
- if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) {
- // Mark as dirty if we can't do the calculation.
- mapTx.modify(it, set_dirty());
- }
+ UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded);
}
}
-bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */)
+bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const
{
setEntries parentHashes;
const CTransaction &tx = entry.GetTx();
@@ -251,6 +242,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
}
}
+void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors)
+{
+ int64_t updateCount = setAncestors.size();
+ int64_t updateSize = 0;
+ CAmount updateFee = 0;
+ int updateSigOps = 0;
+ BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ updateSize += ancestorIt->GetTxSize();
+ updateFee += ancestorIt->GetModifiedFee();
+ updateSigOps += ancestorIt->GetSigOpCount();
+ }
+ mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps));
+}
+
void CTxMemPool::UpdateChildrenForRemoval(txiter it)
{
const setEntries &setMemPoolChildren = GetMemPoolChildren(it);
@@ -259,11 +264,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it)
}
}
-void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
+void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants)
{
// For each entry, walk back all ancestors and decrement size associated with this
// transaction
const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ if (updateDescendants) {
+ // updateDescendants should be true whenever we're not recursively
+ // removing a tx and all its descendants, eg when a transaction is
+ // confirmed in a block.
+ // Here we only update statistics and not data in mapLinks (which
+ // we need to preserve until we're finished with all operations that
+ // need to traverse the mempool).
+ BOOST_FOREACH(txiter removeIt, entriesToRemove) {
+ setEntries setDescendants;
+ CalculateDescendants(removeIt, setDescendants);
+ setDescendants.erase(removeIt); // don't update state for self
+ int64_t modifySize = -((int64_t)removeIt->GetTxSize());
+ CAmount modifyFee = -removeIt->GetModifiedFee();
+ int modifySigOps = -removeIt->GetSigOpCount();
+ BOOST_FOREACH(txiter dit, setDescendants) {
+ mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps));
+ }
+ }
+ }
BOOST_FOREACH(txiter removeIt, entriesToRemove) {
setEntries setAncestors;
const CTxMemPoolEntry &entry = *removeIt;
@@ -287,10 +311,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
// transactions as the set of things to update for removal.
CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
// Note that UpdateAncestorsOf severs the child links that point to
- // removeIt in the entries for the parents of removeIt. This is
- // fine since we don't need to use the mempool children of any entries
- // to walk back over our ancestors (but we do need the mempool
- // parents!)
+ // removeIt in the entries for the parents of removeIt.
UpdateAncestorsOf(false, removeIt, setAncestors);
}
// After updating all the ancestor sizes, we can now sever the link between each
@@ -301,22 +322,24 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
}
}
-void CTxMemPoolEntry::SetDirty()
+void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
{
- nCountWithDescendants = 0;
- nSizeWithDescendants = nTxSize;
- nModFeesWithDescendants = GetModifiedFee();
+ nSizeWithDescendants += modifySize;
+ assert(int64_t(nSizeWithDescendants) > 0);
+ nModFeesWithDescendants += modifyFee;
+ nCountWithDescendants += modifyCount;
+ assert(int64_t(nCountWithDescendants) > 0);
}
-void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
+void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps)
{
- if (!IsDirty()) {
- nSizeWithDescendants += modifySize;
- assert(int64_t(nSizeWithDescendants) > 0);
- nModFeesWithDescendants += modifyFee;
- nCountWithDescendants += modifyCount;
- assert(int64_t(nCountWithDescendants) > 0);
- }
+ nSizeWithAncestors += modifySize;
+ assert(int64_t(nSizeWithAncestors) > 0);
+ nModFeesWithAncestors += modifyFee;
+ nCountWithAncestors += modifyCount;
+ assert(int64_t(nCountWithAncestors) > 0);
+ nSigOpCountWithAncestors += modifySigOps;
+ assert(int(nSigOpCountWithAncestors) >= 0);
}
CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
@@ -409,6 +432,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
}
UpdateAncestorsOf(true, newit, setAncestors);
+ UpdateEntryForAncestors(newit, setAncestors);
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
@@ -461,7 +485,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants
}
}
-void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive)
+void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list<CTransaction>& removed)
{
// Remove transaction from memory pool
{
@@ -470,8 +494,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
txiter origit = mapTx.find(origTx.GetHash());
if (origit != mapTx.end()) {
txToRemove.insert(origit);
- } else if (fRecursive) {
- // If recursively removing but origTx isn't in the mempool
+ } else {
+ // When recursively removing but origTx isn't in the mempool
// be sure to remove any children that are in the pool. This can
// happen during chain re-orgs if origTx isn't re-accepted into
// the mempool for any reason.
@@ -485,17 +509,13 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
}
}
setEntries setAllRemoves;
- if (fRecursive) {
- BOOST_FOREACH(txiter it, txToRemove) {
- CalculateDescendants(it, setAllRemoves);
- }
- } else {
- setAllRemoves.swap(txToRemove);
+ BOOST_FOREACH(txiter it, txToRemove) {
+ CalculateDescendants(it, setAllRemoves);
}
BOOST_FOREACH(txiter it, setAllRemoves) {
removed.push_back(it->GetTx());
}
- RemoveStaged(setAllRemoves);
+ RemoveStaged(setAllRemoves, false);
}
}
@@ -506,7 +526,11 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
list<CTransaction> transactionsToRemove;
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
const CTransaction& tx = it->GetTx();
- if (!CheckFinalTx(tx, flags)) {
+ LockPoints lp = it->GetLockPoints();
+ bool validLP = TestLockPointValidity(&lp);
+ if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) {
+ // Note if CheckSequenceLocks fails the LockPoints may still be invalid
+ // So it's critical that we remove the tx and not depend on the LockPoints.
transactionsToRemove.push_back(tx);
} else if (it->GetSpendsCoinbase()) {
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
@@ -521,10 +545,13 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
}
}
}
+ if (!validLP) {
+ mapTx.modify(it, update_lock_points(lp));
+ }
}
BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) {
list<CTransaction> removed;
- remove(tx, removed, true);
+ removeRecursive(tx, removed);
}
}
@@ -539,7 +566,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
const CTransaction &txConflict = *it->second.ptx;
if (txConflict != tx)
{
- remove(txConflict, removed, true);
+ removeRecursive(txConflict, removed);
ClearPrioritisation(txConflict.GetHash());
}
}
@@ -564,8 +591,12 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
}
BOOST_FOREACH(const CTransaction& tx, vtx)
{
- std::list<CTransaction> dummy;
- remove(tx, dummy, false);
+ txiter it = mapTx.find(tx.GetHash());
+ if (it != mapTx.end()) {
+ setEntries stage;
+ stage.insert(it);
+ RemoveStaged(stage, true);
+ }
removeConflicts(tx, conflicts);
ClearPrioritisation(tx.GetHash());
}
@@ -622,6 +653,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);
bool fDependsWait = false;
setEntries setParentCheck;
+ int64_t parentSizes = 0;
+ unsigned int parentSigOpCount = 0;
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
@@ -629,7 +662,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
fDependsWait = true;
- setParentCheck.insert(it2);
+ if (setParentCheck.insert(it2).second) {
+ parentSizes += it2->GetTxSize();
+ parentSigOpCount += it2->GetSigOpCount();
+ }
} else {
const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
assert(coins && coins->IsAvailable(txin.prevout.n));
@@ -642,28 +678,42 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
i++;
}
assert(setParentCheck == GetMemPoolParents(it));
+ // Verify ancestor state is correct.
+ setEntries setAncestors;
+ uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ std::string dummy;
+ CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
+ uint64_t nCountCheck = setAncestors.size() + 1;
+ uint64_t nSizeCheck = it->GetTxSize();
+ CAmount nFeesCheck = it->GetModifiedFee();
+ unsigned int nSigOpCheck = it->GetSigOpCount();
+
+ BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ nSizeCheck += ancestorIt->GetTxSize();
+ nFeesCheck += ancestorIt->GetModifiedFee();
+ nSigOpCheck += ancestorIt->GetSigOpCount();
+ }
+
+ assert(it->GetCountWithAncestors() == nCountCheck);
+ assert(it->GetSizeWithAncestors() == nSizeCheck);
+ assert(it->GetSigOpCountWithAncestors() == nSigOpCheck);
+ assert(it->GetModFeesWithAncestors() == nFeesCheck);
+
// Check children against mapNextTx
CTxMemPool::setEntries setChildrenCheck;
std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
int64_t childSizes = 0;
- CAmount childModFee = 0;
for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second.ptx->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
if (setChildrenCheck.insert(childit).second) {
childSizes += childit->GetTxSize();
- childModFee += childit->GetModifiedFee();
}
}
assert(setChildrenCheck == GetMemPoolChildren(it));
// Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
- if (!it->IsDirty()) {
- assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
- } else {
- assert(it->GetSizeWithDescendants() == it->GetTxSize());
- assert(it->GetModFeesWithDescendants() == it->GetModifiedFee());
- }
+ assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
@@ -721,6 +771,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
return true;
}
+bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
+{
+ LOCK(cs);
+ indexed_transaction_set::const_iterator i = mapTx.find(hash);
+ if (i == mapTx.end())
+ return false;
+ feeRate = CFeeRate(i->GetFee(), i->GetTxSize());
+ return true;
+}
+
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
{
LOCK(cs);
@@ -845,13 +905,13 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
size_t CTxMemPool::DynamicMemoryUsage() const {
LOCK(cs);
- // Estimate the overhead of mapTx to be 12 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
- return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage;
+ // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
+ return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage;
}
-void CTxMemPool::RemoveStaged(setEntries &stage) {
+void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) {
AssertLockHeld(cs);
- UpdateForRemoveFromMempool(stage);
+ UpdateForRemoveFromMempool(stage, updateDescendants);
BOOST_FOREACH(const txiter& it, stage) {
removeUnchecked(it);
}
@@ -859,9 +919,9 @@ void CTxMemPool::RemoveStaged(setEntries &stage) {
int CTxMemPool::Expire(int64_t time) {
LOCK(cs);
- indexed_transaction_set::nth_index<2>::type::iterator it = mapTx.get<2>().begin();
+ indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin();
setEntries toremove;
- while (it != mapTx.get<2>().end() && it->GetTime() < time) {
+ while (it != mapTx.get<entry_time>().end() && it->GetTime() < time) {
toremove.insert(mapTx.project<0>(it));
it++;
}
@@ -869,7 +929,7 @@ int CTxMemPool::Expire(int64_t time) {
BOOST_FOREACH(txiter removeit, toremove) {
CalculateDescendants(removeit, stage);
}
- RemoveStaged(stage);
+ RemoveStaged(stage, false);
return stage.size();
}
@@ -957,7 +1017,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
unsigned nTxnRemoved = 0;
CFeeRate maxFeeRateRemoved(0);
while (DynamicMemoryUsage() > sizelimit) {
- indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin();
+ indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin();
// We set the new mempool min fee to the feerate of the removed set, plus the
// "minimum reasonable fee rate" (ie some value under which we consider txn
@@ -978,7 +1038,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
BOOST_FOREACH(txiter it, stage)
txn.push_back(it->GetTx());
}
- RemoveStaged(stage);
+ RemoveStaged(stage, false);
if (pvNoSpendsRemaining) {
BOOST_FOREACH(const CTransaction& tx, txn) {
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
diff --git a/src/txmempool.h b/src/txmempool.h
index 386cb26d25..9dbb37dad0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -19,6 +19,7 @@
#include "boost/multi_index/ordered_index.hpp"
class CAutoFile;
+class CBlockIndex;
inline double AllowFreeThreshold()
{
@@ -35,6 +36,21 @@ 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;
+struct LockPoints
+{
+ // Will be set to the blockchain height and median time past
+ // values that would be necessary to satisfy all relative locktime
+ // constraints (BIP68) of this tx given our view of block chain history
+ int height;
+ int64_t time;
+ // As long as the current chain descends from the highest height block
+ // containing one of the inputs used in the calculation, then the cached
+ // values are still valid even after a reorg.
+ CBlockIndex* maxInputBlock;
+
+ LockPoints() : height(0), time(0), maxInputBlock(NULL) { }
+};
+
class CTxMemPool;
/** \class CTxMemPoolEntry
@@ -70,6 +86,7 @@ private:
bool spendsCoinbase; //! keep track of transactions that spend a coinbase
unsigned int sigOpCount; //! Legacy sig ops plus P2SH sig op count
int64_t feeDelta; //! Used for determining the priority of the transaction for mining in a block
+ LockPoints lockPoints; //! Track the height and time at which tx was final
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
@@ -80,11 +97,17 @@ private:
uint64_t nSizeWithDescendants; //! ... and size
CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
+ // Analogous statistics for ancestor transactions
+ uint64_t nCountWithAncestors;
+ uint64_t nSizeWithAncestors;
+ CAmount nModFeesWithAncestors;
+ unsigned int nSigOpCountWithAncestors;
+
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase,
- unsigned int nSigOps);
+ unsigned int nSigOps, LockPoints lp);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return this->tx; }
@@ -101,25 +124,28 @@ public:
unsigned int GetSigOpCount() const { return sigOpCount; }
int64_t GetModifiedFee() const { return nFee + feeDelta; }
size_t DynamicMemoryUsage() const { return nUsageSize; }
+ const LockPoints& GetLockPoints() const { return lockPoints; }
// Adjusts the descendant state, if this entry is not dirty.
- void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ // Adjusts the ancestor state
+ void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
-
- /** We can set the entry to be dirty if doing the full calculation of in-
- * mempool descendants will be too expensive, which can potentially happen
- * when re-adding transactions from a block back to the mempool.
- */
- void SetDirty();
- bool IsDirty() const { return nCountWithDescendants == 0; }
+ // Update the LockPoints after a reorg
+ void UpdateLockPoints(const LockPoints& lp);
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
+
+ uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
+ uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
+ CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
+ unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; }
};
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
@@ -130,7 +156,7 @@ struct update_descendant_state
{}
void operator() (CTxMemPoolEntry &e)
- { e.UpdateState(modifySize, modifyFee, modifyCount); }
+ { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }
private:
int64_t modifySize;
@@ -138,10 +164,20 @@ struct update_descendant_state
int64_t modifyCount;
};
-struct set_dirty
+struct update_ancestor_state
{
+ update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int _modifySigOps) :
+ modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOps(_modifySigOps)
+ {}
+
void operator() (CTxMemPoolEntry &e)
- { e.SetDirty(); }
+ { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOps); }
+
+ private:
+ int64_t modifySize;
+ CAmount modifyFee;
+ int64_t modifyCount;
+ int modifySigOps;
};
struct update_fee_delta
@@ -154,6 +190,16 @@ private:
int64_t feeDelta;
};
+struct update_lock_points
+{
+ update_lock_points(const LockPoints& _lp) : lp(_lp) { }
+
+ void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
+
+private:
+ const LockPoints& lp;
+};
+
// extracts a TxMemPoolEntry's transaction hash
struct mempoolentry_txid
{
@@ -228,6 +274,35 @@ public:
}
};
+class CompareTxMemPoolEntryByAncestorFee
+{
+public:
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ {
+ double aFees = a.GetModFeesWithAncestors();
+ double aSize = a.GetSizeWithAncestors();
+
+ double bFees = b.GetModFeesWithAncestors();
+ double bSize = b.GetSizeWithAncestors();
+
+ // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
+ double f1 = aFees * bSize;
+ double f2 = aSize * bFees;
+
+ if (f1 == f2) {
+ return a.GetTx().GetHash() < b.GetTx().GetHash();
+ }
+
+ return f1 > f2;
+ }
+};
+
+// Multi_index tag names
+struct descendant_score {};
+struct entry_time {};
+struct mining_score {};
+struct ancestor_score {};
+
class CBlockPolicyEstimator;
/** An inpoint - a combination of a transaction and an index n into its vin */
@@ -350,18 +425,27 @@ public:
boost::multi_index::ordered_unique<mempoolentry_txid>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<descendant_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByDescendantScore
>,
// sorted by entry time
boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<entry_time>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByEntryTime
- >,
+ >,
// sorted by score (for mining prioritization)
boost::multi_index::ordered_unique<
+ boost::multi_index::tag<mining_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByScore
+ >,
+ // sorted by fee rate with ancestors
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<ancestor_score>,
+ boost::multi_index::identity<CTxMemPoolEntry>,
+ CompareTxMemPoolEntryByAncestorFee
>
>
> indexed_transaction_set;
@@ -420,7 +504,7 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true);
- void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
+ void removeRecursive(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
@@ -445,8 +529,12 @@ public:
public:
/** Remove a set of transactions from the mempool.
* If a transaction is in this set, then all in-mempool descendants must
- * also be in the set.*/
- void RemoveStaged(setEntries &stage);
+ * also be in the set, unless this transaction is being removed for being
+ * in a block.
+ * Set updateDescendants to true when removing a tx that was in a block, so
+ * that any in-mempool descendants have their ancestor state updated.
+ */
+ void RemoveStaged(setEntries &stage, bool updateDescendants);
/** When adding transactions from a disconnected block back to the mempool,
* new mempool entries may have children in the mempool (which is generally
@@ -469,7 +557,7 @@ public:
* fSearchForParents = whether to search a tx's vin for in-mempool parents, or
* look up parents from mapLinks. Must be true for entries not in the mempool
*/
- bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true);
+ bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const;
/** Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of anything
@@ -512,6 +600,7 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+ bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
@@ -547,21 +636,21 @@ private:
* updated and hence their state is already reflected in the parent
* state).
*
- * If updating an entry requires looking at more than maxDescendantsToVisit
- * transactions, outside of the ones in setExclude, then give up.
- *
* cachedDescendants will be updated with the descendants of the transaction
* being updated, so that future invocations don't need to walk the
* same transaction again, if encountered in another transaction chain.
*/
- bool UpdateForDescendants(txiter updateIt,
- int maxDescendantsToVisit,
+ void UpdateForDescendants(txiter updateIt,
cacheMap &cachedDescendants,
const std::set<uint256> &setExclude);
/** Update ancestors of hash to add/remove it as a descendant transaction. */
void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors);
- /** For each transaction being removed, update ancestors and any direct children. */
- void UpdateForRemoveFromMempool(const setEntries &entriesToRemove);
+ /** Set ancestor state for an entry */
+ void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors);
+ /** For each transaction being removed, update ancestors and any direct children.
+ * If updateDescendants is true, then also update in-mempool descendants'
+ * ancestor state. */
+ void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants);
/** Sever link between specified transaction and direct children. */
void UpdateChildrenForRemoval(txiter entry);
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 967d243270..0b51d52e65 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -83,10 +83,9 @@ public:
boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
/**
- * New, updated or cancelled alert.
- * @note called with lock cs_mapAlerts held.
+ * Status bar alerts changed.
*/
- boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;
+ boost::signals2::signal<void ()> NotifyAlertChanged;
/** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet;
diff --git a/src/uint256.h b/src/uint256.h
index 4495000f2f..bcdb6dd7c2 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -42,9 +42,11 @@ public:
memset(data, 0, sizeof(data));
}
- friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; }
- friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; }
- friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; }
+ inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); }
+
+ friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
+ friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
+ friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
std::string GetHex() const;
void SetHex(const char* psz);
diff --git a/src/util.cpp b/src/util.cpp
index 492697e12f..59f58f2c55 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -738,28 +738,6 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
}
#endif
-boost::filesystem::path GetTempPath() {
-#if BOOST_FILESYSTEM_VERSION == 3
- return boost::filesystem::temp_directory_path();
-#else
- // TODO: remove when we don't support filesystem v2 anymore
- boost::filesystem::path path;
-#ifdef WIN32
- char pszPath[MAX_PATH] = "";
-
- if (GetTempPathA(MAX_PATH, pszPath))
- path = boost::filesystem::path(pszPath);
-#else
- path = boost::filesystem::path("/tmp");
-#endif
- if (path.empty() || !boost::filesystem::is_directory(path)) {
- LogPrintf("GetTempPath(): failed to find temp path\n");
- return boost::filesystem::path("");
- }
- return path;
-#endif
-}
-
void runCommand(const std::string& strCommand)
{
int nErr = ::system(strCommand.c_str());
diff --git a/src/util.h b/src/util.h
index 9da8fdf87a..ac099f1184 100644
--- a/src/util.h
+++ b/src/util.h
@@ -133,7 +133,6 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
-boost::filesystem::path GetTempPath();
void OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
diff --git a/src/version.h b/src/version.h
index f7cf18d0b6..0e1d8a63ce 100644
--- a/src/version.h
+++ b/src/version.h
@@ -9,7 +9,7 @@
* network protocol versioning
*/
-static const int PROTOCOL_VERSION = 70012;
+static const int PROTOCOL_VERSION = 70013;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@@ -24,10 +24,6 @@ static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION;
//! if possible, avoid requesting addresses nodes older than this
static const int CADDR_TIME_VERSION = 31402;
-//! only request blocks from nodes outside this range of versions
-static const int NOBLKS_VERSION_START = 32000;
-static const int NOBLKS_VERSION_END = 32400;
-
//! BIP 0031, pong message, is enabled for all versions AFTER this one
static const int BIP0031_VERSION = 60000;
@@ -40,4 +36,7 @@ static const int NO_BLOOM_VERSION = 70011;
//! "sendheaders" command and announcing blocks with headers starts with this version
static const int SENDHEADERS_VERSION = 70012;
+//! "feefilter" tells peers to filter invs to you by fee starts with this version
+static const int FEEFILTER_VERSION = 70013;
+
#endif // BITCOIN_VERSION_H
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
new file mode 100644
index 0000000000..fbb60c0fc5
--- /dev/null
+++ b/src/versionbits.cpp
@@ -0,0 +1,133 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "versionbits.h"
+
+ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
+{
+ int nPeriod = Period(params);
+ int nThreshold = Threshold(params);
+ int64_t nTimeStart = BeginTime(params);
+ int64_t nTimeTimeout = EndTime(params);
+
+ // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
+ if (pindexPrev != NULL) {
+ pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
+ }
+
+ // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
+ std::vector<const CBlockIndex*> vToCompute;
+ while (cache.count(pindexPrev) == 0) {
+ if (pindexPrev == NULL) {
+ // The genesis block is by definition defined.
+ cache[pindexPrev] = THRESHOLD_DEFINED;
+ break;
+ }
+ if (pindexPrev->GetMedianTimePast() < nTimeStart) {
+ // Optimizaton: don't recompute down further, as we know every earlier block will be before the start time
+ cache[pindexPrev] = THRESHOLD_DEFINED;
+ break;
+ }
+ vToCompute.push_back(pindexPrev);
+ pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
+ }
+
+ // At this point, cache[pindexPrev] is known
+ assert(cache.count(pindexPrev));
+ ThresholdState state = cache[pindexPrev];
+
+ // Now walk forward and compute the state of descendants of pindexPrev
+ while (!vToCompute.empty()) {
+ ThresholdState stateNext = state;
+ pindexPrev = vToCompute.back();
+ vToCompute.pop_back();
+
+ switch (state) {
+ case THRESHOLD_DEFINED: {
+ if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
+ stateNext = THRESHOLD_FAILED;
+ } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
+ stateNext = THRESHOLD_STARTED;
+ }
+ break;
+ }
+ case THRESHOLD_STARTED: {
+ if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
+ stateNext = THRESHOLD_FAILED;
+ break;
+ }
+ // We need to count
+ const CBlockIndex* pindexCount = pindexPrev;
+ int count = 0;
+ for (int i = 0; i < nPeriod; i++) {
+ if (Condition(pindexCount, params)) {
+ count++;
+ }
+ pindexCount = pindexCount->pprev;
+ }
+ if (count >= nThreshold) {
+ stateNext = THRESHOLD_LOCKED_IN;
+ }
+ break;
+ }
+ case THRESHOLD_LOCKED_IN: {
+ // Always progresses into ACTIVE.
+ stateNext = THRESHOLD_ACTIVE;
+ break;
+ }
+ case THRESHOLD_FAILED:
+ case THRESHOLD_ACTIVE: {
+ // Nothing happens, these are terminal states.
+ break;
+ }
+ }
+ cache[pindexPrev] = state = stateNext;
+ }
+
+ return state;
+}
+
+namespace
+{
+/**
+ * Class to implement versionbits logic.
+ */
+class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
+private:
+ const Consensus::DeploymentPos id;
+
+protected:
+ int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; }
+ int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; }
+ int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
+ int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
+
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
+ {
+ return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
+ }
+
+public:
+ VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
+ uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
+};
+
+}
+
+ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
+{
+ return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
+}
+
+uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)
+{
+ return VersionBitsConditionChecker(pos).Mask(params);
+}
+
+void VersionBitsCache::Clear()
+{
+ for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
+ caches[d].clear();
+ }
+}
diff --git a/src/versionbits.h b/src/versionbits.h
new file mode 100644
index 0000000000..04f4738272
--- /dev/null
+++ b/src/versionbits.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CONSENSUS_VERSIONBITS
+#define BITCOIN_CONSENSUS_VERSIONBITS
+
+#include "chain.h"
+#include <map>
+
+/** What block version to use for new blocks (pre versionbits) */
+static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;
+/** What bits to set in version for versionbits blocks */
+static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL;
+/** What bitmask determines whether versionbits is in use */
+static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;
+/** Total bits available for versionbits */
+static const int32_t VERSIONBITS_NUM_BITS = 29;
+
+enum ThresholdState {
+ THRESHOLD_DEFINED,
+ THRESHOLD_STARTED,
+ THRESHOLD_LOCKED_IN,
+ THRESHOLD_ACTIVE,
+ THRESHOLD_FAILED,
+};
+
+// A map that gives the state for blocks whose height is a multiple of Period().
+// The map is indexed by the block's parent, however, so all keys in the map
+// will either be NULL or a block with (height + 1) % Period() == 0.
+typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
+
+/**
+ * Abstract class that implements BIP9-style threshold logic, and caches results.
+ */
+class AbstractThresholdConditionChecker {
+protected:
+ virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0;
+ virtual int64_t BeginTime(const Consensus::Params& params) const =0;
+ virtual int64_t EndTime(const Consensus::Params& params) const =0;
+ virtual int Period(const Consensus::Params& params) const =0;
+ virtual int Threshold(const Consensus::Params& params) const =0;
+
+public:
+ // Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent.
+ ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
+};
+
+struct VersionBitsCache
+{
+ ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];
+
+ void Clear();
+};
+
+ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
+uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
+
+#endif
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 50b0f40a6a..c906785e9e 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -165,6 +165,11 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
}
+/* End of headers, beginning of key/value data */
+static const char *HEADER_END = "HEADER=END";
+/* End of key/value data */
+static const char *DATA_END = "DATA=END";
+
bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
{
LOCK(cs_db);
@@ -193,24 +198,35 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
// Format of bdb dump is ascii lines:
// header lines...
// HEADER=END
- // hexadecimal key
- // hexadecimal value
- // ... repeated
+ // hexadecimal key
+ // hexadecimal value
+ // ... repeated
// DATA=END
string strLine;
- while (!strDump.eof() && strLine != "HEADER=END")
+ while (!strDump.eof() && strLine != HEADER_END)
getline(strDump, strLine); // Skip past header
std::string keyHex, valueHex;
- while (!strDump.eof() && keyHex != "DATA=END") {
+ while (!strDump.eof() && keyHex != DATA_END) {
getline(strDump, keyHex);
- if (keyHex != "DATA=END") {
+ if (keyHex != DATA_END) {
+ if (strDump.eof())
+ break;
getline(strDump, valueHex);
+ if (valueHex == DATA_END) {
+ LogPrintf("CDBEnv::Salvage: WARNING: Number of keys in data does not match number of values.\n");
+ break;
+ }
vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
}
}
+ if (keyHex != DATA_END) {
+ LogPrintf("CDBEnv::Salvage: WARNING: Unexpected end of file while reading salvage output.\n");
+ return false;
+ }
+
return (result == 0);
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 9ec28e7b91..bb40cf7245 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -13,6 +13,8 @@
#include "util.h"
#include "utiltime.h"
#include "wallet.h"
+#include "merkleblock.h"
+#include "core_io.h"
#include <fstream>
#include <stdint.h>
@@ -192,7 +194,7 @@ UniValue importaddress(const UniValue& params, bool fHelp)
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
- "If you have the full public key, you should call importpublickey instead of this.\n"
+ "If you have the full public key, you should call importpubkey instead of this.\n"
"\nExamples:\n"
"\nImport a script with rescan\n"
+ HelpExampleCli("importaddress", "\"myscript\"") +
@@ -243,6 +245,109 @@ UniValue importaddress(const UniValue& params, bool fHelp)
return NullUniValue;
}
+UniValue importprunedfunds(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ throw runtime_error(
+ "importprunedfunds\n"
+ "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
+ "\nArguments:\n"
+ "1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
+ "2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
+ "3. \"label\" (string, optional) An optional label\n"
+ );
+
+ CTransaction tx;
+ if (!DecodeHexTx(tx, params[0].get_str()))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+ uint256 hashTx = tx.GetHash();
+ CWalletTx wtx(pwalletMain,tx);
+
+ CDataStream ssMB(ParseHexV(params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ CMerkleBlock merkleBlock;
+ ssMB >> merkleBlock;
+
+ string strLabel = "";
+ if (params.size() == 3)
+ strLabel = params[2].get_str();
+
+ //Search partial merkle tree in proof for our transaction and index in valid block
+ vector<uint256> vMatch;
+ vector<unsigned int> vIndex;
+ unsigned int txnIndex = 0;
+ if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
+
+ LOCK(cs_main);
+
+ if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
+
+ vector<uint256>::const_iterator it;
+ if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
+ }
+
+ txnIndex = vIndex[it - vMatch.begin()];
+ }
+ else {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
+ }
+
+ wtx.nIndex = txnIndex;
+ wtx.hashBlock = merkleBlock.header.GetHash();
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ if (pwalletMain->IsMine(tx)) {
+ CWalletDB walletdb(pwalletMain->strWalletFile, "r+", false);
+ pwalletMain->AddToWallet(wtx, false, &walletdb);
+ return NullUniValue;
+ }
+
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
+}
+
+UniValue removeprunedfunds(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "removeprunedfunds \"txid\"\n"
+ "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n"
+ "\nArguments:\n"
+ "1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n"
+ "\nExamples:\n"
+ + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
+ );
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+ vector<uint256> vHash;
+ vHash.push_back(hash);
+ vector<uint256> vHashOut;
+
+ if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
+ }
+
+ if(vHashOut.empty()) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
+ }
+
+ ThreadFlushWalletDB(pwalletMain->strWalletFile);
+
+ return NullUniValue;
+}
+
UniValue importpubkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 857a3a77e2..61c9846e11 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -394,7 +394,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
}
UniValue sendtoaddress(const UniValue& params, bool fHelp)
@@ -1245,7 +1245,7 @@ UniValue listreceivedbyaddress(const UniValue& 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, default=false) Whether to include addresses that haven't received any payments.\n"
+ "2. includeempty (bool, 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"
@@ -1283,7 +1283,7 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
"\nDEPRECATED. List balances by account.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
- "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
+ "2. includeempty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n"
"3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
"\nResult:\n"
@@ -1346,6 +1346,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong)
WalletTxToJSON(wtx, entry);
+ entry.push_back(Pair("abandoned", wtx.isAbandoned()));
ret.push_back(entry);
}
}
@@ -1438,13 +1439,14 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" \"vout\": n, (numeric) the vout value\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
+ " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable).\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions. Negative confirmations indicate the\n"
" transaction conflicts with the block chain\n"
" \"trusted\": xxx (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
" category of transactions.\n"
- " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
+ " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\n"
" category of transactions.\n"
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
" \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
@@ -1637,7 +1639,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
- " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
+ " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive' category of transactions.\n"
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
" \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
@@ -1721,7 +1723,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
" \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"blockhash\" : \"hash\", (string) The block hash\n"
- " \"blockindex\" : xx, (numeric) The block index\n"
+ " \"blockindex\" : xx, (numeric) The index of the transaction in the block that includes it\n"
" \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
" \"txid\" : \"transactionid\", (string) The transaction id.\n"
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
@@ -1827,7 +1829,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"backupwallet \"destination\"\n"
- "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
+ "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n"
"\nArguments:\n"
"1. \"destination\" (string) The destination directory or file\n"
"\nExamples:\n"
@@ -2098,16 +2100,17 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
+ "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n"
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
+ "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
"Also see the listunspent call\n"
"\nArguments:\n"
"1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
- "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
+ "2. \"transactions\" (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\n"
" [ (json array of json objects)\n"
" {\n"
" \"txid\":\"id\", (string) The transaction id\n"
@@ -2503,8 +2506,10 @@ extern UniValue importaddress(const UniValue& params, bool fHelp);
extern UniValue importpubkey(const UniValue& params, bool fHelp);
extern UniValue dumpwallet(const UniValue& params, bool fHelp);
extern UniValue importwallet(const UniValue& params, bool fHelp);
+extern UniValue importprunedfunds(const UniValue& params, bool fHelp);
+extern UniValue removeprunedfunds(const UniValue& params, bool fHelp);
-const CRPCCommand vWalletRPCCommands[] =
+static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
@@ -2529,6 +2534,7 @@ const CRPCCommand vWalletRPCCommands[] =
{ "wallet", "importprivkey", &importprivkey, true },
{ "wallet", "importwallet", &importwallet, true },
{ "wallet", "importaddress", &importaddress, true },
+ { "wallet", "importprunedfunds", &importprunedfunds, true },
{ "wallet", "importpubkey", &importpubkey, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true },
{ "wallet", "listaccounts", &listaccounts, false },
@@ -2550,16 +2556,11 @@ const CRPCCommand vWalletRPCCommands[] =
{ "wallet", "walletlock", &walletlock, true },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
{ "wallet", "walletpassphrase", &walletpassphrase, true },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, true },
};
-void walletRegisterRPCCommands()
+void RegisterWalletRPCCommands(CRPCTable &tableRPC)
{
- unsigned int vcidx;
- for (vcidx = 0; vcidx < ARRAYLEN(vWalletRPCCommands); vcidx++)
- {
- const CRPCCommand *pcmd;
-
- pcmd = &vWalletRPCCommands[vcidx];
- tableRPC.appendCommand(pcmd->name, pcmd);
- }
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 42e8021afa..a5de7e2de1 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_WALLET_RPCWALLET_H
#define BITCOIN_WALLET_RPCWALLET_H
-void walletRegisterRPCCommands();
+class CRPCTable;
+
+void RegisterWalletRPCCommands(CRPCTable &tableRPC);
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ade460d6ac..1ea8d2ffe7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -33,14 +33,14 @@
using namespace std;
-/**
- * Settings
- */
+/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
+const char * DEFAULT_WALLET_DAT = "wallet.dat";
+
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
* Override with -mintxfee
@@ -399,13 +399,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
if (r == CDBEnv::RECOVER_OK)
{
- warningString += strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
- " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
- " your balance or transactions are incorrect you should"
- " restore from a backup."), GetDataDir());
+ warningString += strprintf(_("Warning: Wallet file corrupt, data salvaged!"
+ " Original %s saved as %s in %s; if"
+ " your balance or transactions are incorrect you should"
+ " restore from a backup."),
+ walletFile, "wallet.{timestamp}.bak", GetDataDir());
}
if (r == CDBEnv::RECOVER_FAIL)
- errorString += _("wallet.dat corrupt, salvage failed");
+ errorString += strprintf(_("%s corrupt, salvage failed"), walletFile);
}
return true;
@@ -846,14 +847,19 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
- CBlockIndex* pindex;
- assert(mapBlockIndex.count(hashBlock));
- pindex = mapBlockIndex[hashBlock];
int conflictconfirms = 0;
- if (chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ if (mapBlockIndex.count(hashBlock)) {
+ CBlockIndex* pindex = mapBlockIndex[hashBlock];
+ if (chainActive.Contains(pindex)) {
+ conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ }
}
- assert(conflictconfirms < 0);
+ // If number of conflict confirms cannot be determined, this means
+ // that the block is still unknown or not yet part of the main chain,
+ // for example when loading the wallet during a reindex. Do nothing in that
+ // case.
+ if (conflictconfirms >= 0)
+ return;
// Do not flush the wallet here for performance reasons
CWalletDB walletdb(strWalletFile, "r+", false);
@@ -1260,9 +1266,11 @@ bool CWalletTx::RelayWalletTransaction()
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
{
- if (GetDepthInMainChain() == 0 && !isAbandoned()) {
+ if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- RelayTransaction((CTransaction)*this);
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(GetHash(), feeRate);
+ RelayTransaction((CTransaction)*this, feeRate);
return true;
}
}
@@ -1572,7 +1580,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -1617,7 +1625,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
@@ -1662,11 +1670,16 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth < 0)
continue;
+ // We should not consider coins which aren't at least in our mempool
+ // It's possible for these to be conflicted via ancestors which we may never be able to detect
+ if (nDepth == 0 && !pcoin->InMempool())
+ continue;
+
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i)))
+ (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
(coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO)));
@@ -1833,10 +1846,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
return true;
}
-bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
+bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
{
- vector<COutput> vCoins;
- AvailableCoins(vCoins, true, coinControl);
+ vector<COutput> vCoins(vAvailableCoins);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
@@ -1924,16 +1936,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC
// Add new txins (keeping original txin scriptSig/order)
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
- bool found = false;
- BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
- {
- if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
- {
- found = true;
- break;
- }
- }
- if (!found)
+ if (!coinControl.IsSelected(txin.prevout))
tx.vin.push_back(txin);
}
@@ -2002,6 +2005,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
LOCK2(cs_main, cs_wallet);
{
+ std::vector<COutput> vAvailableCoins;
+ AvailableCoins(vAvailableCoins, true, coinControl);
+
nFeeRet = 0;
// Start with no fee and loop until there is enough fee
while (true)
@@ -2051,7 +2057,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
- if (!SelectCoins(nValueToSelect, setCoins, nValueIn, coinControl))
+ if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
{
strFailReason = _("Insufficient funds");
return false;
@@ -2347,6 +2353,31 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
return DB_LOAD_OK;
}
+DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut)
+{
+ if (!fFileBacked)
+ return DB_LOAD_OK;
+ DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut);
+ if (nZapSelectTxRet == DB_NEED_REWRITE)
+ {
+ if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ {
+ LOCK(cs_wallet);
+ setKeyPool.clear();
+ // Note: can't top-up keypool here, because wallet is locked.
+ // User will be prompted to unlock wallet the next operation
+ // that requires a new key.
+ }
+ }
+
+ if (nZapSelectTxRet != DB_LOAD_OK)
+ return nZapSelectTxRet;
+
+ MarkDirty();
+
+ return DB_LOAD_OK;
+
+}
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
@@ -2951,6 +2982,203 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
return false;
}
+std::string CWallet::GetWalletHelpString(bool showDebug)
+{
+ std::string strUsage = HelpMessageGroup(_("Wallet options:"));
+ strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
+ strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
+ strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
+ strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
+ strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
+ strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
+ strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
+ strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
+ strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
+ strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
+ strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
+ strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
+ " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
+
+ if (showDebug)
+ {
+ strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
+
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
+ }
+
+ return strUsage;
+}
+
+CWallet* CWallet::InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString)
+{
+ // needed to restore wallet transaction meta data after -zapwallettxes
+ std::vector<CWalletTx> vWtx;
+
+ if (GetBoolArg("-zapwallettxes", false)) {
+ uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
+
+ CWallet *tempWallet = new CWallet(strWalletFile);
+ DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
+ if (nZapWalletRet != DB_LOAD_OK) {
+ errorString = strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile);
+ uiInterface.InitMessage(strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile));
+ return NULL;
+ }
+
+ delete tempWallet;
+ tempWallet = NULL;
+ }
+
+ uiInterface.InitMessage(_("Loading wallet..."));
+
+ int64_t nStart = GetTimeMillis();
+ bool fFirstRun = true;
+ CWallet *walletInstance = new CWallet(strWalletFile);
+ DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
+ if (nLoadWalletRet != DB_LOAD_OK)
+ {
+ if (nLoadWalletRet == DB_CORRUPT)
+ errorString += strprintf(_("Error loading %s: Wallet corrupted"), strWalletFile) + "\n";
+ else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
+ {
+ warningString += strprintf(_("Error reading %s! All keys read correctly, but transaction data"
+ " or address book entries might be missing or incorrect."),
+ strWalletFile);
+ }
+ else if (nLoadWalletRet == DB_TOO_NEW)
+ errorString += strprintf(_("Error loading %s: Wallet requires newer version of %s"),
+ strWalletFile, _(PACKAGE_NAME)) +
+ "\n";
+ else if (nLoadWalletRet == DB_NEED_REWRITE)
+ {
+ errorString += strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)) + "\n";
+ LogPrintf("%s", errorString);
+ }
+ else
+ errorString += strprintf(_("Error loading %s"), strWalletFile) + "\n";
+
+ if (!errorString.empty())
+ return NULL;
+ }
+
+ if (GetBoolArg("-upgradewallet", fFirstRun))
+ {
+ int nMaxVersion = GetArg("-upgradewallet", 0);
+ if (nMaxVersion == 0) // the -upgradewallet without argument case
+ {
+ LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
+ nMaxVersion = CLIENT_VERSION;
+ walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
+ }
+ else
+ LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
+ if (nMaxVersion < walletInstance->GetVersion())
+ {
+ errorString += _("Cannot downgrade wallet") + "\n";
+ return NULL;
+ }
+ walletInstance->SetMaxVersion(nMaxVersion);
+ }
+
+ if (fFirstRun)
+ {
+ // Create new keyUser and set as default key
+ RandAddSeedPerfmon();
+
+ CPubKey newDefaultKey;
+ if (walletInstance->GetKeyFromPool(newDefaultKey)) {
+ walletInstance->SetDefaultKey(newDefaultKey);
+ if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
+ {
+ errorString += _("Cannot write default address") += "\n";
+ return NULL;
+ }
+ }
+
+ walletInstance->SetBestChain(chainActive.GetLocator());
+ }
+
+ LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
+
+ RegisterValidationInterface(walletInstance);
+
+ CBlockIndex *pindexRescan = chainActive.Tip();
+ if (GetBoolArg("-rescan", false))
+ pindexRescan = chainActive.Genesis();
+ else
+ {
+ CWalletDB walletdb(strWalletFile);
+ CBlockLocator locator;
+ if (walletdb.ReadBestBlock(locator))
+ pindexRescan = FindForkInGlobalIndex(chainActive, locator);
+ else
+ pindexRescan = chainActive.Genesis();
+ }
+ if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
+ {
+ //We can't rescan beyond non-pruned blocks, stop and throw an error
+ //this might happen if a user uses a old wallet within a pruned node
+ // or if he ran -disablewallet for a longer time, then decided to re-enable
+ if (fPruneMode)
+ {
+ CBlockIndex *block = chainActive.Tip();
+ while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
+ block = block->pprev;
+
+ if (pindexRescan != block)
+ {
+ errorString = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
+ return NULL;
+ }
+ }
+
+ uiInterface.InitMessage(_("Rescanning..."));
+ LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+ nStart = GetTimeMillis();
+ walletInstance->ScanForWalletTransactions(pindexRescan, true);
+ LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
+ walletInstance->SetBestChain(chainActive.GetLocator());
+ nWalletDBUpdated++;
+
+ // Restore wallet transaction metadata after -zapwallettxes=1
+ if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
+ {
+ CWalletDB walletdb(strWalletFile);
+
+ BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
+ {
+ uint256 hash = wtxOld.GetHash();
+ std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
+ if (mi != walletInstance->mapWallet.end())
+ {
+ const CWalletTx* copyFrom = &wtxOld;
+ CWalletTx* copyTo = &mi->second;
+ copyTo->mapValue = copyFrom->mapValue;
+ copyTo->vOrderForm = copyFrom->vOrderForm;
+ copyTo->nTimeReceived = copyFrom->nTimeReceived;
+ copyTo->nTimeSmart = copyFrom->nTimeSmart;
+ copyTo->fFromMe = copyFrom->fFromMe;
+ copyTo->strFromAccount = copyFrom->strFromAccount;
+ copyTo->nOrderPos = copyFrom->nOrderPos;
+ copyTo->WriteToDisk(&walletdb);
+ }
+ }
+ }
+ }
+ walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
+
+ return walletInstance;
+}
+
CKeyPool::CKeyPool()
{
nTime = GetTime();
@@ -3028,5 +3256,5 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 990b27c7ce..5db36f52d1 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -55,6 +55,8 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
+extern const char * DEFAULT_WALLET_DAT;
+
class CBlockIndex;
class CCoinControl;
class COutput;
@@ -542,7 +544,7 @@ private:
* all coins from coinControl are selected; Never select unconfirmed coins
* if they are not ours
*/
- bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
+ bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
CWalletDB *pwalletdbEncryption;
@@ -790,6 +792,7 @@ public:
DBErrors LoadWallet(bool& fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
@@ -869,6 +872,12 @@ public:
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
+
+ /* Returns the wallets help message */
+ static std::string GetWalletHelpString(bool showDebug);
+
+ /* initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
+ static CWallet* InitLoadWallet(bool fDisableWallet, const std::string& strWalletFile, std::string& warningString, std::string& errorString);
};
/** A key allocated from the key pool. */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 67511976df..f2b5408e92 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -785,6 +785,45 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vec
return result;
}
+DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut)
+{
+ // build list of wallet TXs and hashes
+ vector<uint256> vTxHash;
+ vector<CWalletTx> vWtx;
+ DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
+ if (err != DB_LOAD_OK) {
+ return err;
+ }
+
+ std::sort(vTxHash.begin(), vTxHash.end());
+ std::sort(vTxHashIn.begin(), vTxHashIn.end());
+
+ // erase each matching wallet TX
+ bool delerror = false;
+ vector<uint256>::iterator it = vTxHashIn.begin();
+ BOOST_FOREACH (uint256 hash, vTxHash) {
+ while (it < vTxHashIn.end() && (*it) < hash) {
+ it++;
+ }
+ if (it == vTxHashIn.end()) {
+ break;
+ }
+ else if ((*it) == hash) {
+ pwallet->mapWallet.erase(hash);
+ if(!EraseTx(hash)) {
+ LogPrint("db", "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
+ delerror = true;
+ }
+ vTxHashOut.push_back(hash);
+ }
+ }
+
+ if (delerror) {
+ return DB_CORRUPT;
+ }
+ return DB_LOAD_OK;
+}
+
DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
@@ -847,16 +886,16 @@ void ThreadFlushWalletDB(const string& strFile)
map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
if (mi != bitdb.mapFileUseCount.end())
{
- LogPrint("db", "Flushing wallet.dat\n");
+ LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated;
int64_t nStart = GetTimeMillis();
- // Flush wallet.dat so it's self contained
+ // Flush wallet file so it's self contained
bitdb.CloseDb(strFile);
bitdb.CheckpointLSN(strFile);
bitdb.mapFileUseCount.erase(mi++);
- LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart);
+ LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
}
}
}
@@ -879,7 +918,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
bitdb.CheckpointLSN(wallet.strWalletFile);
bitdb.mapFileUseCount.erase(wallet.strWalletFile);
- // Copy wallet.dat
+ // Copy wallet file
boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
boost::filesystem::path pathDest(strDest);
if (boost::filesystem::is_directory(pathDest))
@@ -891,10 +930,10 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
#else
boost::filesystem::copy_file(pathSrc, pathDest);
#endif
- LogPrintf("copied wallet.dat to %s\n", pathDest.string());
+ LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string());
return true;
} catch (const boost::filesystem::filesystem_error& e) {
- LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what());
+ LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what());
return false;
}
}
@@ -905,15 +944,15 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
}
//
-// Try to (very carefully!) recover wallet.dat if there is a problem.
+// Try to (very carefully!) recover wallet file if there is a problem.
//
bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys)
{
// Recovery procedure:
- // move wallet.dat to wallet.timestamp.bak
+ // move wallet file to wallet.timestamp.bak
// Call Salvage with fAggressive=true to
// get as much data as possible.
- // Rewrite salvaged data to wallet.dat
+ // Rewrite salvaged data to fresh wallet file
// Set -rescan so any missing transactions will be
// found.
int64_t now = GetTime();
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 8da33dead2..fe6c366343 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -73,7 +73,7 @@ public:
}
};
-/** Access to the wallet database (wallet.dat) */
+/** Access to the wallet database */
class CWalletDB : public CDB
{
public:
@@ -130,6 +130,7 @@ public:
DBErrors LoadWallet(CWallet* pwallet);
DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
+ DBErrors ZapSelectTx(CWallet* pwallet, std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, const std::string& filename);
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index c8adcf8462..8705532429 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -100,7 +100,6 @@ bool CZMQNotificationInterface::Initialize()
if (i!=notifiers.end())
{
- Shutdown();
return false;
}
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index ddc8fe93e9..f5839620ff 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -69,6 +69,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
if (rc!=0)
{
zmqError("Failed to bind address");
+ zmq_close(psocket);
return false;
}