aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.qt.include3
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/alert.cpp37
-rw-r--r--src/alert.h3
-rw-r--r--src/bitcoin-cli.cpp6
-rw-r--r--src/bitcoin-tx.cpp20
-rw-r--r--src/chain.cpp5
-rw-r--r--src/chain.h36
-rw-r--r--src/chainparams.cpp84
-rw-r--r--src/chainparams.h6
-rw-r--r--src/chainparamsbase.cpp25
-rw-r--r--src/chainparamsbase.h9
-rw-r--r--src/checkpoints.cpp81
-rw-r--r--src/checkpoints.h12
-rw-r--r--src/coins.cpp117
-rw-r--r--src/coins.h81
-rw-r--r--src/core.cpp23
-rw-r--r--src/core.h13
-rw-r--r--src/init.cpp139
-rw-r--r--src/key.cpp33
-rw-r--r--src/keystore.cpp7
-rw-r--r--src/keystore.h2
-rw-r--r--src/main.cpp888
-rw-r--r--src/main.h54
-rw-r--r--src/miner.cpp10
-rw-r--r--src/net.cpp76
-rw-r--r--src/net.h4
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h3
-rw-r--r--src/noui.cpp6
-rw-r--r--src/pow.cpp33
-rw-r--r--src/pow.h2
-rw-r--r--src/qt/bitcoin.cpp25
-rw-r--r--src/qt/bitcoingui.cpp62
-rw-r--r--src/qt/bitcoingui.h7
-rw-r--r--src/qt/bitcoinstrings.cpp104
-rw-r--r--src/qt/forms/rpcconsole.ui23
-rw-r--r--src/qt/intro.cpp4
-rw-r--r--src/qt/locale/bitcoin_en.ts673
-rw-r--r--src/qt/networkstyle.cpp47
-rw-r--r--src/qt/networkstyle.h33
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/rpcconsole.cpp1
-rw-r--r--src/qt/splashscreen.cpp26
-rw-r--r--src/qt/splashscreen.h4
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/qt/walletmodel.cpp3
-rw-r--r--src/rpcblockchain.cpp4
-rw-r--r--src/rpcdump.cpp5
-rw-r--r--src/rpcmining.cpp2
-rw-r--r--src/rpcmisc.cpp2
-rw-r--r--src/rpcnet.cpp16
-rw-r--r--src/rpcrawtransaction.cpp27
-rw-r--r--src/rpcserver.cpp2
-rw-r--r--src/rpcwallet.cpp2
-rw-r--r--src/script/interpreter.cpp76
-rw-r--r--src/script/interpreter.h27
-rw-r--r--src/script/sigcache.cpp4
-rw-r--r--src/script/sigcache.h6
-rw-r--r--src/script/standard.cpp15
-rw-r--r--src/serialize.h134
-rw-r--r--src/test/DoS_tests.cpp45
-rw-r--r--src/test/bloom_tests.cpp1
-rw-r--r--src/test/canonical_tests.cpp113
-rw-r--r--src/test/checkblock_tests.cpp2
-rw-r--r--src/test/coins_tests.cpp178
-rw-r--r--src/test/data/script_invalid.json133
-rw-r--r--src/test/data/script_valid.json133
-rw-r--r--src/test/key_tests.cpp2
-rw-r--r--src/test/script_P2SH_tests.cpp5
-rw-r--r--src/test/script_tests.cpp111
-rw-r--r--src/test/test_bitcoin.cpp4
-rw-r--r--src/test/transaction_tests.cpp11
-rw-r--r--src/test/util_tests.cpp12
-rw-r--r--src/txdb.cpp23
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/txmempool.h15
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/util.cpp12
-rw-r--r--src/utilstrencodings.cpp8
-rw-r--r--src/version.cpp10
-rw-r--r--src/version.h5
-rw-r--r--src/wallet.cpp47
-rw-r--r--src/wallet.h44
-rw-r--r--src/walletdb.cpp21
-rw-r--r--src/walletdb.h1
88 files changed, 2332 insertions, 1773 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 1ea039adb3..f8f4439159 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -178,6 +178,7 @@ BITCOIN_QT_H = \
qt/macdockiconhandler.h \
qt/macnotificationhandler.h \
qt/monitoreddatamapper.h \
+ qt/networkstyle.h \
qt/notificator.h \
qt/openuridialog.h \
qt/optionsdialog.h \
@@ -269,6 +270,7 @@ BITCOIN_QT_CPP = \
qt/guiutil.cpp \
qt/intro.cpp \
qt/monitoreddatamapper.cpp \
+ qt/networkstyle.cpp \
qt/notificator.cpp \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
@@ -366,6 +368,7 @@ if USE_LIBSECP256K1
qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
endif
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS)
+qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX
#locale/foo.ts -> locale/foo.qm
QT_QM=$(QT_TS:.ts=.qm)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 2cba5b7e1e..23375bef82 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -13,7 +13,7 @@ TEST_QT_H = \
qt/test/paymentservertests.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
- $(QT_INCLUDES) $(QT_TEST_INCLUDES)
+ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
qt/test/test_main.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index ab449f3e71..b20e226c3d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -40,10 +40,10 @@ BITCOIN_TESTS =\
test/base58_tests.cpp \
test/base64_tests.cpp \
test/bloom_tests.cpp \
- test/canonical_tests.cpp \
test/checkblock_tests.cpp \
test/Checkpoints_tests.cpp \
test/compress_tests.cpp \
+ test/coins_tests.cpp \
test/crypto_tests.cpp \
test/DoS_tests.cpp \
test/getarg_tests.cpp \
diff --git a/src/alert.cpp b/src/alert.cpp
index 3271ecfbfd..d495849206 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -233,25 +233,30 @@ bool CAlert::ProcessAlert(bool fThread)
if(AppliesToMe())
{
uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
- std::string strCmd = GetArg("-alertnotify", "");
- if (!strCmd.empty())
- {
- // 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(strStatusBar);
- safeStatus = singleQuote+safeStatus+singleQuote;
- boost::replace_all(strCmd, "%s", safeStatus);
-
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
- }
+ 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
index 5ecf94cea8..ba3235858d 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -101,7 +101,8 @@ public:
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
bool CheckSignature() const;
- bool ProcessAlert(bool fThread = true);
+ bool ProcessAlert(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.
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index badb376cb3..aa5e285b10 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -25,13 +25,13 @@ std::string HelpMessageCli()
string strUsage;
strUsage += _("Options:") + "\n";
strUsage += " -? " + _("This help message") + "\n";
- strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
+ strUsage += " -conf=<file> " + strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf") + "\n";
strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
strUsage += " -testnet " + _("Use the test network") + "\n";
strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
"solved instantly. This is intended for regression testing tools and app development.") + "\n";
- strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
- strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
+ strUsage += " -rpcconnect=<ip> " + strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1") + "\n";
+ strUsage += " -rpcport=<port> " + strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n";
strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index a198eb586e..da37e60c7f 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -340,7 +340,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true;
CCoinsView viewDummy;
- CCoinsViewCache view(viewDummy);
+ CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
@@ -384,21 +384,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
vector<unsigned char> pkData(ParseHexUV(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
- CCoins coins;
- if (view.GetCoins(txid, coins)) {
- if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
+ {
+ CCoinsModifier coins = view.ModifyCoins(txid);
+ if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
- err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
+ err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw runtime_error(err);
}
- // what todo if txid is known, but the actual output isn't?
+ if ((unsigned int)nOut >= coins->vout.size())
+ coins->vout.resize(nOut+1);
+ coins->vout[nOut].scriptPubKey = scriptPubKey;
+ coins->vout[nOut].nValue = 0; // we don't know the actual output value
}
- if ((unsigned int)nOut >= coins.vout.size())
- coins.vout.resize(nOut+1);
- coins.vout[nOut].scriptPubKey = scriptPubKey;
- coins.vout[nOut].nValue = 0; // we don't know the actual output value
- view.SetCoins(txid, coins);
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
diff --git a/src/chain.cpp b/src/chain.cpp
index 05427a4569..56ed22ce71 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -9,17 +9,16 @@ using namespace std;
// CChain implementation
-CBlockIndex *CChain::SetTip(CBlockIndex *pindex) {
+void CChain::SetTip(CBlockIndex *pindex) {
if (pindex == NULL) {
vChain.clear();
- return NULL;
+ return;
}
vChain.resize(pindex->nHeight + 1);
while (pindex && vChain[pindex->nHeight] != pindex) {
vChain[pindex->nHeight] = pindex;
pindex = pindex->pprev;
}
- return pindex;
}
CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
diff --git a/src/chain.h b/src/chain.h
index 0aafb40b98..0533eeb730 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -49,12 +49,29 @@ struct CDiskBlockPos
};
enum BlockStatus {
+ // Unused.
BLOCK_VALID_UNKNOWN = 0,
- BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
- BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint
- BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root
- BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30
- BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok
+
+ // Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
+ BLOCK_VALID_HEADER = 1,
+
+ // All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
+ // are also at least TREE.
+ BLOCK_VALID_TREE = 2,
+
+ // Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,
+ // sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all
+ // parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.
+ BLOCK_VALID_TRANSACTIONS = 3,
+
+ // Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30.
+ // Implies all parents are also at least CHAIN.
+ BLOCK_VALID_CHAIN = 4,
+
+ // Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
+ BLOCK_VALID_SCRIPTS = 5,
+
+ // All validity bits.
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
@@ -103,7 +120,8 @@ public:
// Note: in a potential headers-first mode, this number cannot be relied upon
unsigned int nTx;
- // (memory only) Number of transactions in the chain up to and including this block
+ // (memory only) Number of transactions in the chain up to and including this block.
+ // This value will be non-zero only if and only if transactions for this block and all its parents are available.
unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030
// Verification status of this block. See enum BlockStatus
@@ -146,7 +164,7 @@ public:
SetNull();
}
- CBlockIndex(CBlockHeader& block)
+ CBlockIndex(const CBlockHeader& block)
{
SetNull();
@@ -377,8 +395,8 @@ public:
return vChain.size() - 1;
}
- /** Set/initialize a chain with a given tip. Returns the forking point. */
- CBlockIndex *SetTip(CBlockIndex *pindex);
+ /** Set/initialize a chain with a given tip. */
+ void SetTip(CBlockIndex *pindex);
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 31c67715c8..dfb4c59d87 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -44,6 +44,57 @@ static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data
}
}
+ // What makes a good checkpoint block?
+ // + Is surrounded by blocks with reasonable timestamps
+ // (no blocks before with a timestamp after, none after with
+ // timestamp before)
+ // + Contains no strange transactions
+static Checkpoints::MapCheckpoints mapCheckpoints =
+ boost::assign::map_list_of
+ ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
+ ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
+ ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
+ (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
+ (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
+ (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
+ (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
+ (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
+ (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
+ (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
+ (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
+ (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
+ (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"))
+ ;
+static const Checkpoints::CCheckpointData data = {
+ &mapCheckpoints,
+ 1397080064, // * UNIX timestamp of last checkpoint block
+ 36544669, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 60000.0 // * estimated number of transactions per day after checkpoint
+ };
+
+static Checkpoints::MapCheckpoints mapCheckpointsTestnet =
+ boost::assign::map_list_of
+ ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
+ ;
+static const Checkpoints::CCheckpointData dataTestnet = {
+ &mapCheckpointsTestnet,
+ 1337966069,
+ 1488,
+ 300
+ };
+
+static Checkpoints::MapCheckpoints mapCheckpointsRegtest =
+ boost::assign::map_list_of
+ ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
+ ;
+static const Checkpoints::CCheckpointData dataRegtest = {
+ &mapCheckpointsRegtest,
+ 0,
+ 0,
+ 0
+ };
+
class CMainParams : public CChainParams {
public:
CMainParams() {
@@ -116,6 +167,12 @@ public:
fRequireStandard = true;
fMineBlocksOnDemand = false;
fSkipProofOfWorkCheck = false;
+ fTestnetToBeDeprecatedFieldRPC = false;
+ }
+
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return data;
}
};
static CMainParams mainParams;
@@ -172,6 +229,11 @@ public:
fAllowMinDifficultyBlocks = true;
fRequireStandard = false;
fMineBlocksOnDemand = false;
+ fTestnetToBeDeprecatedFieldRPC = true;
+ }
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return dataTestnet;
}
};
static CTestNetParams testNetParams;
@@ -211,6 +273,11 @@ public:
fAllowMinDifficultyBlocks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
+ fTestnetToBeDeprecatedFieldRPC = false;
+ }
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ return dataRegtest;
}
};
static CRegTestParams regTestParams;
@@ -233,7 +300,13 @@ public:
fAllowMinDifficultyBlocks = false;
fMineBlocksOnDemand = true;
}
-public:
+
+ const Checkpoints::CCheckpointData& Checkpoints() const
+ {
+ // UnitTest share the same checkpoints as MAIN
+ return data;
+ }
+
// Published setters to allow changing values in unit test cases
virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; }
virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; }
@@ -281,10 +354,13 @@ void SelectParams(CBaseChainParams::Network network) {
pCurrentParams = &Params(network);
}
-bool SelectParamsFromCommandLine() {
- if (!SelectBaseParamsFromCommandLine())
+bool SelectParamsFromCommandLine()
+{
+ CBaseChainParams::Network network = NetworkIdFromCommandLine();
+ if (network == CBaseChainParams::MAX_NETWORK_TYPES)
return false;
- SelectParams(BaseParams().NetworkID());
+ SelectBaseParams(network);
+ SelectParams(network);
return true;
}
diff --git a/src/chainparams.h b/src/chainparams.h
index 50441a89f3..f157419bb2 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -8,6 +8,7 @@
#include "core.h"
#include "chainparamsbase.h"
+#include "checkpoints.h"
#include "protocol.h"
#include "uint256.h"
@@ -71,12 +72,14 @@ public:
/* Make miner stop after a block is found. In RPC, don't return
* until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
- CBaseChainParams::Network NetworkID() const { return networkID; }
+ /* In the future use NetworkIDString() for RPC fields */
+ bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
/* Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<CAddress>& FixedSeeds() const { return vFixedSeeds; }
+ virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0;
protected:
CChainParams() {}
@@ -106,6 +109,7 @@ protected:
bool fRequireStandard;
bool fMineBlocksOnDemand;
bool fSkipProofOfWorkCheck;
+ bool fTestnetToBeDeprecatedFieldRPC;
};
/** Modifiable parameters interface is used by test cases to adapt the parameters in order
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index e9d63197bd..5d9ec7927b 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -100,22 +100,27 @@ void SelectBaseParams(CBaseChainParams::Network network)
}
}
-bool SelectBaseParamsFromCommandLine()
+CBaseChainParams::Network NetworkIdFromCommandLine()
{
bool fRegTest = GetBoolArg("-regtest", false);
bool fTestNet = GetBoolArg("-testnet", false);
- if (fTestNet && fRegTest) {
+ if (fTestNet && fRegTest)
+ return CBaseChainParams::MAX_NETWORK_TYPES;
+ if (fRegTest)
+ return CBaseChainParams::REGTEST;
+ if (fTestNet)
+ return CBaseChainParams::TESTNET;
+ return CBaseChainParams::MAIN;
+}
+
+bool SelectBaseParamsFromCommandLine()
+{
+ CBaseChainParams::Network network = NetworkIdFromCommandLine();
+ if (network == CBaseChainParams::MAX_NETWORK_TYPES)
return false;
- }
- if (fRegTest) {
- SelectBaseParams(CBaseChainParams::REGTEST);
- } else if (fTestNet) {
- SelectBaseParams(CBaseChainParams::TESTNET);
- } else {
- SelectBaseParams(CBaseChainParams::MAIN);
- }
+ SelectBaseParams(network);
return true;
}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index cc154cf501..911d1181ac 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -26,7 +26,6 @@ public:
const std::string& DataDir() const { return strDataDir; }
int RPCPort() const { return nRPCPort; }
- Network NetworkID() const { return networkID; }
protected:
CBaseChainParams() {}
@@ -46,7 +45,13 @@ const CBaseChainParams& BaseParams();
void SelectBaseParams(CBaseChainParams::Network network);
/**
- * Looks for -regtest or -testnet and then calls SelectParams as appropriate.
+ * Looks for -regtest or -testnet and returns the appropriate Network ID.
+ * Returns MAX_NETWORK_TYPES if an invalid combination is given.
+ */
+CBaseChainParams::Network NetworkIdFromCommandLine();
+
+/**
+ * Calls NetworkIdFromCommandLine() and then calls SelectParams as appropriate.
* Returns false if an invalid combination is given.
*/
bool SelectBaseParamsFromCommandLine();
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 9a6bc05e63..fbde47339d 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -4,18 +4,16 @@
#include "checkpoints.h"
+#include "chainparams.h"
#include "main.h"
#include "uint256.h"
#include <stdint.h>
-#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
namespace Checkpoints {
- typedef std::map<int, uint256> MapCheckpoints;
-
// How many times we expect transactions after the last checkpoint to
// be slower. This number is a compromise, as it can't be accurate for
// every system. When reindexing from a fast disk with a slow CPU, it
@@ -23,83 +21,14 @@ namespace Checkpoints {
// fast multicore CPU, it won't be much higher than 1.
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
- struct CCheckpointData {
- const MapCheckpoints *mapCheckpoints;
- int64_t nTimeLastCheckpoint;
- int64_t nTransactionsLastCheckpoint;
- double fTransactionsPerDay;
- };
-
bool fEnabled = true;
- // What makes a good checkpoint block?
- // + Is surrounded by blocks with reasonable timestamps
- // (no blocks before with a timestamp after, none after with
- // timestamp before)
- // + Contains no strange transactions
- static MapCheckpoints mapCheckpoints =
- boost::assign::map_list_of
- ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
- ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
- ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
- (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
- (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
- (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
- (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
- (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
- (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
- (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
- (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
- (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
- (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"))
- ;
- static const CCheckpointData data = {
- &mapCheckpoints,
- 1397080064, // * UNIX timestamp of last checkpoint block
- 36544669, // * total number of transactions between genesis and last checkpoint
- // (the tx=... number in the SetBestChain debug.log lines)
- 60000.0 // * estimated number of transactions per day after checkpoint
- };
-
- static MapCheckpoints mapCheckpointsTestnet =
- boost::assign::map_list_of
- ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
- ;
- static const CCheckpointData dataTestnet = {
- &mapCheckpointsTestnet,
- 1337966069,
- 1488,
- 300
- };
-
- static MapCheckpoints mapCheckpointsRegtest =
- boost::assign::map_list_of
- ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
- ;
- static const CCheckpointData dataRegtest = {
- &mapCheckpointsRegtest,
- 0,
- 0,
- 0
- };
-
- const CCheckpointData &Checkpoints() {
- if (Params().NetworkID() == CBaseChainParams::TESTNET)
- return dataTestnet;
- else if (Params().NetworkID() == CBaseChainParams::MAIN)
- return data;
- else if (Params().NetworkID() == CBaseChainParams::UNITTEST) // UnitTest share the same checkpoints as MAIN
- return data;
- else
- return dataRegtest;
- }
-
bool CheckBlock(int nHeight, const uint256& hash)
{
if (!fEnabled)
return true;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
@@ -119,7 +48,7 @@ namespace Checkpoints {
// Work is defined as: 1.0 per transaction before the last checkpoint, and
// fSigcheckVerificationFactor per transaction after.
- const CCheckpointData &data = Checkpoints();
+ const CCheckpointData &data = Params().Checkpoints();
if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
double nCheapBefore = pindex->nChainTx;
@@ -143,7 +72,7 @@ namespace Checkpoints {
if (!fEnabled)
return 0;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
return checkpoints.rbegin()->first;
}
@@ -153,7 +82,7 @@ namespace Checkpoints {
if (!fEnabled)
return NULL;
- const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
+ const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
diff --git a/src/checkpoints.h b/src/checkpoints.h
index fca046559a..b5b620fa6b 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -5,16 +5,26 @@
#ifndef BITCOIN_CHECKPOINT_H
#define BITCOIN_CHECKPOINT_H
+#include "uint256.h"
+
#include <map>
class CBlockIndex;
-class uint256;
/** Block-chain checkpoints are compiled-in sanity checks.
* They are updated every release or three.
*/
namespace Checkpoints
{
+typedef std::map<int, uint256> MapCheckpoints;
+
+struct CCheckpointData {
+ const MapCheckpoints *mapCheckpoints;
+ int64_t nTimeLastCheckpoint;
+ int64_t nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+};
+
// Returns true if block passes checkpoint checks
bool CheckBlock(int nHeight, const uint256& hash);
diff --git a/src/coins.cpp b/src/coins.cpp
index 9b8d63d4e4..e4f3e67aeb 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -53,61 +53,72 @@ bool CCoins::Spend(int nPos) {
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
-bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(0); }
-bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
-CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
+CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
-bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
-bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
-CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { }
+CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), hashBlock(0) { }
-bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
- if (cacheCoins.count(txid)) {
- coins = cacheCoins[txid];
- return true;
- }
- if (base->GetCoins(txid, coins)) {
- cacheCoins[txid] = coins;
- return true;
- }
- return false;
+CCoinsViewCache::~CCoinsViewCache()
+{
+ assert(!hasModifier);
}
-CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
CCoinsMap::iterator it = cacheCoins.find(txid);
if (it != cacheCoins.end())
return it;
CCoins tmp;
- if (!base->GetCoins(txid,tmp))
+ if (!base->GetCoins(txid, tmp))
return cacheCoins.end();
- CCoinsMap::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
- tmp.swap(ret->second);
+ CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
+ tmp.swap(ret->second.coins);
+ if (ret->second.coins.IsPruned()) {
+ // The parent only has an empty entry for this txid; we can consider our
+ // version as fresh.
+ ret->second.flags = CCoinsCacheEntry::FRESH;
+ }
return ret;
}
-CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
- /* Avoid redundant implementation with the const-cast. */
- return const_cast<CCoinsViewCache*>(this)->FetchCoins(txid);
+bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
+ CCoinsMap::const_iterator it = FetchCoins(txid);
+ if (it != cacheCoins.end()) {
+ coins = it->second.coins;
+ return true;
+ }
+ return false;
}
-CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
- CCoinsMap::iterator it = FetchCoins(txid);
- assert(it != cacheCoins.end());
- return it->second;
+CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
+ assert(!hasModifier);
+ hasModifier = true;
+ std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
+ if (ret.second) {
+ if (!base->GetCoins(txid, ret.first->second.coins)) {
+ // The parent view does not have this entry; mark it as fresh.
+ ret.first->second.coins.Clear();
+ ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ } else if (ret.first->second.coins.IsPruned()) {
+ // The parent view only has a pruned entry for this; mark it as fresh.
+ ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ }
+ }
+ // Assume that whenever ModifyCoins is called, the entry will be modified.
+ ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
+ return CCoinsModifier(*this, ret.first);
}
const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
@@ -115,22 +126,17 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
if (it == cacheCoins.end()) {
return NULL;
} else {
- return &it->second;
+ return &it->second.coins;
}
}
-bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
- cacheCoins[txid] = coins;
- return true;
-}
-
bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
CCoinsMap::const_iterator it = FetchCoins(txid);
// We're using vtx.empty() instead of IsPruned here for performance reasons,
// as we only care about the case where an transaction was replaced entirely
// in a reorganization (which wipes vout entirely, as opposed to spending
// which just cleans individual outputs).
- return (it != cacheCoins.end() && !it->second.vout.empty());
+ return (it != cacheCoins.end() && !it->second.coins.vout.empty());
}
uint256 CCoinsViewCache::GetBestBlock() const {
@@ -139,14 +145,39 @@ uint256 CCoinsViewCache::GetBestBlock() const {
return hashBlock;
}
-bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
+void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn;
- return true;
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
+ assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- cacheCoins[it->first].swap(it->second);
+ if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
+ CCoinsMap::iterator itUs = cacheCoins.find(it->first);
+ if (itUs == cacheCoins.end()) {
+ if (!it->second.coins.IsPruned()) {
+ // The parent cache does not have an entry, while the child
+ // cache does have (a non-pruned) one. Move the data up, and
+ // mark it as fresh (if the grandparent did have it, we
+ // would have pulled it in at first GetCoins).
+ assert(it->second.flags & CCoinsCacheEntry::FRESH);
+ CCoinsCacheEntry& entry = cacheCoins[it->first];
+ entry.coins.swap(it->second.coins);
+ entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
+ }
+ } else {
+ if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
+ // The grandparent does not have an entry, and the child is
+ // modified and being pruned. This means we can just delete
+ // it from the parent.
+ cacheCoins.erase(itUs);
+ } else {
+ // A normal modification.
+ itUs->second.coins.swap(it->second.coins);
+ itUs->second.flags |= CCoinsCacheEntry::DIRTY;
+ }
+ }
+ }
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
}
@@ -213,3 +244,15 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
}
return tx.ComputePriority(dResult);
}
+
+CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {}
+
+CCoinsModifier::~CCoinsModifier()
+{
+ assert(cache.hasModifier);
+ cache.hasModifier = false;
+ it->second.coins.Cleanup();
+ if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
+ cache.cacheCoins.erase(it);
+ }
+}
diff --git a/src/coins.h b/src/coins.h
index 2583475323..b8f1e5bcc5 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -83,11 +83,26 @@ public:
// as new tx version will probably only be introduced at certain heights
int nVersion;
- // construct a CCoins from a CTransaction, at a given height
- CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) {
+ void FromTx(const CTransaction &tx, int nHeightIn) {
+ fCoinBase = tx.IsCoinBase();
+ vout = tx.vout;
+ nHeight = nHeightIn;
+ nVersion = tx.nVersion;
ClearUnspendable();
}
+ // construct a CCoins from a CTransaction, at a given height
+ CCoins(const CTransaction &tx, int nHeightIn) {
+ FromTx(tx, nHeightIn);
+ }
+
+ void Clear() {
+ fCoinBase = false;
+ std::vector<CTxOut>().swap(vout);
+ nHeight = 0;
+ nVersion = 0;
+ }
+
// empty constructor
CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
@@ -256,7 +271,20 @@ public:
}
};
-typedef boost::unordered_map<uint256, CCoins, CCoinsKeyHasher> CCoinsMap;
+struct CCoinsCacheEntry
+{
+ CCoins coins; // The actual cached data.
+ unsigned char flags;
+
+ enum Flags {
+ DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
+ FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
+ };
+
+ CCoinsCacheEntry() : coins(), flags(0) {}
+};
+
+typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
struct CCoinsStats
{
@@ -279,9 +307,6 @@ public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
- // Modify the CCoins for a given txid
- virtual bool SetCoins(const uint256 &txid, const CCoins &coins);
-
// Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions
virtual bool HaveCoins(const uint256 &txid) const;
@@ -289,10 +314,7 @@ public:
// Retrieve the block hash whose state this CCoinsView currently represents
virtual uint256 GetBestBlock() const;
- // Modify the currently active block hash
- virtual bool SetBestBlock(const uint256 &hashBlock);
-
- // Do a bulk modification (multiple SetCoins + one SetBestBlock).
+ // Do a bulk modification (multiple CCoins changes + BestBlock change).
// The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
@@ -311,22 +333,41 @@ protected:
CCoinsView *base;
public:
- CCoinsViewBacked(CCoinsView &viewIn);
+ CCoinsViewBacked(CCoinsView *viewIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats) const;
};
+class CCoinsViewCache;
+
+/** A reference to a mutable cache entry. Encapsulating it allows us to run
+ * cleanup code after the modification is finished, and keeping track of
+ * concurrent modifications. */
+class CCoinsModifier
+{
+private:
+ CCoinsViewCache& cache;
+ CCoinsMap::iterator it;
+ CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_);
+
+public:
+ CCoins* operator->() { return &it->second.coins; }
+ CCoins& operator*() { return it->second.coins; }
+ ~CCoinsModifier();
+ friend class CCoinsViewCache;
+};
+
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
class CCoinsViewCache : public CCoinsViewBacked
{
protected:
+ /* Whether this cache has an active modifier. */
+ bool hasModifier;
/* Make mutable so that we can "fill the cache" even from Get-methods
declared as "const". */
@@ -334,14 +375,14 @@ protected:
mutable CCoinsMap cacheCoins;
public:
- CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
+ CCoinsViewCache(CCoinsView *baseIn);
+ ~CCoinsViewCache();
// Standard CCoinsView methods
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
+ void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
// Return a pointer to CCoins in the cache, or NULL if not found. This is
@@ -349,8 +390,10 @@ public:
// allowed while accessing the returned pointer.
const CCoins* AccessCoins(const uint256 &txid) const;
- // Return a modifiable reference to a CCoins. Check HaveCoins first.
- CCoins &GetCoins(const uint256 &txid);
+ // Return a modifiable reference to a CCoins. If no entry with the given
+ // txid exists, a new one is created. Simultaneous modifications are not
+ // allowed.
+ CCoinsModifier ModifyCoins(const uint256 &txid);
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
@@ -377,6 +420,8 @@ public:
const CTxOut &GetOutputFor(const CTxIn& input) const;
+ friend class CCoinsModifier;
+
private:
CCoinsMap::iterator FetchCoins(const uint256 &txid);
CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const;
diff --git a/src/core.cpp b/src/core.cpp
index 380b1c38e0..6a7a9ff378 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -7,8 +7,6 @@
#include "tinyformat.h"
-#include <boost/foreach.hpp>
-
std::string COutPoint::ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
@@ -113,10 +111,10 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
CAmount CTransaction::GetValueOut() const
{
CAmount nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
+ for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)
{
- nValueOut += txout.nValue;
- if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
+ nValueOut += it->nValue;
+ if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
}
return nValueOut;
@@ -139,10 +137,9 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
// risk encouraging people to create junk outputs to redeem later.
if (nTxSize == 0)
nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
-
- BOOST_FOREACH(const CTxIn& txin, vin)
+ for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
{
- unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size());
+ unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
if (nTxSize > offset)
nTxSize -= offset;
}
@@ -263,8 +260,8 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
*/
vMerkleTree.clear();
vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
- BOOST_FOREACH(const CTransaction& tx, vtx)
- vMerkleTree.push_back(tx.GetHash());
+ for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
+ vMerkleTree.push_back(it->GetHash());
int j = 0;
bool mutated = false;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
@@ -307,12 +304,12 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer
{
if (nIndex == -1)
return 0;
- BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
+ for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
{
if (nIndex & 1)
- hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
+ hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
else
- hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
+ hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
nIndex >>= 1;
}
return hash;
diff --git a/src/core.h b/src/core.h
index a348293578..a024dad740 100644
--- a/src/core.h
+++ b/src/core.h
@@ -61,19 +61,6 @@ public:
std::string ToString() const;
};
-/** An inpoint - a combination of a transaction and an index n into its vin */
-class CInPoint
-{
-public:
- const CTransaction* ptx;
- uint32_t n;
-
- CInPoint() { SetNull(); }
- CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; }
- void SetNull() { ptx = NULL; n = (uint32_t) -1; }
- bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); }
-};
-
/** An input of a transaction. It contains the location of the previous
* transaction's output that it claims and a signature that matches the
* output's public key.
diff --git a/src/init.cpp b/src/init.cpp
index 980c589b29..70ac5190d3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -47,6 +47,7 @@ using namespace std;
#ifdef ENABLE_WALLET
CWallet* pwalletMain = NULL;
#endif
+bool fFeeEstimatesInitialized = false;
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
@@ -119,6 +120,10 @@ void Shutdown()
if (!lockShutdown)
return;
+ /// Note: Shutdown() must be able to handle cases in which AppInit2() failed part of the way,
+ /// for example if the data directory was found to be locked.
+ /// Be sure that anything that writes files or flushes caches only does this if the respective
+ /// module was initialized.
RenameThread("bitcoin-shutoff");
mempool.AddTransactionsUpdated(1);
StopRPCThreads();
@@ -130,13 +135,15 @@ void Shutdown()
StopNode();
UnregisterNodeSignals(GetNodeSignals());
+ if (fFeeEstimatesInitialized)
{
boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION);
- if (est_fileout)
+ if (!est_fileout.IsNull())
mempool.WriteFeeEstimates(est_fileout);
else
LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
+ fFeeEstimatesInitialized = false;
}
{
@@ -163,7 +170,7 @@ void Shutdown()
#ifndef WIN32
boost::filesystem::remove(GetPidFile());
#endif
- UnregisterAllWallets();
+ UnregisterAllValidationInterfaces();
#ifdef ENABLE_WALLET
delete pwalletMain;
pwalletMain = NULL;
@@ -215,9 +222,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -? " + _("This help message") + "\n";
strUsage += " -alertnotify=<cmd> " + _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)") + "\n";
strUsage += " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n";
- strUsage += " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n";
- strUsage += " -checklevel=<n> " + _("How thorough the block verification of -checkblocks is (0-4, default: 3)") + "\n";
- strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
+ strUsage += " -checkblocks=<n> " + strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288) + "\n";
+ strUsage += " -checklevel=<n> " + strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3) + "\n";
+ strUsage += " -conf=<file> " + strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf") + "\n";
if (mode == HMM_BITCOIND)
{
#if !defined(WIN32)
@@ -231,79 +238,78 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -maxorphantx=<n> " + strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS) + "\n";
strUsage += " -par=<n> " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n";
#ifndef WIN32
- strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n";
+ strUsage += " -pid=<file> " + strprintf(_("Specify pid file (default: %s)"), "bitcoind.pid") + "\n";
#endif
strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup") + "\n";
#if !defined(WIN32)
strUsage += " -sysperms " + _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)") + "\n";
#endif
- strUsage += " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n";
+ strUsage += " -txindex " + strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0) + "\n";
strUsage += "\n" + _("Connection options:") + "\n";
strUsage += " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n";
- strUsage += " -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n";
- strUsage += " -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n";
+ strUsage += " -banscore=<n> " + strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100) + "\n";
+ strUsage += " -bantime=<n> " + strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), 86400) + "\n";
strUsage += " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n";
strUsage += " -connect=<ip> " + _("Connect only to the specified node(s)") + "\n";
strUsage += " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n";
strUsage += " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + _("(default: 1)") + "\n";
strUsage += " -dnsseed " + _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)") + "\n";
strUsage += " -externalip=<ip> " + _("Specify your own public address") + "\n";
- strUsage += " -forcednsseed " + _("Always query for peer addresses via DNS lookup (default: 0)") + "\n";
+ strUsage += " -forcednsseed " + strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0) + "\n";
strUsage += " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n";
- strUsage += " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n";
- strUsage += " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n";
- strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n";
- strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
+ strUsage += " -maxconnections=<n> " + strprintf(_("Maintain at most <n> connections to peers (default: %u)"), 125) + "\n";
+ strUsage += " -maxreceivebuffer=<n> " + strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000) + "\n";
+ strUsage += " -maxsendbuffer=<n> " + strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000) + "\n";
+ strUsage += " -onion=<ip:port> " + strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy") + "\n";
strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)") + "\n";
- strUsage += " -permitbaremultisig " + _("Relay non-P2SH multisig (default: 1)") + "\n";
- strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
+ strUsage += " -permitbaremultisig " + strprintf(_("Relay non-P2SH multisig (default: %u)"), 1) + "\n";
+ strUsage += " -port=<port> " + strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), 8333, 18333) + "\n";
strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
+ strUsage += " -timeout=<n> " + strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT) + "\n";
#ifdef USE_UPNP
#if USE_UPNP
strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n";
#else
- strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n";
+ strUsage += " -upnp " + strprintf(_("Use UPnP to map the listening port (default: %u)"), 0) + "\n";
#endif
#endif
strUsage += " -whitebind=<addr> " + _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6") + "\n";
- strUsage += " -whitelist=<netmask> " + _("Whitelist peers connecting from the given netmask or ip. Can be specified multiple times.") + "\n";
+ strUsage += " -whitelist=<netmask> " + _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + "\n";
strUsage += " " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway") + "\n";
#ifdef ENABLE_WALLET
strUsage += "\n" + _("Wallet options:") + "\n";
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
- strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
+ strUsage += " -keypool=<n> " + strprintf(_("Set key pool size to <n> (default: %u)"), 100) + "\n";
if (GetBoolArg("-help-debug", false))
strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CWallet::minTxFee.GetFeePerK())) + "\n";
strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
- strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
- strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
- strUsage += " -txconfirmtarget=<n> " + _("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)") + "\n";
+ strUsage += " -spendzeroconfchange " + strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1) + "\n";
+ strUsage += " -txconfirmtarget=<n> " + strprintf(_("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: %u)"), 1) + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
- strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
+ strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
strUsage += " -zapwallettxes=<mode> " + _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + "\n";
- strUsage += " " + _("(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)") + "\n";
+ strUsage += " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)") + "\n";
#endif
strUsage += "\n" + _("Debugging/Testing options:") + "\n";
if (GetBoolArg("-help-debug", false))
{
- strUsage += " -checkpoints " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n";
- strUsage += " -dblogsize=<n> " + _("Flush database activity from memory pool to disk log every <n> megabytes (default: 100)") + "\n";
- strUsage += " -disablesafemode " + _("Disable safemode, override a real safe mode event (default: 0)") + "\n";
- strUsage += " -testsafemode " + _("Force safe mode (default: 0)") + "\n";
+ strUsage += " -checkpoints " + strprintf(_("Only accept block chain matching built-in checkpoints (default: %u)"), 1) + "\n";
+ strUsage += " -dblogsize=<n> " + strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), 100) + "\n";
+ strUsage += " -disablesafemode " + strprintf(_("Disable safemode, override a real safe mode event (default: %u)"), 0) + "\n";
+ strUsage += " -testsafemode " + strprintf(_("Force safe mode (default: %u)"), 0) + "\n";
strUsage += " -dropmessagestest=<n> " + _("Randomly drop 1 of every <n> network messages") + "\n";
strUsage += " -fuzzmessagestest=<n> " + _("Randomly fuzz 1 of every <n> network messages") + "\n";
- strUsage += " -flushwallet " + _("Run a thread to flush wallet periodically (default: 1)") + "\n";
- strUsage += " -stopafterblockimport " + _("Stop running after importing blocks from disk (default: 0)") + "\n";
+ strUsage += " -flushwallet " + strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1) + "\n";
+ strUsage += " -stopafterblockimport " + strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0) + "\n";
}
- strUsage += " -debug=<category> " + _("Output debugging information (default: 0, supplying <category> is optional)") + "\n";
+ strUsage += " -debug=<category> " + strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + "\n";
strUsage += " " + _("If <category> is not supplied, output all debugging information.") + "\n";
strUsage += " " + _("<category> can be:");
strUsage += " addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net"; // Don't translate these and qt below
@@ -311,25 +317,25 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += ", qt";
strUsage += ".\n";
#ifdef ENABLE_WALLET
- strUsage += " -gen " + _("Generate coins (default: 0)") + "\n";
- strUsage += " -genproclimit=<n> " + _("Set the processor limit for when generation is on (-1 = unlimited, default: -1)") + "\n";
+ strUsage += " -gen " + strprintf(_("Generate coins (default: %u)"), 0) + "\n";
+ strUsage += " -genproclimit=<n> " + strprintf(_("Set the processor limit for when generation is on (-1 = unlimited, default: %d)"), -1) + "\n";
#endif
strUsage += " -help-debug " + _("Show all debugging options (usage: --help -help-debug)") + "\n";
- strUsage += " -logips " + _("Include IP addresses in debug output (default: 0)") + "\n";
- strUsage += " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n";
+ strUsage += " -logips " + strprintf(_("Include IP addresses in debug output (default: %u)"), 0) + "\n";
+ strUsage += " -logtimestamps " + strprintf(_("Prepend debug output with timestamp (default: %u)"), 1) + "\n";
if (GetBoolArg("-help-debug", false))
{
- strUsage += " -limitfreerelay=<n> " + _("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)") + "\n";
- strUsage += " -maxsigcachesize=<n> " + _("Limit size of signature cache to <n> entries (default: 50000)") + "\n";
+ strUsage += " -limitfreerelay=<n> " + strprintf(_("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:%u)"), 15) + "\n";
+ strUsage += " -maxsigcachesize=<n> " + strprintf(_("Limit size of signature cache to <n> entries (default: %u)"), 50000) + "\n";
}
strUsage += " -minrelaytxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n";
strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
if (GetBoolArg("-help-debug", false))
{
strUsage += " -printblock=<hash> " + _("Print block on startup, if found in block index") + "\n";
- strUsage += " -printblocktree " + _("Print block tree on startup (default: 0)") + "\n";
- strUsage += " -printpriority " + _("Log transaction priority and fee per kB when mining blocks (default: 0)") + "\n";
- strUsage += " -privdb " + _("Sets the DB_PRIVATE flag in the wallet db environment (default: 1)") + "\n";
+ strUsage += " -printblocktree " + strprintf(_("Print block tree on startup (default: %u)"), 0) + "\n";
+ strUsage += " -printpriority " + strprintf(_("Log transaction priority and fee per kB when mining blocks (default: %u)"), 0) + "\n";
+ strUsage += " -privdb " + strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), 1) + "\n";
strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly.") + "\n";
strUsage += " " + _("This is intended for regression testing tools and app development.") + "\n";
strUsage += " " + _("In this mode -genproclimit controls how many blocks are generated immediately.") + "\n";
@@ -338,10 +344,10 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -testnet " + _("Use the test network") + "\n";
strUsage += "\n" + _("Node relay options:") + "\n";
- strUsage += " -datacarrier " + _("Relay and mine data carrier transactions (default: 1)") + "\n";
+ strUsage += " -datacarrier " + strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1) + "\n";
strUsage += "\n" + _("Block creation options:") + "\n";
- strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n";
+ strUsage += " -blockminsize=<n> " + strprintf(_("Set minimum block size in bytes (default: %u)"), 0) + "\n";
strUsage += " -blockmaxsize=<n> " + strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE) + "\n";
strUsage += " -blockprioritysize=<n> " + strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE) + "\n";
@@ -350,15 +356,15 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -rpcbind=<addr> " + _("Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)") + "\n";
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
- strUsage += " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n";
+ strUsage += " -rpcport=<port> " + strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n";
strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times") + "\n";
- strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
+ strUsage += " -rpcthreads=<n> " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
- strUsage += " -rpcsslcertificatechainfile=<file.cert> " + _("Server certificate file (default: server.cert)") + "\n";
- strUsage += " -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n";
- strUsage += " -rpcsslciphers=<ciphers> " + _("Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)") + "\n";
+ strUsage += " -rpcsslcertificatechainfile=<file.cert> " + strprintf(_("Server certificate file (default: %s)"), "server.cert") + "\n";
+ strUsage += " -rpcsslprivatekeyfile=<file.pem> " + strprintf(_("Server private key (default: %s)"), "server.pem") + "\n";
+ strUsage += " -rpcsslciphers=<ciphers> " + strprintf(_("Acceptable ciphers (default: %s)"), "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH") + "\n";
return strUsage;
}
@@ -641,12 +647,9 @@ bool AppInit2(boost::thread_group& threadGroup)
bool fDisableWallet = GetBoolArg("-disablewallet", false);
#endif
- if (mapArgs.count("-timeout"))
- {
- int nNewTimeout = GetArg("-timeout", 5000);
- if (nNewTimeout > 0 && nNewTimeout < 600000)
- nConnectTimeout = nNewTimeout;
- }
+ nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
+ if (nConnectTimeout <= 0)
+ nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
// Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support.
@@ -959,7 +962,7 @@ bool AppInit2(boost::thread_group& threadGroup)
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ pcoinsTip = new CCoinsViewCache(pcoinsdbview);
if (fReindex)
pblocktree->WriteReindexing(true);
@@ -971,7 +974,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
- if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL)
+ if (!mapBlockIndex.empty() && mapBlockIndex.count(Params().HashGenesisBlock()) == 0)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
// Initialize the block index (no-op if non-empty database was already loaded)
@@ -1061,8 +1064,9 @@ bool AppInit2(boost::thread_group& threadGroup)
boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION);
// Allowed to fail as this file IS missing on first startup.
- if (est_filein)
+ if (!est_filein.IsNull())
mempool.ReadFeeEstimates(est_filein);
+ fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
@@ -1150,7 +1154,7 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("%s", strErrors.str());
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
- RegisterWallet(pwalletMain);
+ RegisterValidationInterface(pwalletMain);
CBlockIndex *pindexRescan = chainActive.Tip();
if (GetBoolArg("-rescan", false))
@@ -1219,22 +1223,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
- // ********************************************************* Step 10: load peers
-
- uiInterface.InitMessage(_("Loading addresses..."));
-
- nStart = GetTimeMillis();
-
- {
- CAddrDB adb;
- if (!adb.Read(addrman))
- LogPrintf("Invalid or missing peers.dat; recreating\n");
- }
-
- LogPrintf("Loaded %i addresses from peers.dat %dms\n",
- addrman.size(), GetTimeMillis() - nStart);
-
- // ********************************************************* Step 11: start node
+ // ********************************************************* Step 10: start node
if (!CheckDiskSpace())
return false;
@@ -1263,7 +1252,7 @@ bool AppInit2(boost::thread_group& threadGroup)
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1));
#endif
- // ********************************************************* Step 12: finished
+ // ********************************************************* Step 11: finished
uiInterface.InitMessage(_("Done loading"));
diff --git a/src/key.cpp b/src/key.cpp
index c2251b4f2a..079e2c6540 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -179,19 +179,17 @@ public:
BN_clear_free(&bn);
}
- void GetPrivKey(CPrivKey &privkey, bool fCompressed) {
+ int GetPrivKeySize(bool fCompressed) {
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
- int nSize = i2d_ECPrivateKey(pkey, NULL);
- assert(nSize);
- privkey.resize(nSize);
- unsigned char* pbegin = &privkey[0];
- int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
- assert(nSize == nSize2);
+ return i2d_ECPrivateKey(pkey, NULL);
+ }
+ int GetPrivKey(unsigned char* privkey, bool fCompressed) {
+ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
+ return i2d_ECPrivateKey(pkey, &privkey);
}
- bool SetPrivKey(const CPrivKey &privkey, bool fSkipCheck=false) {
- const unsigned char* pbegin = &privkey[0];
- if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
+ bool SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck=false) {
+ if (d2i_ECPrivateKey(&pkey, &privkey, size)) {
if(fSkipCheck)
return true;
@@ -424,7 +422,7 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
return false;
#else
CECKey key;
- if (!key.SetPrivKey(privkey))
+ if (!key.SetPrivKey(&privkey[0], privkey.size()))
return false;
key.GetSecretBytes(vch);
#endif
@@ -436,16 +434,21 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
+ int privkeylen, ret;
#ifdef USE_SECP256K1
privkey.resize(279);
- int privkeylen = 279;
- int ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
+ privkeylen = 279;
+ ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
assert(ret);
privkey.resize(privkeylen);
#else
CECKey key;
key.SetSecretBytes(vch);
- key.GetPrivKey(privkey, fCompressed);
+ privkeylen = key.GetPrivKeySize(fCompressed);
+ assert(privkeylen);
+ privkey.resize(privkeylen);
+ ret = key.GetPrivKey(&privkey[0], fCompressed);
+ assert(ret == (int)privkey.size());
#endif
return privkey;
}
@@ -517,7 +520,7 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
return false;
#else
CECKey key;
- if (!key.SetPrivKey(privkey, fSkipCheck))
+ if (!key.SetPrivKey(&privkey[0], privkey.size(), fSkipCheck))
return false;
key.GetSecretBytes(vch);
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 98bc0e9e28..755defa26d 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -67,6 +67,13 @@ bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
return true;
}
+bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
+{
+ LOCK(cs_KeyStore);
+ setWatchOnly.erase(dest);
+ return true;
+}
+
bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
{
LOCK(cs_KeyStore);
diff --git a/src/keystore.h b/src/keystore.h
index 3b49e282d9..d3478f7672 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -40,6 +40,7 @@ public:
// Support for Watch-only addresses
virtual bool AddWatchOnly(const CScript &dest) =0;
+ virtual bool RemoveWatchOnly(const CScript &dest) =0;
virtual bool HaveWatchOnly(const CScript &dest) const =0;
virtual bool HaveWatchOnly() const =0;
};
@@ -98,6 +99,7 @@ public:
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
virtual bool AddWatchOnly(const CScript &dest);
+ virtual bool RemoveWatchOnly(const CScript &dest);
virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
};
diff --git a/src/main.cpp b/src/main.cpp
index 8b4c03c190..0cfe90beda 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -26,8 +26,8 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
-using namespace std;
using namespace boost;
+using namespace std;
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
@@ -41,6 +41,7 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
+CBlockIndex *pindexBestHeader = NULL;
int64_t nTimeBestReceived = 0;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
@@ -51,19 +52,12 @@ bool fTxIndex = false;
bool fIsBareMultisigStd = true;
unsigned int nCoinCacheSize = 5000;
+
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
CTxMemPool mempool(::minRelayTxFee);
-struct COrphanBlock {
- uint256 hashBlock;
- uint256 hashPrev;
- vector<unsigned char> vchBlock;
-};
-map<uint256, COrphanBlock*> mapOrphanBlocks;
-multimap<uint256, COrphanBlock*> mapOrphanBlocksByPrev;
-
struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
@@ -105,7 +99,11 @@ namespace {
// The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
// as good as our current tip. Entries may be failed, though.
- set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid;
+ set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+ // Number of nodes with fSyncStarted.
+ int nSyncStarted = 0;
+ // All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions.
+ multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -125,11 +123,10 @@ namespace {
// Protected by cs_main.
struct QueuedBlock {
uint256 hash;
+ CBlockIndex *pindex; // Optional.
int64_t nTime; // Time of "getdata" request in microseconds.
- int nQueuedBefore; // Number of blocks in flight at the time of request.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
- map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload;
} // anon namespace
@@ -159,25 +156,25 @@ struct CMainSignals {
} // anon namespace
-void RegisterWallet(CWalletInterface* pwalletIn) {
- g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
- g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
- g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
- g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
- g_signals.Inventory.connect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1));
- g_signals.Broadcast.connect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn));
+void RegisterValidationInterface(CValidationInterface* pwalletIn) {
+ g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
+ g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
+ g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
+ g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn));
}
-void UnregisterWallet(CWalletInterface* pwalletIn) {
- g_signals.Broadcast.disconnect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn));
- g_signals.Inventory.disconnect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1));
- g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
- g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
- g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
- g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
+void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
+ g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn));
+ g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
+ g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
+ g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
}
-void UnregisterAllWallets() {
+void UnregisterAllValidationInterfaces() {
g_signals.Broadcast.disconnect_all_slots();
g_signals.Inventory.disconnect_all_slots();
g_signals.SetBestChain.disconnect_all_slots();
@@ -220,22 +217,24 @@ struct CNodeState {
CBlockIndex *pindexBestKnownBlock;
// The hash of the last unknown block this peer has announced.
uint256 hashLastUnknownBlock;
+ // The last full block we both have.
+ CBlockIndex *pindexLastCommonBlock;
+ // Whether we've started headers synchronization with this peer.
+ bool fSyncStarted;
+ // Since when we're stalling block download progress (in microseconds), or 0.
+ int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
- list<uint256> vBlocksToDownload;
- int nBlocksToDownload;
- int64_t nLastBlockReceive;
- int64_t nLastBlockProcess;
CNodeState() {
nMisbehavior = 0;
fShouldBan = false;
pindexBestKnownBlock = NULL;
hashLastUnknownBlock = uint256(0);
- nBlocksToDownload = 0;
+ pindexLastCommonBlock = NULL;
+ fSyncStarted = false;
+ nStallingSince = 0;
nBlocksInFlight = 0;
- nLastBlockReceive = 0;
- nLastBlockProcess = 0;
}
};
@@ -266,64 +265,37 @@ void FinalizeNode(NodeId nodeid) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
+ if (state->fSyncStarted)
+ nSyncStarted--;
+
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight)
mapBlocksInFlight.erase(entry.hash);
- BOOST_FOREACH(const uint256& hash, state->vBlocksToDownload)
- mapBlocksToDownload.erase(hash);
EraseOrphansFor(nodeid);
mapNodeState.erase(nodeid);
}
// Requires cs_main.
-void MarkBlockAsReceived(const uint256 &hash, NodeId nodeFrom = -1) {
- map<uint256, pair<NodeId, list<uint256>::iterator> >::iterator itToDownload = mapBlocksToDownload.find(hash);
- if (itToDownload != mapBlocksToDownload.end()) {
- CNodeState *state = State(itToDownload->second.first);
- state->vBlocksToDownload.erase(itToDownload->second.second);
- state->nBlocksToDownload--;
- mapBlocksToDownload.erase(itToDownload);
- }
-
+void MarkBlockAsReceived(const uint256& hash) {
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
- if (itInFlight->second.first == nodeFrom)
- state->nLastBlockReceive = GetTimeMicros();
+ state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
}
}
// Requires cs_main.
-bool AddBlockToQueue(NodeId nodeid, const uint256 &hash) {
- if (mapBlocksToDownload.count(hash) || mapBlocksInFlight.count(hash))
- return false;
-
- CNodeState *state = State(nodeid);
- if (state == NULL)
- return false;
-
- list<uint256>::iterator it = state->vBlocksToDownload.insert(state->vBlocksToDownload.end(), hash);
- state->nBlocksToDownload++;
- if (state->nBlocksToDownload > 5000)
- Misbehaving(nodeid, 10);
- mapBlocksToDownload[hash] = std::make_pair(nodeid, it);
- return true;
-}
-
-// Requires cs_main.
-void MarkBlockAsInFlight(NodeId nodeid, const uint256 &hash) {
+void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex = NULL) {
CNodeState *state = State(nodeid);
assert(state != NULL);
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
- QueuedBlock newentry = {hash, GetTimeMicros(), state->nBlocksInFlight};
- if (state->nBlocksInFlight == 0)
- state->nLastBlockReceive = newentry.nTime; // Reset when a first request is sent.
+ QueuedBlock newentry = {hash, pindex, GetTimeMicros()};
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
@@ -362,6 +334,104 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
}
}
+/** Find the last common ancestor two blocks have.
+ * Both pa and pb must be non-NULL. */
+CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
+ if (pa->nHeight > pb->nHeight) {
+ pa = pa->GetAncestor(pb->nHeight);
+ } else if (pb->nHeight > pa->nHeight) {
+ pb = pb->GetAncestor(pa->nHeight);
+ }
+
+ while (pa != pb && pa && pb) {
+ pa = pa->pprev;
+ pb = pb->pprev;
+ }
+
+ // Eventually all chain branches meet at the genesis block.
+ assert(pa == pb);
+ return pa;
+}
+
+/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
+ * at most count entries. */
+void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
+ if (count == 0)
+ return;
+
+ vBlocks.reserve(vBlocks.size() + count);
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ // Make sure pindexBestKnownBlock is up to date, we'll need it.
+ ProcessBlockAvailability(nodeid);
+
+ if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) {
+ // This peer has nothing interesting.
+ return;
+ }
+
+ if (state->pindexLastCommonBlock == NULL) {
+ // Bootstrap quickly by guessing a parent of our best tip is the forking point.
+ // Guessing wrong in either direction is not a problem.
+ state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())];
+ }
+
+ // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
+ // of their current tip anymore. Go back enough to fix that.
+ state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);
+ if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
+ return;
+
+ std::vector<CBlockIndex*> vToFetch;
+ CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
+ // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
+ // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
+ // download that next block if the window were 1 larger.
+ int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
+ int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
+ NodeId waitingfor = -1;
+ while (pindexWalk->nHeight < nMaxHeight) {
+ // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards
+ // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive
+ // as iterating over ~100 CBlockIndex* entries anyway.
+ int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));
+ vToFetch.resize(nToFetch);
+ pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
+ vToFetch[nToFetch - 1] = pindexWalk;
+ for (unsigned int i = nToFetch - 1; i > 0; i--) {
+ vToFetch[i - 1] = vToFetch[i]->pprev;
+ }
+
+ // Iterate over those blocks in vToFetch (in forward direction), adding the ones that
+ // are not yet downloaded and not in flight to vBlocks. In the mean time, update
+ // pindexLastCommonBlock as long as all ancestors are already downloaded.
+ BOOST_FOREACH(CBlockIndex* pindex, vToFetch) {
+ if (pindex->nStatus & BLOCK_HAVE_DATA) {
+ if (pindex->nChainTx)
+ state->pindexLastCommonBlock = pindex;
+ } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
+ // The block is not already downloaded, and not yet in flight.
+ if (pindex->nHeight > nWindowEnd) {
+ // We reached the end of the window.
+ if (vBlocks.size() == 0 && waitingfor != nodeid) {
+ // We aren't able to fetch anything, but we would be if the download window was one larger.
+ nodeStaller = waitingfor;
+ }
+ return;
+ }
+ vBlocks.push_back(pindex);
+ if (vBlocks.size() == count) {
+ return;
+ }
+ } else if (waitingfor == -1) {
+ // This is the first already-in-flight block.
+ waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
+ }
+ }
+ }
+}
+
} // anon namespace
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
@@ -371,6 +441,11 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
return false;
stats.nMisbehavior = state->nMisbehavior;
stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
+ stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
+ BOOST_FOREACH(const QueuedBlock& queue, state->vBlocksInFlight) {
+ if (queue.pindex)
+ stats.vHeightInFlight.push_back(queue.pindex->nHeight);
+ }
return true;
}
@@ -844,12 +919,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{
CCoinsView dummy;
- CCoinsViewCache view(dummy);
+ CCoinsViewCache view(&dummy);
CAmount nValueIn = 0;
{
LOCK(pool.cs);
- CCoinsViewMemPool viewMemPool(*pcoinsTip, pool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
@@ -976,7 +1051,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
CBlockHeader header;
try {
file >> header;
- fseek(file, postx.nTxOffset, SEEK_CUR);
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
file >> txOut;
} catch (std::exception &e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
@@ -1031,7 +1106,7 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
- if (!fileout)
+ if (fileout.IsNull())
return error("WriteBlockToDisk : OpenBlockFile failed");
// Write index header
@@ -1039,16 +1114,16 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
fileout << FLATDATA(Params().MessageStart()) << nSize;
// Write block
- long fileOutPos = ftell(fileout);
+ long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("WriteBlockToDisk : ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << block;
// Flush stdio buffers and commit to disk before returning
- fflush(fileout);
+ fflush(fileout.Get());
if (!IsInitialBlockDownload())
- FileCommit(fileout);
+ FileCommit(fileout.Get());
return true;
}
@@ -1059,7 +1134,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
- if (!filein)
+ if (filein.IsNull())
return error("ReadBlockFromDisk : OpenBlockFile failed");
// Read block
@@ -1086,46 +1161,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
return true;
}
-uint256 static GetOrphanRoot(const uint256& hash)
-{
- map<uint256, COrphanBlock*>::iterator it = mapOrphanBlocks.find(hash);
- if (it == mapOrphanBlocks.end())
- return hash;
-
- // Work back to the first block in the orphan chain
- do {
- map<uint256, COrphanBlock*>::iterator it2 = mapOrphanBlocks.find(it->second->hashPrev);
- if (it2 == mapOrphanBlocks.end())
- return it->first;
- it = it2;
- } while(true);
-}
-
-// Remove a random orphan block (which does not have any dependent orphans).
-void static PruneOrphanBlocks()
-{
- if (mapOrphanBlocksByPrev.size() <= (size_t)std::max((int64_t)0, GetArg("-maxorphanblocks", DEFAULT_MAX_ORPHAN_BLOCKS)))
- return;
-
- // Pick a random orphan block.
- int pos = insecure_rand() % mapOrphanBlocksByPrev.size();
- std::multimap<uint256, COrphanBlock*>::iterator it = mapOrphanBlocksByPrev.begin();
- while (pos--) it++;
-
- // As long as this block has other orphans depending on it, move to one of those successors.
- do {
- std::multimap<uint256, COrphanBlock*>::iterator it2 = mapOrphanBlocksByPrev.find(it->second->hashBlock);
- if (it2 == mapOrphanBlocksByPrev.end())
- break;
- it = it2;
- } while(1);
-
- uint256 hash = it->second->hashBlock;
- delete it->second;
- mapOrphanBlocksByPrev.erase(it);
- mapOrphanBlocks.erase(hash);
-}
-
CAmount GetBlockValue(int nHeight, const CAmount& nFees)
{
int64_t nSubsidy = 50 * COIN;
@@ -1178,14 +1213,9 @@ void CheckForkWarningConditions()
{
if (!fLargeWorkForkFound)
{
- std::string strCmd = GetArg("-alertnotify", "");
- if (!strCmd.empty())
- {
- std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
- pindexBestForkBase->phashBlock->ToString() + std::string("'");
- boost::replace_all(strCmd, "%s", warning);
- boost::thread t(runCommand, strCmd); // thread runs free
- }
+ std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
+ pindexBestForkBase->phashBlock->ToString() + std::string("'");
+ CAlert::Notify(warning, true);
}
if (pindexBestForkTip)
{
@@ -1289,29 +1319,25 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
- setBlockIndexValid.erase(pindex);
+ setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
}
}
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
{
- bool ret;
// mark inputs spent
if (!tx.IsCoinBase()) {
txundo.vprevout.reserve(tx.vin.size());
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const CTxIn &txin = tx.vin[i];
- CCoins &coins = inputs.GetCoins(txin.prevout.hash);
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
txundo.vprevout.push_back(CTxInUndo());
- ret = coins.Spend(txin.prevout, txundo.vprevout.back());
+ bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back());
assert(ret);
}
}
// add outputs
- ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight));
- assert(ret);
+ inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
bool CScriptCheck::operator()() const {
@@ -1453,21 +1479,23 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
// exactly. Note that transactions with only provably unspendable outputs won't
// have outputs available even in the block itself, so we handle that case
// specially with outsEmpty.
+ {
CCoins outsEmpty;
- CCoins &outs = view.HaveCoins(hash) ? view.GetCoins(hash) : outsEmpty;
- outs.ClearUnspendable();
+ CCoinsModifier outs = view.ModifyCoins(hash);
+ outs->ClearUnspendable();
- CCoins outsBlock = CCoins(tx, pindex->nHeight);
+ CCoins outsBlock(tx, pindex->nHeight);
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if (outsBlock.nVersion < 0)
- outs.nVersion = outsBlock.nVersion;
- if (outs != outsBlock)
+ outs->nVersion = outsBlock.nVersion;
+ if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted");
// remove outputs
- outs = CCoins();
+ outs->Clear();
+ }
// restore inputs
if (i > 0) { // not coinbases
@@ -1477,27 +1505,24 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout;
const CTxInUndo &undo = txundo.vprevout[j];
- CCoins coins;
- view.GetCoins(out.hash, coins); // this can fail if the prevout was already entirely spent
+ CCoinsModifier coins = view.ModifyCoins(out.hash);
if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent
- if (!coins.IsPruned())
+ if (!coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction");
- coins = CCoins();
- coins.fCoinBase = undo.fCoinBase;
- coins.nHeight = undo.nHeight;
- coins.nVersion = undo.nVersion;
+ coins->Clear();
+ coins->fCoinBase = undo.fCoinBase;
+ coins->nHeight = undo.nHeight;
+ coins->nVersion = undo.nVersion;
} else {
- if (coins.IsPruned())
+ if (coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction");
}
- if (coins.IsAvailable(out.n))
+ if (coins->IsAvailable(out.n))
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output");
- if (coins.vout.size() < out.n+1)
- coins.vout.resize(out.n+1);
- coins.vout[out.n] = undo.txout;
- if (!view.SetCoins(out.hash, coins))
- return error("DisconnectBlock() : cannot restore coin inputs");
+ if (coins->vout.size() < out.n+1)
+ coins->vout.resize(out.n+1);
+ coins->vout[out.n] = undo.txout;
}
}
}
@@ -1674,11 +1699,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
if (fJustCheck)
return true;
- // Correct transaction counts.
- pindex->nTx = block.vtx.size();
- if (pindex->pprev)
- pindex->nChainTx = pindex->pprev->nChainTx + block.vtx.size();
-
// Write undo information to disk
if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS))
{
@@ -1706,9 +1726,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
return state.Abort("Failed to write transaction index");
// add this block to the view's block chain
- bool ret;
- ret = view.SetBestBlock(pindex->GetBlockHash());
- assert(ret);
+ view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
@@ -1752,15 +1770,16 @@ void static UpdateTip(CBlockIndex *pindexNew) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
+ LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), 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(chainActive.Tip()));
+ Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize());
cvBlockChange.notify_all();
// Check the version of the last 100 blocks to see if we need to upgrade:
- if (!IsInitialBlockDownload())
+ static bool fWarned = false;
+ if (!IsInitialBlockDownload() && !fWarned)
{
int nUpgraded = 0;
const CBlockIndex* pindex = chainActive.Tip();
@@ -1773,8 +1792,12 @@ void static UpdateTip(CBlockIndex *pindexNew) {
if (nUpgraded > 0)
LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION);
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;
+ }
}
}
@@ -1790,7 +1813,7 @@ bool static DisconnectTip(CValidationState &state) {
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
if (!DisconnectBlock(block, state, pindexDelete, view))
return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush());
@@ -1843,7 +1866,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
int64_t nTime3;
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
if (!ConnectBlock(*pblock, state, pindexNew, view)) {
if (state.IsInvalid())
@@ -1896,8 +1919,8 @@ static CBlockIndex* FindMostWorkChain() {
// Find the best candidate header.
{
- std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
- if (it == setBlockIndexValid.rend())
+ std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexCandidates.rbegin();
+ if (it == setBlockIndexCandidates.rend())
return NULL;
pindexNew = *it;
}
@@ -1907,6 +1930,8 @@ static CBlockIndex* FindMostWorkChain() {
CBlockIndex *pindexTest = pindexNew;
bool fInvalidAncestor = false;
while (pindexTest && !chainActive.Contains(pindexTest)) {
+ assert(pindexTest->nStatus & BLOCK_HAVE_DATA);
+ assert(pindexTest->nChainTx || pindexTest->nHeight == 0);
if (pindexTest->nStatus & BLOCK_FAILED_MASK) {
// Candidate has an invalid ancestor, remove entire chain from the set.
if (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
@@ -1914,10 +1939,10 @@ static CBlockIndex* FindMostWorkChain() {
CBlockIndex *pindexFailed = pindexNew;
while (pindexTest != pindexFailed) {
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
- setBlockIndexValid.erase(pindexFailed);
+ setBlockIndexCandidates.erase(pindexFailed);
pindexFailed = pindexFailed->pprev;
}
- setBlockIndexValid.erase(pindexTest);
+ setBlockIndexCandidates.erase(pindexTest);
fInvalidAncestor = true;
break;
}
@@ -1944,12 +1969,20 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
// Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect;
- vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
- CBlockIndex *pindexIter = pindexMostWork;
- while (pindexIter && pindexIter != pindexFork) {
+ bool fContinue = true;
+ int nHeight = pindexFork ? pindexFork->nHeight : -1;
+ while (fContinue && nHeight != pindexMostWork->nHeight) {
+ // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need
+ // a few blocks along the way.
+ int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight);
+ vpindexToConnect.clear();
+ vpindexToConnect.reserve(nTargetHeight - nHeight);
+ CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight);
+ while (pindexIter && pindexIter->nHeight != nHeight) {
vpindexToConnect.push_back(pindexIter);
pindexIter = pindexIter->pprev;
}
+ nHeight = nTargetHeight;
// Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
@@ -1960,27 +1993,30 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
InvalidChainFound(vpindexToConnect.back());
state = CValidationState();
fInvalidFound = true;
+ fContinue = false;
break;
} else {
// A system error occurred (disk space, database error, ...).
return false;
}
} else {
- // Delete all entries in setBlockIndexValid that are worse than our new current block.
+ // Delete all entries in setBlockIndexCandidates that are worse than our new current block.
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
- std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexValid.begin();
- while (setBlockIndexValid.value_comp()(*it, chainActive.Tip())) {
- setBlockIndexValid.erase(it++);
+ std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
+ while (setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) {
+ setBlockIndexCandidates.erase(it++);
}
- // Either the current tip or a successor of it we're working towards is left in setBlockIndexValid.
- assert(!setBlockIndexValid.empty());
+ // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates.
+ assert(!setBlockIndexCandidates.empty());
if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {
// We're in a better position than we were. Return temporarily to release the lock.
+ fContinue = false;
break;
}
}
}
+ }
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
@@ -2026,10 +2062,10 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
// Relay inventory, but don't relay old inventory during initial block download.
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
{
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
- pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
}
uiInterface.NotifyBlockTip(hashNewTip);
@@ -2039,7 +2075,7 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
return true;
}
-CBlockIndex* AddToBlockIndex(CBlockHeader& block)
+CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
{
// Check for duplicate
uint256 hash = block.GetHash();
@@ -2050,10 +2086,10 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block);
assert(pindexNew);
- {
- LOCK(cs_nBlockSequenceId);
- pindexNew->nSequenceId = nBlockSequenceId++;
- }
+ // We assign the sequence id to blocks only when the full data is available,
+ // to avoid miners withholding blocks but broadcasting headers, to get a
+ // competitive advantage.
+ pindexNew->nSequenceId = 0;
BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
@@ -2065,6 +2101,11 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
}
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork();
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
+ if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork)
+ pindexBestHeader = pindexNew;
+
+ // Ok if it fails, we'll download the header again next time.
+ pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew));
return pindexNew;
}
@@ -2073,30 +2114,45 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{
pindexNew->nTx = block.vtx.size();
- if (pindexNew->pprev) {
- // Not the genesis block.
- if (pindexNew->pprev->nChainTx) {
- // This parent's block's total number transactions is known, so compute outs.
- pindexNew->nChainTx = pindexNew->pprev->nChainTx + pindexNew->nTx;
- } else {
- // The total number of transactions isn't known yet.
- // We will compute it when the block is connected.
- pindexNew->nChainTx = 0;
- }
- } else {
- // Genesis block.
- pindexNew->nChainTx = pindexNew->nTx;
- }
+ pindexNew->nChainTx = 0;
pindexNew->nFile = pos.nFile;
pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
+ pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
+ {
+ LOCK(cs_nBlockSequenceId);
+ pindexNew->nSequenceId = nBlockSequenceId++;
+ }
- if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS))
- setBlockIndexValid.insert(pindexNew);
-
- if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
- return state.Abort("Failed to write block index");
+ if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) {
+ // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS.
+ deque<CBlockIndex*> queue;
+ queue.push_back(pindexNew);
+
+ // Recursively process any descendant blocks that now may be eligible to be connected.
+ while (!queue.empty()) {
+ CBlockIndex *pindex = queue.front();
+ queue.pop_front();
+ pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
+ setBlockIndexCandidates.insert(pindex);
+ std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);
+ while (range.first != range.second) {
+ std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first;
+ queue.push_back(it->second);
+ range.first++;
+ mapBlocksUnlinked.erase(it);
+ }
+ if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex)))
+ return state.Abort("Failed to write block index");
+ }
+ } else {
+ if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) {
+ mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew));
+ }
+ if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
+ return state.Abort("Failed to write block index");
+ }
return true;
}
@@ -2203,12 +2259,31 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
{
- // These are checks that are independent of context
- // that can be verified before saving an orphan block.
+ // These are checks that are independent of context.
if (!CheckBlockHeader(block, state, fCheckPOW))
return false;
+ // Check the merkle root.
+ if (fCheckMerkleRoot) {
+ bool mutated;
+ uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated);
+ if (block.hashMerkleRoot != hashMerkleRoot2)
+ return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
+ REJECT_INVALID, "bad-txnmrklroot", true);
+
+ // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
+ // of transactions in a block without affecting the merkle root of a block,
+ // while still invalidating it.
+ if (mutated)
+ return state.DoS(100, error("CheckBlock() : duplicate transaction"),
+ REJECT_INVALID, "bad-txns-duplicate", true);
+ }
+
+ // All potential-corruption validation must be done before we do any
+ // transaction validation, as otherwise we may mark the header as invalid
+ // because we receive the wrong transactions for it.
+
// Size limits
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"),
@@ -2228,15 +2303,6 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
- // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
- // of transactions in a block without affecting the merkle root of a block,
- // while still invalidating it.
- bool mutated;
- uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated);
- if (mutated)
- return state.DoS(100, error("CheckBlock() : duplicate transaction"),
- REJECT_INVALID, "bad-txns-duplicate", true);
-
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
@@ -2246,15 +2312,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"),
REJECT_INVALID, "bad-blk-sigops", true);
- // Check merkle root
- if (fCheckMerkleRoot && block.hashMerkleRoot != hashMerkleRoot2)
- return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
- REJECT_INVALID, "bad-txnmrklroot", true);
-
return true;
}
-bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex)
+bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex)
{
AssertLockHeld(cs_main);
// Check for duplicate
@@ -2262,26 +2323,13 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = NULL;
if (miSelf != mapBlockIndex.end()) {
+ // Block header is already known.
pindex = miSelf->second;
+ if (ppindex)
+ *ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK)
return state.Invalid(error("%s : block is marked invalid", __func__), 0, "duplicate");
- }
-
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
- if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
- {
- // Extra checks to prevent "fill up memory by spamming with bogus blocks"
- int64_t deltaTime = block.GetBlockTime() - pcheckpoint->GetBlockTime();
- if (deltaTime < 0)
- {
- return state.DoS(100, error("%s : block with timestamp before last checkpoint", __func__),
- REJECT_CHECKPOINT, "time-too-old");
- }
- if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime))
- {
- return state.DoS(100, error("%s : block with too little proof-of-work", __func__),
- REJECT_INVALID, "bad-diffbits");
- }
+ return true;
}
// Get prev block index
@@ -2342,6 +2390,12 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (!AcceptBlockHeader(block, state, &pindex))
return false;
+ if (pindex->nStatus & BLOCK_HAVE_DATA) {
+ // TODO: deal better with duplicate blocks.
+ // return state.DoS(20, error("AcceptBlock() : already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
+ return true;
+ }
+
if (!CheckBlock(block, state)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
@@ -2454,93 +2508,26 @@ void CBlockIndex::BuildSkip()
pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}
-void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
-{
- AssertLockHeld(cs_main);
- // Filter out duplicate requests
- if (pindexBegin == pnode->pindexLastGetBlocksBegin && hashEnd == pnode->hashLastGetBlocksEnd)
- return;
- pnode->pindexLastGetBlocksBegin = pindexBegin;
- pnode->hashLastGetBlocksEnd = hashEnd;
-
- pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd);
-}
-
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
- // Check for duplicate
- uint256 hash = pblock->GetHash();
-
- {
- LOCK(cs_main);
- if (mapBlockIndex.count(hash))
- return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()), 0, "duplicate");
- if (mapOrphanBlocks.count(hash))
- return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate");
-
// Preliminary checks
- if (!CheckBlock(*pblock, state))
- return error("ProcessBlock() : CheckBlock FAILED");
+ bool checked = CheckBlock(*pblock, state);
- // If we don't already have its previous block (with full data), shunt it off to holding area until we get it
- BlockMap::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
- if (pblock->hashPrevBlock != 0 && (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)))
{
- LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString());
-
- // Accept orphans as long as there is a node to request its parents from
- if (pfrom) {
- PruneOrphanBlocks();
- COrphanBlock* pblock2 = new COrphanBlock();
- {
- CDataStream ss(SER_DISK, CLIENT_VERSION);
- ss << *pblock;
- pblock2->vchBlock = std::vector<unsigned char>(ss.begin(), ss.end());
- }
- pblock2->hashBlock = hash;
- pblock2->hashPrev = pblock->hashPrevBlock;
- mapOrphanBlocks.insert(make_pair(hash, pblock2));
- mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrev, pblock2));
-
- // Ask this guy to fill in what we're missing
- PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(hash));
+ LOCK(cs_main);
+ MarkBlockAsReceived(pblock->GetHash());
+ if (!checked) {
+ return error("ProcessBlock() : CheckBlock FAILED");
}
- return true;
- }
- // Store to disk
- CBlockIndex *pindex = NULL;
- bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
- if (!ret)
- return error("ProcessBlock() : AcceptBlock FAILED");
-
- // Recursively process any orphan blocks that depended on this one
- vector<uint256> vWorkQueue;
- vWorkQueue.push_back(hash);
- for (unsigned int i = 0; i < vWorkQueue.size(); i++)
- {
- uint256 hashPrev = vWorkQueue[i];
- for (multimap<uint256, COrphanBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
- mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
- ++mi)
- {
- CBlock block;
- {
- CDataStream ss(mi->second->vchBlock, SER_DISK, CLIENT_VERSION);
- ss >> block;
- }
- block.BuildMerkleTree();
- // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
- CValidationState stateDummy;
- CBlockIndex *pindexChild = NULL;
- if (AcceptBlock(block, stateDummy, &pindexChild))
- vWorkQueue.push_back(mi->second->hashBlock);
- mapOrphanBlocks.erase(mi->second->hashBlock);
- delete mi->second;
+ // Store to disk
+ CBlockIndex *pindex = NULL;
+ bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
+ if (pindex && pfrom) {
+ mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
}
- mapOrphanBlocksByPrev.erase(hashPrev);
- }
-
+ if (!ret)
+ return error("ProcessBlock() : AcceptBlock FAILED");
}
if (!ActivateBestChain(state, pblock))
@@ -2806,13 +2793,26 @@ bool static LoadBlockIndexDB()
{
CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork();
- pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
- if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS))
- setBlockIndexValid.insert(pindex);
+ if (pindex->nStatus & BLOCK_HAVE_DATA) {
+ if (pindex->pprev) {
+ if (pindex->pprev->nChainTx) {
+ pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
+ } else {
+ pindex->nChainTx = 0;
+ mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex));
+ }
+ } else {
+ pindex->nChainTx = pindex->nTx;
+ }
+ }
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
+ setBlockIndexCandidates.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindex;
if (pindex->pprev)
pindex->BuildSkip();
+ if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
+ pindexBestHeader = pindex;
}
// Load block file info
@@ -2845,7 +2845,7 @@ bool static LoadBlockIndexDB()
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)
{
CDiskBlockPos pos(*it, 0);
- if (!CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION)) {
+ if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) {
return false;
}
}
@@ -2895,7 +2895,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
nCheckDepth = chainActive.Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
- CCoinsViewCache coins(*coinsview, true);
+ CCoinsViewCache coins(coinsview);
CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
@@ -2961,7 +2961,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
void UnloadBlockIndex()
{
mapBlockIndex.clear();
- setBlockIndexValid.clear();
+ setBlockIndexCandidates.clear();
chainActive.SetTip(NULL);
pindexBestInvalid = NULL;
}
@@ -3084,21 +3084,14 @@ void PrintBlockTree()
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
{
+ // Map of disk positions for blocks with unknown parent (only used for reindex)
+ static std::multimap<uint256, CDiskBlockPos> mapBlocksUnknownParent;
int64_t nStart = GetTimeMillis();
int nLoaded = 0;
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
- uint64_t nStartByte = 0;
- if (dbp) {
- // (try to) skip already indexed part
- CBlockFileInfo info;
- if (pblocktree->ReadBlockFileInfo(dbp->nFile, info)) {
- nStartByte = info.nSize;
- blkdat.Seek(info.nSize);
- }
- }
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
boost::this_thread::interruption_point();
@@ -3126,21 +3119,57 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
try {
// read block
uint64_t nBlockPos = blkdat.GetPos();
+ if (dbp)
+ dbp->nPos = nBlockPos;
blkdat.SetLimit(nBlockPos + nSize);
+ blkdat.SetPos(nBlockPos);
CBlock block;
blkdat >> block;
nRewind = blkdat.GetPos();
- // process block
- if (nBlockPos >= nStartByte) {
+ // detect out of order blocks, and store them for later
+ uint256 hash = block.GetHash();
+ if (hash != Params().HashGenesisBlock() && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) {
+ LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
+ block.hashPrevBlock.ToString());
if (dbp)
- dbp->nPos = nBlockPos;
+ mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
+ continue;
+ }
+
+ // process in case the block isn't known yet
+ if (mapBlockIndex.count(hash) == 0) {
CValidationState state;
if (ProcessBlock(state, NULL, &block, dbp))
nLoaded++;
if (state.IsError())
break;
}
+
+ // Recursively process earlier encountered successors of this block
+ deque<uint256> queue;
+ queue.push_back(hash);
+ while (!queue.empty()) {
+ uint256 head = queue.front();
+ queue.pop_front();
+ std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
+ while (range.first != range.second) {
+ std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
+ if (ReadBlockFromDisk(block, it->second))
+ {
+ LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
+ head.ToString());
+ CValidationState dummy;
+ if (ProcessBlock(dummy, NULL, &block, &it->second))
+ {
+ nLoaded++;
+ queue.push_back(block.GetHash());
+ }
+ }
+ range.first++;
+ mapBlocksUnknownParent.erase(it);
+ }
+ }
} catch (std::exception &e) {
LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what());
}
@@ -3235,8 +3264,7 @@ bool static AlreadyHave(const CInv& inv)
pcoinsTip->HaveCoins(inv.hash);
}
case MSG_BLOCK:
- return mapBlockIndex.count(inv.hash) ||
- mapOrphanBlocks.count(inv.hash);
+ return mapBlockIndex.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
@@ -3384,10 +3412,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
- {
- LOCK(cs_main);
- State(pfrom->GetId())->nLastBlockProcess = GetTimeMicros();
- }
@@ -3596,6 +3620,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
+ std::vector<CInv> vToFetch;
+
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
{
const CInv &inv = vInv[nInv];
@@ -3606,19 +3632,30 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fAlreadyHave = AlreadyHave(inv);
LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
- if (!fAlreadyHave) {
- if (!fImporting && !fReindex) {
- if (inv.type == MSG_BLOCK)
- AddBlockToQueue(pfrom->GetId(), inv.hash);
- else
- pfrom->AskFor(inv);
- }
- } else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
- PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(inv.hash));
- }
+ if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK)
+ pfrom->AskFor(inv);
- if (inv.type == MSG_BLOCK)
+ if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom->GetId(), inv.hash);
+ if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
+ // First request the headers preceeding the announced block. In the normal fully-synced
+ // case where a new block is announced that succeeds the current tip (no reorganization),
+ // there are no such headers.
+ // Secondly, and only when we are close to being synced, we request the announced block directly,
+ // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the
+ // time the block arrives, the header chain leading up to it is already validated. Not
+ // doing this will result in the received block being rejected as an orphan in case it is
+ // not a direct successor.
+ pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash);
+ if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - Params().TargetSpacing() * 20) {
+ vToFetch.push_back(inv);
+ // Mark block as in flight already, even though the actual "getdata" message only goes out
+ // later (within the same cs_main lock, though).
+ MarkBlockAsInFlight(pfrom->GetId(), inv.hash);
+ }
+ LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
+ }
+ }
// Track requests for our stuff
g_signals.Inventory(inv.hash);
@@ -3628,6 +3665,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return error("send buffer size() = %u", pfrom->nSendSize);
}
}
+
+ if (!vToFetch.empty())
+ pfrom->PushMessage("getdata", vToFetch);
}
@@ -3715,8 +3755,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
- int nLimit = 2000;
- LogPrint("net", "getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString());
+ int nLimit = MAX_HEADERS_RESULTS;
+ LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -3835,22 +3875,67 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
+ else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing
+ {
+ std::vector<CBlockHeader> headers;
+
+ // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
+ unsigned int nCount = ReadCompactSize(vRecv);
+ if (nCount > MAX_HEADERS_RESULTS) {
+ Misbehaving(pfrom->GetId(), 20);
+ return error("headers message size = %u", nCount);
+ }
+ headers.resize(nCount);
+ for (unsigned int n = 0; n < nCount; n++) {
+ vRecv >> headers[n];
+ ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
+ }
+
+ LOCK(cs_main);
+
+ if (nCount == 0) {
+ // Nothing interesting. Stop asking this peers for more headers.
+ return true;
+ }
+
+ CBlockIndex *pindexLast = NULL;
+ BOOST_FOREACH(const CBlockHeader& header, headers) {
+ CValidationState state;
+ if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) {
+ Misbehaving(pfrom->GetId(), 20);
+ return error("non-continuous headers sequence");
+ }
+ if (!AcceptBlockHeader(header, state, &pindexLast)) {
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ if (nDoS > 0)
+ Misbehaving(pfrom->GetId(), nDoS);
+ return error("invalid header received");
+ }
+ }
+ }
+
+ if (pindexLast)
+ UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
+
+ if (nCount == MAX_HEADERS_RESULTS && pindexLast) {
+ // Headers message had its maximum size; the peer may have more headers.
+ // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
+ // from there instead.
+ LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
+ pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256(0));
+ }
+ }
+
else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlock block;
vRecv >> block;
- LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id);
-
CInv inv(MSG_BLOCK, block.GetHash());
- pfrom->AddInventoryKnown(inv);
+ LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id);
- {
- LOCK(cs_main);
- // Remember who we got this block from.
- mapBlockSource[inv.hash] = pfrom->GetId();
- MarkBlockAsReceived(inv.hash, pfrom->GetId());
- }
+ pfrom->AddInventoryKnown(inv);
CValidationState state;
ProcessBlock(state, pfrom, &block);
@@ -4332,9 +4417,18 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
state.rejects.clear();
// Start block sync
- if (pto->fStartSync && !fImporting && !fReindex) {
- pto->fStartSync = false;
- PushGetBlocks(pto, chainActive.Tip(), uint256(0));
+ if (pindexBestHeader == NULL)
+ pindexBestHeader = chainActive.Tip();
+ bool fFetch = !pto->fInbound || (pindexBestHeader && (state.pindexLastCommonBlock ? state.pindexLastCommonBlock->nHeight : 0) + 144 > pindexBestHeader->nHeight);
+ if (!state.fSyncStarted && !pto->fClient && fFetch && !fImporting && !fReindex) {
+ // Only actively request headers from a single peer, unless we're close to today.
+ if (nSyncStarted == 0 || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
+ state.fSyncStarted = true;
+ nSyncStarted++;
+ CBlockIndex *pindexStart = pindexBestHeader->pprev ? pindexBestHeader->pprev : pindexBestHeader;
+ LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
+ pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256(0));
+ }
}
// Resend wallet transactions that haven't gotten in a block yet
@@ -4393,35 +4487,35 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!vInv.empty())
pto->PushMessage("inv", vInv);
-
- // Detect stalled peers. Require that blocks are in flight, we haven't
- // received a (requested) block in one minute, and that all blocks are
- // in flight for over two minutes, since we first had a chance to
- // process an incoming block.
+ // Detect whether we're stalling
int64_t nNow = GetTimeMicros();
- if (!pto->fDisconnect && state.nBlocksInFlight &&
- state.nLastBlockReceive < state.nLastBlockProcess - BLOCK_DOWNLOAD_TIMEOUT*1000000 &&
- state.vBlocksInFlight.front().nTime < state.nLastBlockProcess - 2*BLOCK_DOWNLOAD_TIMEOUT*1000000) {
- LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name);
+ if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
+ // Stalling only triggers when the block download window cannot move. During normal steady state,
+ // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
+ // should only happen during initial block download.
+ LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true;
}
- // Update knowledge of peer's block availability.
- ProcessBlockAvailability(pto->GetId());
-
//
// Message: getdata (blocks)
//
vector<CInv> vGetData;
- while (!pto->fDisconnect && state.nBlocksToDownload && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- uint256 hash = state.vBlocksToDownload.front();
- vGetData.push_back(CInv(MSG_BLOCK, hash));
- MarkBlockAsInFlight(pto->GetId(), hash);
- LogPrint("net", "Requesting block %s peer=%d\n", hash.ToString(), pto->id);
- if (vGetData.size() >= 1000)
- {
- pto->PushMessage("getdata", vGetData);
- vGetData.clear();
+ if (!pto->fDisconnect && !pto->fClient && fFetch && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ vector<CBlockIndex*> vToDownload;
+ NodeId staller = -1;
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
+ vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex);
+ LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->id);
+ }
+ if (state.nBlocksInFlight == 0 && staller != -1) {
+ if (State(staller)->nStallingSince == 0) {
+ State(staller)->nStallingSince = nNow;
+ LogPrint("net", "Stall started peer=%d\n", staller);
+ }
}
}
@@ -4456,7 +4550,7 @@ bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
- if (!fileout)
+ if (fileout.IsNull())
return error("CBlockUndo::WriteToDisk : OpenUndoFile failed");
// Write index header
@@ -4464,7 +4558,7 @@ bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
fileout << FLATDATA(Params().MessageStart()) << nSize;
// Write undo data
- long fileOutPos = ftell(fileout);
+ long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("CBlockUndo::WriteToDisk : ftell failed");
pos.nPos = (unsigned int)fileOutPos;
@@ -4477,9 +4571,9 @@ bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
fileout << hasher.GetHash();
// Flush stdio buffers and commit to disk before returning
- fflush(fileout);
+ fflush(fileout.Get());
if (!IsInitialBlockDownload())
- FileCommit(fileout);
+ FileCommit(fileout.Get());
return true;
}
@@ -4488,7 +4582,7 @@ bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock
{
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
- if (!filein)
+ if (filein.IsNull())
return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
// Read block
@@ -4528,12 +4622,6 @@ public:
delete (*it1).second;
mapBlockIndex.clear();
- // orphan blocks
- std::map<uint256, COrphanBlock*>::iterator it2 = mapOrphanBlocks.begin();
- for (; it2 != mapOrphanBlocks.end(); it2++)
- delete (*it2).second;
- mapOrphanBlocks.clear();
-
// orphan transactions
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
diff --git a/src/main.h b/src/main.h
index cad7eebfb7..c0c1fb2707 100644
--- a/src/main.h
+++ b/src/main.h
@@ -72,9 +72,17 @@ static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
/** Number of blocks that can be requested at any given time from a single peer. */
-static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 128;
-/** Timeout in seconds before considering a block download peer unresponsive. */
-static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60;
+static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
+/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
+static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
+/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
+ * less than this number, we reached their tip. Changing this value is a protocol upgrade. */
+static const unsigned int MAX_HEADERS_RESULTS = 2000;
+/** Size of the "block download window": how far ahead of our current height do we fetch?
+ * Larger windows tolerate larger download speed differences between peer, but increase the potential
+ * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
+ * harder). We'll probably want to make this a per-peer adaptive value at some point. */
+static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** "reject" message codes **/
static const unsigned char REJECT_MALFORMED = 0x01;
@@ -110,6 +118,9 @@ extern bool fIsBareMultisigStd;
extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee;
+// Best header we've seen so far (used for getheaders queries' starting points).
+extern CBlockIndex *pindexBestHeader;
+
// Minimum disk space required - used in CheckDiskSpace()
static const uint64_t nMinDiskSpace = 52428800;
@@ -118,17 +129,17 @@ class CBlockTreeDB;
class CTxUndo;
class CScriptCheck;
class CValidationState;
-class CWalletInterface;
+class CValidationInterface;
struct CNodeStateStats;
struct CBlockTemplate;
/** Register a wallet to receive updates from core */
-void RegisterWallet(CWalletInterface* pwalletIn);
+void RegisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister a wallet from core */
-void UnregisterWallet(CWalletInterface* pwalletIn);
+void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
-void UnregisterAllWallets();
+void UnregisterAllValidationInterfaces();
/** Push an updated transaction to all registered wallets */
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
@@ -137,8 +148,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
-
/** Process an incoming block */
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
@@ -193,6 +202,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
struct CNodeStateStats {
int nMisbehavior;
int nSyncHeight;
+ int nCommonHeight;
+ std::vector<int> vHeightInFlight;
};
struct CDiskTxPos : public CDiskBlockPos
@@ -439,9 +450,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
// Apply the effects of this block (with given index) on the UTXO set represented by coins
bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
-// Add this block to the block index, and if necessary, switch the active block chain to this
-bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
-
// Context-independent validity checks
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
@@ -449,7 +457,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = t
// Store block on disk
// if dbp is provided, the file is known to already reside on disk
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
-bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
+bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
@@ -632,17 +640,17 @@ public:
};
-class CWalletInterface {
+class CValidationInterface {
protected:
- virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) =0;
- virtual void EraseFromWallet(const uint256 &hash) =0;
- virtual void SetBestChain(const CBlockLocator &locator) =0;
- virtual void UpdatedTransaction(const uint256 &hash) =0;
- virtual void Inventory(const uint256 &hash) =0;
- virtual void ResendWalletTransactions() =0;
- friend void ::RegisterWallet(CWalletInterface*);
- friend void ::UnregisterWallet(CWalletInterface*);
- friend void ::UnregisterAllWallets();
+ virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {};
+ virtual void EraseFromWallet(const uint256 &hash) {};
+ virtual void SetBestChain(const CBlockLocator &locator) {};
+ virtual void UpdatedTransaction(const uint256 &hash) {};
+ virtual void Inventory(const uint256 &hash) {};
+ virtual void ResendWalletTransactions() {};
+ friend void ::RegisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterAllValidationInterfaces();
};
#endif // BITCOIN_MAIN_H
diff --git a/src/miner.cpp b/src/miner.cpp
index 280349e8c2..a1f9bd597f 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -17,6 +17,7 @@
#endif
#include <boost/thread.hpp>
+#include <boost/tuple/tuple.hpp>
using namespace std;
@@ -83,6 +84,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return NULL;
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ // -regtest only: allow overriding block.nVersion with
+ // -blockversion=N to test forking scenarios
+ if (Params().MineBlocksOnDemand())
+ pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+
// Create coinbase tx
CMutableTransaction txNew;
txNew.vin.resize(1);
@@ -116,7 +122,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
{
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
- CCoinsViewCache view(*pcoinsTip, true);
+ CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
@@ -316,7 +322,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
- CCoinsViewCache viewNew(*pcoinsTip, true);
+ CCoinsViewCache viewNew(pcoinsTip);
CValidationState state;
if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
diff --git a/src/net.cpp b/src/net.cpp
index 866bac2c0e..6cf64f51c3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -73,11 +73,11 @@ map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
-static CNode* pnodeSync = NULL;
uint64_t nLocalHostNonce = 0;
static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
int nMaxConnections = 125;
+bool fAddressesInitialized = false;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@@ -518,10 +518,6 @@ void CNode::CloseSocketDisconnect()
TRY_LOCK(cs_vRecvMsg, lockRecv);
if (lockRecv)
vRecvMsg.clear();
-
- // if this was the sync node, we'll need a new one
- if (this == pnodeSync)
- pnodeSync = NULL;
}
void CNode::PushVersion()
@@ -614,7 +610,6 @@ void CNode::copyStats(CNodeStats &stats)
X(nSendBytes);
X(nRecvBytes);
X(fWhitelisted);
- stats.fSyncNode = (this == pnodeSync);
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
@@ -1486,61 +1481,20 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
}
-// for now, use a very simple selection metric: the node from which we received
-// most recently
-static int64_t NodeSyncScore(const CNode *pnode) {
- return pnode->nLastRecv;
-}
-
-void static StartSync(const vector<CNode*> &vNodes) {
- CNode *pnodeNewSync = NULL;
- int64_t nBestScore = 0;
-
- int nBestHeight = g_signals.GetHeight().get_value_or(0);
-
- // Iterate over all nodes
- BOOST_FOREACH(CNode* pnode, vNodes) {
- // check preconditions for allowing a sync
- if (!pnode->fClient && !pnode->fOneShot &&
- !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
- (pnode->nStartingHeight > (nBestHeight - 144)) &&
- (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
- // if ok, compare node's score with the best so far
- int64_t nScore = NodeSyncScore(pnode);
- if (pnodeNewSync == NULL || nScore > nBestScore) {
- pnodeNewSync = pnode;
- nBestScore = nScore;
- }
- }
- }
- // if a new sync candidate was found, start sync!
- if (pnodeNewSync) {
- pnodeNewSync->fStartSync = true;
- pnodeSync = pnodeNewSync;
- }
-}
-
void ThreadMessageHandler()
{
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true)
{
- bool fHaveSyncNode = false;
-
vector<CNode*> vNodesCopy;
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy) {
pnode->AddRef();
- if (pnode == pnodeSync)
- fHaveSyncNode = true;
}
}
- if (!fHaveSyncNode)
- StartSync(vNodesCopy);
-
// Poll the connected nodes for messages
CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty())
@@ -1739,6 +1693,18 @@ void static Discover(boost::thread_group& threadGroup)
void StartNode(boost::thread_group& threadGroup)
{
+ uiInterface.InitMessage(_("Loading addresses..."));
+ // Load addresses for peers.dat
+ int64_t nStart = GetTimeMillis();
+ {
+ CAddrDB adb;
+ if (!adb.Read(addrman))
+ LogPrintf("Invalid or missing peers.dat; recreating\n");
+ }
+ LogPrintf("Loaded %i addresses from peers.dat %dms\n",
+ addrman.size(), GetTimeMillis() - nStart);
+ fAddressesInitialized = true;
+
if (semOutbound == NULL) {
// initialize semaphore
int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
@@ -1785,7 +1751,12 @@ bool StopNode()
if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
semOutbound->post();
- DumpAddresses();
+
+ if (fAddressesInitialized)
+ {
+ DumpAddresses();
+ fAddressesInitialized = false;
+ }
return true;
}
@@ -1958,7 +1929,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (!fileout)
+ if (fileout.IsNull())
return error("%s : Failed to open file %s", __func__, pathTmp.string());
// Write and commit header, data
@@ -1968,7 +1939,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
catch (std::exception &e) {
return error("%s : Serialize or I/O error - %s", __func__, e.what());
}
- FileCommit(fileout);
+ FileCommit(fileout.Get());
fileout.fclose();
// replace existing peers.dat, if any, with new peers.dat.XXXX
@@ -1983,7 +1954,7 @@ bool CAddrDB::Read(CAddrMan& addr)
// open input file, and associate with CAutoFile
FILE *file = fopen(pathAddr.string().c_str(), "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
- if (!filein)
+ if (filein.IsNull())
return error("%s : Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer
@@ -2060,10 +2031,7 @@ CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fIn
nSendSize = 0;
nSendOffset = 0;
hashContinue = 0;
- pindexLastGetBlocksBegin = 0;
- hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
- fStartSync = false;
fGetAddr = false;
fRelayTxes = false;
setInventoryKnown.max_size(SendBufferSize() / 1000);
diff --git a/src/net.h b/src/net.h
index ad0a1df7e2..18da24183f 100644
--- a/src/net.h
+++ b/src/net.h
@@ -158,7 +158,6 @@ public:
int nStartingHeight;
uint64_t nSendBytes;
uint64_t nRecvBytes;
- bool fSyncNode;
bool fWhitelisted;
double dPingTime;
double dPingWait;
@@ -276,10 +275,7 @@ protected:
public:
uint256 hashContinue;
- CBlockIndex* pindexLastGetBlocksBegin;
- uint256 hashLastGetBlocksEnd;
int nStartingHeight;
- bool fStartSync;
// flood relay
std::vector<CAddress> vAddrToSend;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 5819c152a3..b3d1001547 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -40,7 +40,7 @@ using namespace std;
static proxyType proxyInfo[NET_MAX];
static CService nameProxy;
static CCriticalSection cs_proxyInfos;
-int nConnectTimeout = 5000;
+int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = false;
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
diff --git a/src/netbase.h b/src/netbase.h
index 9fc5c72eb8..1455cd8c33 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -19,6 +19,9 @@
extern int nConnectTimeout;
extern bool fNameLookup;
+/** -timeout default */
+static const int DEFAULT_CONNECT_TIMEOUT = 5000;
+
#ifdef WIN32
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
#undef SetPort
diff --git a/src/noui.cpp b/src/noui.cpp
index f786a20db5..8f3b0275b0 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -14,6 +14,9 @@
static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
+ bool fSecure = style & CClientUIInterface::SECURE;
+ style &= ~CClientUIInterface::SECURE;
+
std::string strCaption;
// Check for usage of predefined caption
switch (style) {
@@ -30,7 +33,8 @@ static bool noui_ThreadSafeMessageBox(const std::string& message, const std::str
strCaption += caption; // Use supplied caption (can be empty)
}
- LogPrintf("%s: %s\n", strCaption, message);
+ if (!fSecure)
+ LogPrintf("%s: %s\n", strCaption, message);
fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
return false;
}
diff --git a/src/pow.cpp b/src/pow.cpp
index d50222849c..75fbfc6a6d 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -98,39 +98,6 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
return true;
}
-//
-// true if nBits is greater than the minimum amount of work that could
-// possibly be required deltaTime after minimum work required was nBase
-//
-bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime)
-{
- bool fOverflow = false;
- uint256 bnNewBlock;
- bnNewBlock.SetCompact(nBits, NULL, &fOverflow);
- if (fOverflow)
- return false;
-
- const uint256 &bnLimit = Params().ProofOfWorkLimit();
- // Testnet has min-difficulty blocks
- // after Params().TargetSpacing()*2 time between blocks:
- if (Params().AllowMinDifficultyBlocks() && deltaTime > Params().TargetSpacing()*2)
- return bnNewBlock <= bnLimit;
-
- uint256 bnResult;
- bnResult.SetCompact(nBase);
- while (deltaTime > 0 && bnResult < bnLimit)
- {
- // Maximum 400% adjustment...
- bnResult *= 4;
- // ... in best-case exactly 4-times-normal target time
- deltaTime -= Params().TargetTimespan()*4;
- }
- if (bnResult > bnLimit)
- bnResult = bnLimit;
-
- return bnNewBlock <= bnResult;
-}
-
void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev)
{
pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
diff --git a/src/pow.h b/src/pow.h
index 5d91108ac4..233d1f3795 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -16,8 +16,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
-/** Check the work is more than the minimum a received block needs, without knowing its direct parent */
-bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime);
void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 5e2fdc6c30..9872ebc1f6 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -12,6 +12,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
+#include "networkstyle.h"
#include "optionsmodel.h"
#include "splashscreen.h"
#include "utilitydialog.h"
@@ -190,9 +191,9 @@ public:
/// Create options model
void createOptionsModel();
/// Create main window
- void createWindow(bool isaTestNet);
+ void createWindow(const NetworkStyle *networkStyle);
/// Create splash screen
- void createSplashScreen(bool isaTestNet);
+ void createSplashScreen(const NetworkStyle *networkStyle);
/// Request core initialization
void requestInitialize();
@@ -331,18 +332,18 @@ void BitcoinApplication::createOptionsModel()
optionsModel = new OptionsModel();
}
-void BitcoinApplication::createWindow(bool isaTestNet)
+void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
{
- window = new BitcoinGUI(isaTestNet, 0);
+ window = new BitcoinGUI(networkStyle, 0);
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
pollShutdownTimer->start(200);
}
-void BitcoinApplication::createSplashScreen(bool isaTestNet)
+void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
- SplashScreen *splash = new SplashScreen(0, isaTestNet);
+ SplashScreen *splash = new SplashScreen(0, networkStyle);
// We don't hold a direct pointer to the splash screen after creation, so use
// Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
splash->setAttribute(Qt::WA_DeleteOnClose);
@@ -572,12 +573,10 @@ int main(int argc, char *argv[])
if (!PaymentServer::ipcParseCommandLine(argc, argv))
exit(0);
#endif
- bool isaTestNet = Params().NetworkID() != CBaseChainParams::MAIN;
+ QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
+ assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets
- if (isaTestNet)
- QApplication::setApplicationName(QAPP_APP_NAME_TESTNET);
- else
- QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
+ QApplication::setApplicationName(networkStyle->getAppName());
// Re-initialize translations after changing application name (language in network-specific settings can be different)
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
@@ -617,11 +616,11 @@ int main(int argc, char *argv[])
uiInterface.InitMessage.connect(InitMessage);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
- app.createSplashScreen(isaTestNet);
+ app.createSplashScreen(networkStyle.data());
try
{
- app.createWindow(isaTestNet);
+ app.createWindow(networkStyle.data());
app.requestInitialize();
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Bitcoin Core didn't yet exit safely..."), (HWND)app.getMainWinId());
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 7380fbd240..f0471c32f9 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -8,6 +8,7 @@
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
+#include "networkstyle.h"
#include "notificator.h"
#include "openuridialog.h"
#include "optionsdialog.h"
@@ -59,7 +60,7 @@
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
walletFrame(0),
@@ -112,26 +113,13 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
} else {
windowTitle += tr("Node");
}
-
- if (!fIsTestnet)
- {
+ windowTitle += " " + networkStyle->getTitleAddText();
#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
- setWindowIcon(QIcon(":icons/bitcoin"));
+ QApplication::setWindowIcon(networkStyle->getAppIcon());
+ setWindowIcon(networkStyle->getAppIcon());
#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
+ MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon());
#endif
- }
- else
- {
- windowTitle += " " + tr("[testnet]");
-#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
- setWindowIcon(QIcon(":icons/bitcoin_testnet"));
-#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
-#endif
- }
setWindowTitle(windowTitle);
#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
@@ -161,7 +149,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
// Create actions for the toolbar, menu bar and tray/dock icon
// Needs walletFrame to be initialized
- createActions(fIsTestnet);
+ createActions(networkStyle);
// Create application menu bar
createMenuBar();
@@ -170,7 +158,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
createToolBars();
// Create system tray icon and notification
- createTrayIcon(fIsTestnet);
+ createTrayIcon(networkStyle);
// Create status bar
statusBar();
@@ -248,7 +236,7 @@ BitcoinGUI::~BitcoinGUI()
#endif
}
-void BitcoinGUI::createActions(bool fIsTestnet)
+void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
{
QActionGroup *tabGroup = new QActionGroup(this);
@@ -295,10 +283,7 @@ void BitcoinGUI::createActions(bool fIsTestnet)
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- if (!fIsTestnet)
- aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin Core"), this);
- else
- aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin Core"), this);
+ aboutAction = new QAction(networkStyle->getAppIcon(), tr("&About Bitcoin Core"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin Core"));
aboutAction->setMenuRole(QAction::AboutRole);
#if QT_VERSION < 0x050000
@@ -311,10 +296,7 @@ void BitcoinGUI::createActions(bool fIsTestnet)
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- if (!fIsTestnet)
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
- else
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this);
+ toggleHideAction = new QAction(networkStyle->getAppIcon(), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
@@ -505,22 +487,13 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
openAction->setEnabled(enabled);
}
-void BitcoinGUI::createTrayIcon(bool fIsTestnet)
+void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
{
#ifndef Q_OS_MAC
trayIcon = new QSystemTrayIcon(this);
-
- if (!fIsTestnet)
- {
- trayIcon->setToolTip(tr("Bitcoin Core client"));
- trayIcon->setIcon(QIcon(":/icons/bitcoin"));
- }
- else
- {
- trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]"));
- trayIcon->setIcon(QIcon(":/icons/bitcoin_testnet"));
- }
-
+ QString toolTip = tr("Bitcoin Core client") + " " + networkStyle->getTitleAddText();
+ trayIcon->setToolTip(toolTip);
+ trayIcon->setIcon(networkStyle->getAppIcon());
trayIcon->show();
#endif
@@ -692,7 +665,7 @@ void BitcoinGUI::setNumBlocks(int count)
QDateTime currentDate = QDateTime::currentDateTime();
int secs = lastBlockDate.secsTo(currentDate);
- tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
+ tooltip = tr("Processed %n blocks of transaction history.", "", count);
// Set icon state: spinning if catching up, tick otherwise
if(secs < 90*60)
@@ -1019,6 +992,9 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress)
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
+ // The SECURE flag has no effect in the Qt GUI.
+ // bool secure = (style & CClientUIInterface::SECURE);
+ style &= ~CClientUIInterface::SECURE;
bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(gui, "message",
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 8af6eda867..f65f0e9137 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -19,6 +19,7 @@
#include <QSystemTrayIcon>
class ClientModel;
+class NetworkStyle;
class Notificator;
class OptionsModel;
class RPCConsole;
@@ -46,7 +47,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
- explicit BitcoinGUI(bool fIsTestnet = false, QWidget *parent = 0);
+ explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
@@ -114,13 +115,13 @@ private:
int spinnerFrame;
/** Create the main UI actions. */
- void createActions(bool fIsTestnet);
+ void createActions(const NetworkStyle *networkStyle);
/** Create the menu bar and sub-menus. */
void createMenuBar();
/** Create the toolbars */
void createToolBars();
/** Create system tray icon and notification */
- void createTrayIcon(bool fIsTestnet);
+ void createTrayIcon(const NetworkStyle *networkStyle);
/** Create system tray menu (or setup the dock menu) */
void createTrayIconMenu();
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 25c811183f..1073b6a472 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -22,11 +22,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"It is also recommended to set alertnotify so you are notified of problems;\n"
"for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"(default: 1, 1 = keep tx meta data e.g. account owner and payment request "
-"information, 2 = drop tx meta data)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!"
-"3DES:@STRENGTH)"),
+"(1 = keep tx meta data e.g. account owner and payment request information, 2 "
+"= drop tx meta data)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Allow JSON-RPC connections from specified source. Valid for <ip> are a "
"single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or "
@@ -49,7 +46,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Continuously rate-limit free transactions to <n>*1000 bytes per minute "
-"(default:15)"),
+"(default:%u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Create new files with system default permissions, instead of umask 077 (only "
"effective with disabled wallet functionality)"),
@@ -75,9 +72,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Unsupported argument -socks found. Setting SOCKS version isn't "
"possible anymore, only SOCKS5 proxies are supported."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Execute command when a network tx respends wallet tx input (%s=respend TxID, "
-"%t=wallet TxID)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a relevant alert is received or we see a really long "
"fork (%s in cmd is replaced by message)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -94,22 +88,24 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Flush database activity from memory pool to disk log every <n> megabytes "
-"(default: 100)"),
+"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"How thorough the block verification of -checkblocks is (0-4, default: 3)"),
+"How thorough the block verification of -checkblocks is (0-4, default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"If paytxfee is not set, include enough fee so transactions are confirmed on "
-"average within n blocks (default: 1)"),
+"average within n blocks (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"In this mode -genproclimit controls how many blocks are generated "
"immediately."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)"),
+"Log transaction priority and fee per kB when mining blocks (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Maintain a full transaction index, used by the getrawtransaction rpc call "
+"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Number of seconds to keep misbehaving peers from reconnecting (default: "
-"86400)"),
+"Number of seconds to keep misbehaving peers from reconnecting (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Output debugging information (default: 0, supplying <category> is optional)"),
+"Output debugging information (default: %u, supplying <category> is optional)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Query for peer addresses via DNS lookup, if low on addresses (default: 1 "
"unless -connect)"),
@@ -120,7 +116,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"leave that many cores free, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set the processor limit for when generation is on (-1 = unlimited, default: "
-"-1)"),
+"%d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This is a pre-release test build - use at your own risk - do not use for "
"mining or merchant applications"),
@@ -132,8 +128,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. Bitcoin Core is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -"
-"proxy)"),
+"Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: "
+"%s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: -paytxfee is set very high! This is the transaction fee you will "
"pay if you send a transaction."),
@@ -154,19 +150,20 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect "
"you should restore from a backup."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Whitelist peers connecting from the given netmask or ip. Can be specified "
-"multiple times."),
+"Whitelist peers connecting from the given netmask or IP address. Can be "
+"specified multiple times."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Whitelisted peers cannot be DoS banned and their transactions are always "
"relayed, even if they are already in the mempool, useful e.g. for a gateway"),
+QT_TRANSLATE_NOOP("bitcoin-core", "(default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "(default: wallet.dat)"),
QT_TRANSLATE_NOOP("bitcoin-core", "<category> can be:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Acceptable ciphers (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Always query for peer addresses via DNS lookup (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Always query for peer addresses via DNS lookup (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
@@ -182,7 +179,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) 2009-%i The Bitcoin Core Develo
QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"),
QT_TRANSLATE_NOOP("bitcoin-core", "Could not parse -rpcbind value %s as network address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Debugging/Testing options:"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Disable safemode, override a real safe mode event (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Disable safemode, override a real safe mode event (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do not load the wallet and disable wallet RPC calls"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"),
@@ -201,13 +198,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unsupported argument -tor found, use -
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in BTC/kB) to add to transactions you send (default: %s)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Force safe mode (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Force safe mode (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: %u, 0 = all)"),
QT_TRANSLATE_NOOP("bitcoin-core", "If <category> is not supplied, output all debugging information."),
QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. Bitcoin Core is shutting down."),
@@ -222,61 +219,60 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable blocks in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Limit size of signature cache to <n> entries (default: 50000)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Limit size of signature cache to <n> entries (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: %u or testnet: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Log transaction priority and fee per kB when mining blocks (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Maintain a full transaction index (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (ipv4, ipv6 or onion)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Print block on startup, if found in block index"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Print block tree on startup (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Print block tree on startup (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC server options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly drop 1 of every <n> network messages"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly fuzz 1 of every <n> network messages"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild block chain index from current blk000??.dat files"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Run a thread to flush wallet periodically (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Run a thread to flush wallet periodically (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: %d)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: 4)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Sets the DB_PRIVATE flag in the wallet db environment (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: %d)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Show all debugging options (usage: --help -help-debug)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (default: 5000)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (minimum: 1, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Stop running after importing blocks from disk (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Stop running after importing blocks from disk (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is intended for regression testing tools and app development."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must be positive"),
@@ -285,7 +281,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind r
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 1 when listening)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index 7f28209c9a..898df2b080 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -836,29 +836,6 @@
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_25">
- <property name="text">
- <string>Sync Node</string>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <widget class="QLabel" name="peerSyncNode">
- <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_29">
<property name="text">
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index d469c9a0bd..7618bff69d 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -215,10 +215,10 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable
{
ui->freeSpace->setText("");
} else {
- QString freeString = QString::number(bytesAvailable/GB_BYTES) + tr("GB of free space available");
+ QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
if(bytesAvailable < BLOCK_CHAIN_SIZE)
{
- freeString += " " + tr("(of %1GB needed)").arg(BLOCK_CHAIN_SIZE/GB_BYTES);
+ freeString += " " + tr("(of %n GB needed)", "", BLOCK_CHAIN_SIZE/GB_BYTES);
ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
} else {
ui->freeSpace->setStyleSheet("");
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 5c3abef2e7..df285441e1 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -286,27 +286,27 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+327"/>
+ <location filename="../bitcoingui.cpp" line="+309"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+348"/>
+ <location line="+339"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-420"/>
+ <location line="-405"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
<message>
- <location line="-142"/>
+ <location line="-129"/>
<source>Node</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+143"/>
+ <location line="+130"/>
<source>Show general overview of wallet</source>
<translation>Show general overview of wallet</translation>
</message>
@@ -331,7 +331,7 @@
<translation>Quit application</translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+7"/>
<location line="+2"/>
<source>About &amp;Qt</source>
<translation>About &amp;Qt</translation>
@@ -347,7 +347,7 @@
<translation>&amp;Options...</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+6"/>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encrypt Wallet...</translation>
</message>
@@ -377,13 +377,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+175"/>
- <location line="+5"/>
+ <location line="+172"/>
<source>Bitcoin Core client</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+158"/>
+ <location line="+157"/>
<source>Importing blocks from disk...</source>
<translation>Importing blocks from disk...</translation>
</message>
@@ -393,17 +392,17 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="-418"/>
+ <location line="-403"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
<message>
- <location line="+49"/>
+ <location line="+46"/>
<source>Modify configuration options for Bitcoin</source>
<translation>Modify configuration options for Bitcoin</translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+9"/>
<source>Backup wallet to another location</source>
<translation>Backup wallet to another location</translation>
</message>
@@ -428,17 +427,17 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+446"/>
+ <location line="+437"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-664"/>
+ <location line="-636"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
<message>
- <location line="+151"/>
+ <location line="+138"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -448,13 +447,12 @@
<translation>&amp;Receive</translation>
</message>
<message>
- <location line="+33"/>
+ <location line="+30"/>
<source>Show information about Bitcoin Core</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <location line="+2"/>
+ <location line="+12"/>
<source>&amp;Show / Hide</source>
<translation>&amp;Show / Hide</translation>
</message>
@@ -499,29 +497,22 @@
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="-289"/>
- <location line="+393"/>
- <source>[testnet]</source>
- <translation>[testnet]</translation>
- </message>
- <message>
- <location line="-418"/>
+ <location line="-295"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
<message>
- <location line="+168"/>
+ <location line="+155"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+29"/>
- <location line="+2"/>
+ <location line="+28"/>
<source>&amp;About Bitcoin Core</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+35"/>
+ <location line="+32"/>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"></translation>
</message>
@@ -546,7 +537,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+316"/>
+ <location line="+307"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -558,13 +549,8 @@
<source>No block source available...</source>
<translation>No block source available...</translation>
</message>
- <message>
- <location line="+10"/>
- <source>Processed %1 blocks of transaction history.</source>
- <translation>Processed %1 blocks of transaction history.</translation>
- </message>
<message numerus="yes">
- <location line="+26"/>
+ <location line="+36"/>
<source>%n hour(s)</source>
<translation>
<numerusform>%n hour</numerusform>
@@ -636,8 +622,16 @@
<source>Up to date</source>
<translation>Up to date</translation>
</message>
+ <message numerus="yes">
+ <location line="-5"/>
+ <source>Processed %n blocks of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
+ </message>
<message>
- <location line="+44"/>
+ <location line="+49"/>
<source>Catching up...</source>
<translation>Catching up...</translation>
</message>
@@ -1172,15 +1166,21 @@ Address: %4
<source>Error</source>
<translation>Error</translation>
</message>
- <message>
+ <message numerus="yes">
<location line="+9"/>
- <source>GB of free space available</source>
- <translation>GB of free space available</translation>
+ <source>%n GB of free space available</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
</message>
- <message>
+ <message numerus="yes">
<location line="+3"/>
- <source>(of %1GB needed)</source>
- <translation>(of %1GB needed)</translation>
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
</message>
</context>
<context>
@@ -1813,12 +1813,11 @@ Address: %4
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
- <location line="+23"/>
<source>N/A</source>
<translation>N/A</translation>
</message>
<message>
- <location line="-990"/>
+ <location line="-967"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -1921,11 +1920,6 @@ Address: %4
</message>
<message>
<location line="+23"/>
- <source>Sync Node</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+23"/>
<source>Starting Height</source>
<translation type="unfinished"></translation>
</message>
@@ -1970,7 +1964,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-764"/>
+ <location line="-741"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -2086,17 +2080,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Yes</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+0"/>
- <source>No</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+12"/>
+ <location line="+13"/>
<source>Unknown</source>
<translation type="unfinished"></translation>
</message>
@@ -2853,7 +2837,7 @@ Address: %4
<context>
<name>SplashScreen</name>
<message>
- <location filename="../splashscreen.cpp" line="+34"/>
+ <location filename="../splashscreen.cpp" line="+35"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -2863,7 +2847,7 @@ Address: %4
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location filename="../networkstyle.cpp" line="+19"/>
<source>[testnet]</source>
<translation>[testnet]</translation>
</message>
@@ -3418,7 +3402,7 @@ Address: %4
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+103"/>
+ <location filename="../bitcoingui.cpp" line="+106"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
@@ -3485,62 +3469,27 @@ Address: %4
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+240"/>
+ <location filename="../bitcoinstrings.cpp" line="+236"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
<message>
- <location line="+28"/>
- <source>Specify configuration file (default: bitcoin.conf)</source>
- <translation>Specify configuration file (default: bitcoin.conf)</translation>
- </message>
- <message>
- <location line="+3"/>
- <source>Specify pid file (default: bitcoind.pid)</source>
- <translation>Specify pid file (default: bitcoind.pid)</translation>
- </message>
- <message>
- <location line="-1"/>
+ <location line="+30"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-44"/>
- <source>Listen for connections on &lt;port&gt; (default: 8333 or testnet: 18333)</source>
- <translation>Listen for connections on &lt;port&gt; (default: 8333 or testnet: 18333)</translation>
- </message>
- <message>
- <location line="+6"/>
- <source>Maintain at most &lt;n&gt; connections to peers (default: 125)</source>
- <translation>Maintain at most &lt;n&gt; connections to peers (default: 125)</translation>
- </message>
- <message>
- <location line="-53"/>
+ <location line="-90"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+94"/>
+ <location line="+93"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="+6"/>
- <source>Threshold for disconnecting misbehaving peers (default: 100)</source>
- <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation>
- </message>
- <message>
- <location line="-171"/>
- <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
- <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation>
- </message>
- <message>
- <location line="-2"/>
- <source>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</source>
- <translation>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</translation>
- </message>
- <message>
- <location line="+59"/>
+ <location line="-108"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
@@ -3560,7 +3509,7 @@ Address: %4
<translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
</message>
<message>
- <location line="-154"/>
+ <location line="-150"/>
<source>%s, you must set a rpcpassword in the configuration file:
%s
It is recommended you use the following random password:
@@ -3585,22 +3534,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</translation>
</message>
<message>
- <location line="+15"/>
- <source>Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+10"/>
+ <location line="+22"/>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation>
</message>
<message>
- <location line="+13"/>
- <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default:15)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+6"/>
+ <location line="+19"/>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation type="unfinished"></translation>
</message>
@@ -3620,37 +3559,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+9"/>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
- <location line="+12"/>
- <source>Flush database activity from memory pool to disk log every &lt;n&gt; megabytes (default: 100)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
- <source>How thorough the block verification of -checkblocks is (0-4, default: 3)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
+ <location line="+20"/>
<source>In this mode -genproclimit controls how many blocks are generated immediately.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+17"/>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Set the processor limit for when generation is on (-1 = unlimited, default: -1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+6"/>
<source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
<translation>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation>
</message>
@@ -3660,12 +3584,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
<translation>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</translation>
</message>
@@ -3690,13 +3609,13 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>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.</translation>
</message>
<message>
- <location line="+10"/>
- <source>(default: 1)</source>
+ <location line="+4"/>
+ <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>(default: wallet.dat)</source>
+ <location line="+7"/>
+ <source>(default: 1)</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -3705,7 +3624,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+7"/>
<source>Attempt to recover private keys from a corrupt wallet.dat</source>
<translation>Attempt to recover private keys from a corrupt wallet.dat</translation>
</message>
@@ -3735,12 +3654,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Disable safemode, override a real safe mode event (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Discover own IP address (default: 1 when listening and no -externalip)</source>
<translation>Discover own IP address (default: 1 when listening and no -externalip)</translation>
</message>
@@ -3795,22 +3709,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
<message>
- <location line="+2"/>
- <source>Force safe mode (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Generate coins (default: 0)</source>
- <translation>Generate coins (default: 0)</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>How many blocks to check at startup (default: 288, 0 = all)</source>
- <translation>How many blocks to check at startup (default: 288, 0 = all)</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+5"/>
<source>If &lt;category&gt; is not supplied, output all debugging information.</source>
<translation type="unfinished"></translation>
</message>
@@ -3830,7 +3729,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+21"/>
<source>Not enough file descriptors available.</source>
<translation>Not enough file descriptors available.</translation>
</message>
@@ -3840,12 +3739,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Prepend debug output with timestamp (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+7"/>
+ <location line="+10"/>
<source>Rebuild block chain index from current blk000??.dat files</source>
<translation>Rebuild block chain index from current blk000??.dat files</translation>
</message>
@@ -3860,32 +3754,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Set the number of threads to service RPC calls (default: 4)</source>
- <translation>Set the number of threads to service RPC calls (default: 4)</translation>
- </message>
- <message>
- <location line="+9"/>
+ <location line="+11"/>
<source>Specify wallet file (within data directory)</source>
<translation>Specify wallet file (within data directory)</translation>
</message>
<message>
- <location line="+2"/>
- <source>Spend unconfirmed change when sending transactions (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Stop running after importing blocks from disk (default: 0)</source>
+ <location line="+6"/>
+ <source>This is intended for regression testing tools and app development.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>This is intended for regression testing tools and app development.</source>
+ <location line="+10"/>
+ <source>Use UPnP to map the listening port (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+4"/>
<source>Verifying blocks...</source>
<translation>Verifying blocks...</translation>
</message>
@@ -3910,17 +3794,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>You need to rebuild the database using -reindex to change -txindex</translation>
</message>
<message>
- <location line="-92"/>
+ <location line="-91"/>
<source>Imports blocks from external blk000??.dat file</source>
<translation>Imports blocks from external blk000??.dat file</translation>
</message>
<message>
- <location line="-185"/>
- <source>(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+6"/>
+ <location line="-179"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source>
<translation type="unfinished"></translation>
</message>
@@ -3945,7 +3824,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+3"/>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default:%u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
<translation type="unfinished"></translation>
</message>
@@ -3966,11 +3850,6 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<location line="+3"/>
- <source>Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
<source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source>
<translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation>
</message>
@@ -3985,17 +3864,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
- <source>If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+11"/>
- <source>Output debugging information (default: 0, supplying &lt;category&gt; is optional)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+2"/>
+ <location line="+23"/>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
<translation type="unfinished"></translation>
</message>
@@ -4015,22 +3884,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
- <source>Whitelist peers connecting from the given netmask or ip. Can be specified multiple times.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+19"/>
<source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
- <source>Always query for peer addresses via DNS lookup (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+6"/>
+ <location line="+17"/>
<source>Cannot resolve -whitebind address: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4065,12 +3924,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
- <source>Include IP addresses in debug output (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+2"/>
+ <location line="+9"/>
<source>Information</source>
<translation>Information</translation>
</message>
@@ -4110,32 +3964,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Limit size of signature cache to &lt;n&gt; entries (default: 50000)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
- <source>Log transaction priority and fee per kB when mining blocks (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Maintain a full transaction index (default: 0)</source>
- <translation>Maintain a full transaction index (default: 0)</translation>
- </message>
- <message>
- <location line="+2"/>
- <source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: 5000)</source>
- <translation>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: 5000)</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: 1000)</source>
- <translation>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: 1000)</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+10"/>
<source>Need to specify a port with -whitebind: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4145,22 +3974,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Only accept block chain matching built-in checkpoints (default: 1)</source>
- <translation>Only accept block chain matching built-in checkpoints (default: 1)</translation>
- </message>
- <message>
- <location line="+5"/>
+ <location line="+7"/>
<source>Print block on startup, if found in block index</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Print block tree on startup (default: 0)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
<translation type="unfinished"></translation>
</message>
@@ -4180,37 +3999,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Relay and mine data carrier transactions (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Relay non-P2SH multisig (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
- <source>Run a thread to flush wallet periodically (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+2"/>
+ <location line="+8"/>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Send trace/debug info to console instead of debug.log file</translation>
</message>
<message>
- <location line="+6"/>
- <source>Set minimum block size in bytes (default: 0)</source>
- <translation>Set minimum block size in bytes (default: 0)</translation>
- </message>
- <message>
- <location line="+2"/>
- <source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+9"/>
<source>Show all debugging options (usage: --help -help-debug)</source>
<translation type="unfinished"></translation>
</message>
@@ -4225,12 +4019,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Signing transaction failed</translation>
</message>
<message>
- <location line="+2"/>
- <source>Specify connection timeout in milliseconds (default: 5000)</source>
- <translation>Specify connection timeout in milliseconds (default: 5000)</translation>
- </message>
- <message>
- <location line="+8"/>
+ <location line="+10"/>
<source>This is experimental software.</source>
<translation type="unfinished"></translation>
</message>
@@ -4255,12 +4044,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>Use UPnP to map the listening port (default: 0)</source>
- <translation>Use UPnP to map the listening port (default: 0)</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+5"/>
<source>Use UPnP to map the listening port (default: 1 when listening)</source>
<translation>Use UPnP to map the listening port (default: 1 when listening)</translation>
</message>
@@ -4315,22 +4099,17 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-155"/>
+ <location line="-157"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+200"/>
+ <location line="+202"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
<message>
- <location line="-26"/>
- <source>Set key pool size to &lt;n&gt; (default: 100)</source>
- <translation>Set key pool size to &lt;n&gt; (default: 100)</translation>
- </message>
- <message>
- <location line="-8"/>
+ <location line="-34"/>
<source>Rescan the block chain for missing wallet transactions</source>
<translation>Rescan the block chain for missing wallet transactions</translation>
</message>
@@ -4340,52 +4119,252 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Use OpenSSL (https) for JSON-RPC connections</translation>
</message>
<message>
- <location line="-30"/>
- <source>Server certificate file (default: server.cert)</source>
- <translation>Server certificate file (default: server.cert)</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Server private key (default: server.pem)</source>
- <translation>Server private key (default: server.pem)</translation>
- </message>
- <message>
- <location line="+18"/>
+ <location line="-11"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
<message>
- <location line="-108"/>
+ <location line="-107"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+59"/>
+ <location line="+60"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-33"/>
+ <location line="-34"/>
<source>Error loading wallet.dat: Wallet corrupted</source>
<translation>Error loading wallet.dat: Wallet corrupted</translation>
</message>
<message>
- <location line="-1"/>
+ <location line="-167"/>
+ <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+65"/>
+ <source>Flush database activity from memory pool to disk log every &lt;n&gt; megabytes (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Log transaction priority and fee per kB when mining blocks (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Number of seconds to keep misbehaving peers from reconnecting (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Set the processor limit for when generation is on (-1 = unlimited, default: %d)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+28"/>
+ <source>(default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Acceptable ciphers (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Always query for peer addresses via DNS lookup (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+16"/>
+ <source>Disable safemode, override a real safe mode event (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
<source>Error loading wallet.dat</source>
<translation>Error loading wallet.dat</translation>
</message>
<message>
- <location line="+23"/>
+ <location line="+11"/>
+ <source>Force safe mode (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Generate coins (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>How many blocks to check at startup (default: %u, 0 = all)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Include IP addresses in debug output (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Invalid -proxy address: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+69"/>
+ <location line="+9"/>
+ <source>Limit size of signature cache to &lt;n&gt; entries (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Listen for connections on &lt;port&gt; (default: %u or testnet: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Maintain at most &lt;n&gt; connections to peers (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Only accept block chain matching built-in checkpoints (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Prepend debug output with timestamp (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Print block tree on startup (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Relay and mine data carrier transactions (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Relay non-P2SH multisig (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Run a thread to flush wallet periodically (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Server certificate file (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Server private key (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Set key pool size to &lt;n&gt; (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Set minimum block size in bytes (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Set the number of threads to service RPC calls (default: %d)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Sets the DB_PRIVATE flag in the wallet db environment (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Specify configuration file (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Specify connection timeout in milliseconds (minimum: 1, default: %d)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Specify pid file (default: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Spend unconfirmed change when sending transactions (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Stop running after importing blocks from disk (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Threshold for disconnecting misbehaving peers (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-112"/>
+ <location line="-111"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -4410,22 +4389,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+15"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-61"/>
+ <location line="-62"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+63"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-57"/>
+ <location line="-58"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -4435,22 +4414,22 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+77"/>
+ <location line="+76"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-64"/>
+ <location line="-63"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+91"/>
+ <location line="+90"/>
<source>To use the %s option</source>
<translation>To use the %s option</translation>
</message>
<message>
- <location line="-83"/>
+ <location line="-82"/>
<source>Error</source>
<translation>Error</translation>
</message>
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
new file mode 100644
index 0000000000..62c44703f4
--- /dev/null
+++ b/src/qt/networkstyle.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "networkstyle.h"
+
+#include "guiconstants.h"
+
+#include <QApplication>
+
+static const struct {
+ const char *networkId;
+ const char *appName;
+ const char *appIcon;
+ const char *titleAddText;
+ const char *splashImage;
+} network_styles[] = {
+ {"main", QAPP_APP_NAME_DEFAULT, ":/icons/bitcoin", "", ":/images/splash"},
+ {"test", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", QT_TRANSLATE_NOOP("SplashScreen", "[testnet]"), ":/images/splash_testnet"},
+ {"regtest", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", "[regtest]", ":/images/splash_testnet"}
+};
+static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
+
+// titleAddText needs to be const char* for tr()
+NetworkStyle::NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage):
+ appName(appName),
+ appIcon(appIcon),
+ titleAddText(qApp->translate("SplashScreen", titleAddText)),
+ splashImage(splashImage)
+{
+}
+
+const NetworkStyle *NetworkStyle::instantiate(const QString &networkId)
+{
+ for (unsigned x=0; x<network_styles_count; ++x)
+ {
+ if (networkId == network_styles[x].networkId)
+ {
+ return new NetworkStyle(
+ network_styles[x].appName,
+ network_styles[x].appIcon,
+ network_styles[x].titleAddText,
+ network_styles[x].splashImage);
+ }
+ }
+ return 0;
+}
diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h
new file mode 100644
index 0000000000..99304d61a3
--- /dev/null
+++ b/src/qt/networkstyle.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_NETWORKSTYLE
+#define H_NETWORKSTYLE
+
+#include <QIcon>
+#include <QPixmap>
+#include <QString>
+
+/* Coin network-specific GUI style information */
+class NetworkStyle
+{
+public:
+ /** Get style associated with provided BIP70 network id, or 0 if not known */
+ static const NetworkStyle *instantiate(const QString &networkId);
+
+ const QString &getAppName() const { return appName; }
+ const QIcon &getAppIcon() const { return appIcon; }
+ const QString &getTitleAddText() const { return titleAddText; }
+ const QPixmap &getSplashImage() const { return splashImage; }
+
+private:
+ NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage);
+
+ QString appName;
+ QIcon appIcon;
+ QString titleAddText;
+ QPixmap splashImage;
+};
+
+#endif // H_NETWORKSTYLE
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index cb80bd0e3d..6db654dff7 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -119,6 +119,8 @@ void OptionsModel::Init()
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
+ else if(!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty())
+ addOverriddenOption("-proxy");
// Display
if (!settings.contains("language"))
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 8129353d4b..2d2d448b49 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -611,7 +611,6 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight));
- ui->peerSyncNode->setText(stats->nodeStats.fSyncNode ? tr("Yes") : tr("No"));
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 4fe610794f..b4b81440ca 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -6,6 +6,7 @@
#include "clientversion.h"
#include "init.h"
+#include "networkstyle.h"
#include "ui_interface.h"
#include "util.h"
#include "version.h"
@@ -19,7 +20,7 @@
#include <QDesktopWidget>
#include <QPainter>
-SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
+SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
QWidget(0, f), curAlignment(0)
{
// set reference point, paddings
@@ -34,17 +35,12 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
QString titleText = tr("Bitcoin Core");
QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion()));
QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers"));
- QString testnetAddText = QString(tr("[testnet]")); // define text to place as single text object
+ QString titleAddText = networkStyle->getTitleAddText();
QString font = "Arial";
// load the bitmap for writing some text over it
- if(isTestNet) {
- pixmap = QPixmap(":/images/splash_testnet");
- }
- else {
- pixmap = QPixmap(":/images/splash");
- }
+ pixmap = networkStyle->getSplashImage();
QPainter pixPaint(&pixmap);
pixPaint.setPen(QColor(100,100,100));
@@ -78,23 +74,20 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, bool isTestNet) :
pixPaint.setFont(QFont(font, 10*fontFactor));
pixPaint.drawText(pixmap.width()-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText);
- // draw testnet string if testnet is on
- if(isTestNet) {
+ // draw additional text if special network
+ if(!titleAddText.isEmpty()) {
QFont boldFont = QFont(font, 10*fontFactor);
boldFont.setWeight(QFont::Bold);
pixPaint.setFont(boldFont);
fm = pixPaint.fontMetrics();
- int testnetAddTextWidth = fm.width(testnetAddText);
- pixPaint.drawText(pixmap.width()-testnetAddTextWidth-10,15,testnetAddText);
+ int titleAddTextWidth = fm.width(titleAddText);
+ pixPaint.drawText(pixmap.width()-titleAddTextWidth-10,15,titleAddText);
}
pixPaint.end();
// Set window title
- if(isTestNet)
- setWindowTitle(titleText + " " + testnetAddText);
- else
- setWindowTitle(titleText);
+ setWindowTitle(titleText + " " + titleAddText);
// Resize window and move to center of desktop, disallow resizing
QRect r(QPoint(), pixmap.size());
@@ -177,5 +170,6 @@ void SplashScreen::paintEvent(QPaintEvent *event)
void SplashScreen::closeEvent(QCloseEvent *event)
{
+ StartShutdown(); // allows an "emergency" shutdown during startup
event->ignore();
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 89c21e6457..128edadbee 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -7,6 +7,8 @@
#include <QSplashScreen>
+class NetworkStyle;
+
/** Class for the splashscreen with information of the running client.
*
* @note this is intentionally not a QSplashScreen. Bitcoin Core initialization
@@ -18,7 +20,7 @@ class SplashScreen : public QWidget
Q_OBJECT
public:
- explicit SplashScreen(Qt::WindowFlags f, bool isTestNet);
+ explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle);
~SplashScreen();
protected:
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index afb343f349..5278c8673a 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -32,7 +32,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
QList<TransactionRecord> parts;
int64_t nTime = wtx.GetTxTime();
- CAmount nCredit = wtx.GetCredit(true);
+ CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
CAmount nNet = nCredit - nDebit;
uint256 hash = wtx.GetHash();
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index b8701a23a6..b4733d369e 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -605,7 +605,8 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
- vCoins.push_back(out);
+ if (outpoint.n < out.tx->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
+ vCoins.push_back(out);
}
BOOST_FOREACH(const COutput& out, vCoins)
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 4b3beae20c..5beac0512a 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -381,7 +381,7 @@ Value gettxout(const Array& params, bool fHelp)
CCoins coins;
if (fMempool) {
LOCK(mempool.cs);
- CCoinsViewMemPool view(*pcoinsTip, mempool);
+ CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(hash, coins))
return Value::null;
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
@@ -445,6 +445,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
+ " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
@@ -458,6 +459,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
Object obj;
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
+ obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 1ac7024550..9da0a7d091 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -114,8 +114,6 @@ Value importprivkey(const Array& params, bool fHelp)
CPubKey pubkey = key.GetPubKey();
CKeyID vchAddress = pubkey.GetID();
{
- LOCK2(cs_main, pwalletMain->cs_wallet);
-
pwalletMain->MarkDirty();
pwalletMain->SetAddressBook(vchAddress, strLabel, "receive");
@@ -181,7 +179,8 @@ Value importaddress(const Array& params, bool fHelp)
fRescan = params[2].get_bool();
{
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
// add to address book or update label
if (address.IsValid())
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index e794bf69e0..c767835a27 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -239,7 +239,7 @@ Value getmininginfo(const Array& params, bool fHelp)
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
+ obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
#ifdef ENABLE_WALLET
obj.push_back(Pair("generate", getgenerate(params, false)));
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index dd45eefd58..8be14b567c 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -87,7 +87,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
+ obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index bc19d1372a..12dcd5b540 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -97,7 +97,12 @@ Value getpeerinfo(const Array& params, bool fHelp)
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\n"
- " \"syncnode\": true|false (boolean) if sync node\n"
+ " \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
+ " \"synced_blocks\": n, (numeric) The last block we have in common with this peer\n"
+ " \"inflight\": [\n"
+ " n, (numeric) The heights of blocks we're currently asking from this peer\n"
+ " ...\n"
+ " ]\n"
" }\n"
" ,...\n"
"]\n"
@@ -137,9 +142,14 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
- obj.push_back(Pair("syncheight", statestats.nSyncHeight));
+ obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
+ obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
+ Array heights;
+ BOOST_FOREACH(int height, statestats.vHeightInFlight) {
+ heights.push_back(height);
+ }
+ obj.push_back(Pair("inflight", heights));
}
- obj.push_back(Pair("syncnode", stats.fSyncNode));
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
ret.push_back(obj);
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index e50a278bc8..78372da685 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -110,6 +110,9 @@ Value getrawtransaction(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
+ "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
+ "or there is an unspent output in the utxo for this transaction. To make it always work,\n"
+ "you need to maintain a transaction index, using the -txindex command line option.\n"
"\nReturn the raw transaction data.\n"
"\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"If verbose is non-zero, returns an Object with information about 'txid'.\n"
@@ -202,7 +205,7 @@ Value listunspent(const Array& params, bool fHelp)
"Results are an array of Objects, each of which has:\n"
"{txid, vout, scriptPubKey, amount, confirmations}\n"
"\nArguments:\n"
- "1. minconf (numeric, optional, default=1) The minimum confirmationsi to filter\n"
+ "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
"3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
" [\n"
@@ -557,11 +560,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
- CCoinsViewCache view(viewDummy);
+ CCoinsViewCache view(&viewDummy);
{
LOCK(mempool.cs);
CCoinsViewCache &viewChain = *pcoinsTip;
- CCoinsViewMemPool viewMempool(viewChain, mempool);
+ CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
@@ -612,21 +615,19 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
- CCoins coins;
- if (view.GetCoins(txid, coins)) {
- if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
+ {
+ CCoinsModifier coins = view.ModifyCoins(txid);
+ if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
- err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
+ err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
- // what todo if txid is known, but the actual output isn't?
+ if ((unsigned int)nOut >= coins->vout.size())
+ coins->vout.resize(nOut+1);
+ coins->vout[nOut].scriptPubKey = scriptPubKey;
+ coins->vout[nOut].nValue = 0; // we don't know the actual output value
}
- if ((unsigned int)nOut >= coins.vout.size())
- coins.vout.resize(nOut+1);
- coins.vout[nOut].scriptPubKey = scriptPubKey;
- coins.vout[nOut].nValue = 0; // we don't know the actual output value
- view.SetCoins(txid, coins);
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 1a41344da5..9668c78831 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -581,7 +581,7 @@ void StartRPCThreads()
strWhatAmI,
GetConfigFile().string(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
- "", CClientUIInterface::MSG_ERROR);
+ "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
StartShutdown();
return;
}
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index d7c0c0ef5c..d11455e389 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -1539,7 +1539,7 @@ Value gettransaction(const Array& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
- CAmount nCredit = wtx.GetCredit(filter != 0);
+ CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
CAmount nNet = nCredit - nDebit;
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 56140f19db..ae66217b7c 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -52,10 +52,7 @@ static inline void popstack(vector<valtype>& stack)
stack.pop_back();
}
-bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
- if (!(flags & SCRIPT_VERIFY_STRICTENC))
- return true;
-
+bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
if (vchPubKey.size() < 33)
return error("Non-canonical public key: too short");
if (vchPubKey[0] == 0x04) {
@@ -70,10 +67,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
return true;
}
-bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
- if (!(flags & SCRIPT_VERIFY_STRICTENC))
- return true;
-
+bool static IsDERSignature(const valtype &vchSig) {
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
@@ -83,9 +77,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
return error("Non-canonical signature: too short");
if (vchSig.size() > 73)
return error("Non-canonical signature: too long");
- unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
- if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
- return error("Non-canonical signature: unknown hashtype byte");
if (vchSig[0] != 0x30)
return error("Non-canonical signature: wrong type");
if (vchSig[1] != vchSig.size()-3)
@@ -117,17 +108,54 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
return error("Non-canonical signature: S value excessively padded");
- if (flags & SCRIPT_VERIFY_LOW_S) {
- // If the S value is above the order of the curve divided by two, its
- // complement modulo the order could have been used instead, which is
- // one byte shorter when encoded correctly.
- if (!CKey::CheckSignatureElement(S, nLenS, true))
- return error("Non-canonical signature: S value is unnecessarily high");
+ return true;
+}
+
+bool static IsLowDERSignature(const valtype &vchSig) {
+ if (!IsDERSignature(vchSig)) {
+ return false;
}
+ unsigned int nLenR = vchSig[3];
+ unsigned int nLenS = vchSig[5+nLenR];
+ const unsigned char *S = &vchSig[6+nLenR];
+ // If the S value is above the order of the curve divided by two, its
+ // complement modulo the order could have been used instead, which is
+ // one byte shorter when encoded correctly.
+ if (!CKey::CheckSignatureElement(S, nLenS, true))
+ return error("Non-canonical signature: S value is unnecessarily high");
return true;
}
+bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
+ if (vchSig.size() == 0) {
+ return false;
+ }
+ unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
+ if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
+ return error("Non-canonical signature: unknown hashtype byte");
+
+ return true;
+}
+
+bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) {
+ if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
+ return false;
+ } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) {
+ return false;
+ } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
+ return false;
+ }
+ return true;
+}
+
+bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
+ if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
+ return false;
+ }
+ return true;
+}
+
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker)
{
CScript::const_iterator pc = script.begin();
@@ -670,8 +698,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));
- bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
- checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ if (!CheckSignatureEncoding(vchSig, flags)) {
+ return false;
+ }
+
+ bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
popstack(stack);
popstack(stack);
@@ -730,9 +761,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype& vchSig = stacktop(-isig);
valtype& vchPubKey = stacktop(-ikey);
+ if (!CheckSignatureEncoding(vchSig, flags)) {
+ return false;
+ }
+
// Check signature
- bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
- checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ bool fOk = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
if (fOk) {
isig++;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index f5363a7535..de5ce2ced1 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -10,10 +10,10 @@
#include <stdint.h>
#include <string>
-class uint256;
class CPubKey;
class CScript;
class CTransaction;
+class uint256;
/** Signature hash types/flags */
enum
@@ -28,14 +28,25 @@ enum
enum
{
SCRIPT_VERIFY_NONE = 0,
- SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
- SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
- SCRIPT_VERIFY_NULLDUMMY = (1U << 3), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
-};
-bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
-bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
+ // Evaluate P2SH subscripts (softfork safe, BIP16).
+ SCRIPT_VERIFY_P2SH = (1U << 0),
+
+ // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
+ // Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be
+ // skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT).
+ SCRIPT_VERIFY_STRICTENC = (1U << 1),
+
+ // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
+ SCRIPT_VERIFY_DERSIG = (1U << 2),
+
+ // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
+ // (softfork safe, BIP62 rule 5).
+ SCRIPT_VERIFY_LOW_S = (1U << 3),
+
+ // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
+ SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
+};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 981563b7ae..ab366898d8 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "sigcache.h"
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 9537efbd11..46b8f4d335 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef H_BITCOIN_SCRIPT_SIGCACHE
@@ -23,4 +23,4 @@ public:
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
-#endif
+#endif // H_BITCOIN_SCRIPT_SIGCACHE
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 407baf621d..53ae254d59 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -203,7 +203,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
if (whichType == TX_PUBKEY)
{
- addressRet = CPubKey(vSolutions[0]).GetID();
+ CPubKey pubKey(vSolutions[0]);
+ if (!pubKey.IsValid())
+ return false;
+
+ addressRet = pubKey.GetID();
return true;
}
else if (whichType == TX_PUBKEYHASH)
@@ -237,9 +241,16 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
nRequiredRet = vSolutions.front()[0];
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
{
- CTxDestination address = CPubKey(vSolutions[i]).GetID();
+ CPubKey pubKey(vSolutions[i]);
+ if (!pubKey.IsValid())
+ continue;
+
+ CTxDestination address = pubKey.GetID();
addressRet.push_back(address);
}
+
+ if (addressRet.empty())
+ return false;
}
else
{
diff --git a/src/serialize.h b/src/serialize.h
index ff11edc06c..b9d5f95463 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -20,9 +20,6 @@
#include <utility>
#include <vector>
-#include <boost/tuple/tuple.hpp>
-#include <boost/type_traits/is_fundamental.hpp>
-
class CAutoFile;
class CDataStream;
class CScript;
@@ -432,14 +429,15 @@ template<typename Stream, typename C> void Serialize(Stream& os, const std::basi
template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0);
// vector
-template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
-template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+// vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
+template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
+template<typename T, typename A, typename V> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&);
template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion);
-template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
-template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
+template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&);
template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion);
-template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
-template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
+template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&);
template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion);
// others derived from vector
@@ -452,16 +450,6 @@ template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K
template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion);
template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion);
-// 3 tuple
-template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
-template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
-template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
-
-// 4 tuple
-template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
-template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
-template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
-
// map
template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion);
@@ -536,13 +524,13 @@ void Unserialize(Stream& is, std::basic_string<C>& str, int, int)
// vector
//
template<typename T, typename A>
-unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
{
return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
}
-template<typename T, typename A>
-unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+template<typename T, typename A, typename V>
+unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&)
{
unsigned int nSize = GetSizeOfCompactSize(v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
@@ -553,20 +541,20 @@ unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nV
template<typename T, typename A>
inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion)
{
- return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>());
+ return GetSerializeSize_impl(v, nType, nVersion, T());
}
template<typename Stream, typename T, typename A>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
os.write((char*)&v[0], v.size() * sizeof(T));
}
-template<typename Stream, typename T, typename A>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+template<typename Stream, typename T, typename A, typename V>
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&)
{
WriteCompactSize(os, v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
@@ -576,12 +564,12 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVers
template<typename Stream, typename T, typename A>
inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion)
{
- Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>());
+ Serialize_impl(os, v, nType, nVersion, T());
}
template<typename Stream, typename T, typename A>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
{
// Limit size per read so bogus size value won't cause out of memory
v.clear();
@@ -596,8 +584,8 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
}
}
-template<typename Stream, typename T, typename A>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+template<typename Stream, typename T, typename A, typename V>
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&)
{
v.clear();
unsigned int nSize = ReadCompactSize(is);
@@ -617,7 +605,7 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
template<typename Stream, typename T, typename A>
inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion)
{
- Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>());
+ Unserialize_impl(is, v, nType, nVersion, T());
}
@@ -670,71 +658,6 @@ void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
//
-// 3 tuple
-//
-template<typename T0, typename T1, typename T2>
-unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
-{
- unsigned int nSize = 0;
- nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
- nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
- nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
- return nSize;
-}
-
-template<typename Stream, typename T0, typename T1, typename T2>
-void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
-{
- Serialize(os, boost::get<0>(item), nType, nVersion);
- Serialize(os, boost::get<1>(item), nType, nVersion);
- Serialize(os, boost::get<2>(item), nType, nVersion);
-}
-
-template<typename Stream, typename T0, typename T1, typename T2>
-void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
-{
- Unserialize(is, boost::get<0>(item), nType, nVersion);
- Unserialize(is, boost::get<1>(item), nType, nVersion);
- Unserialize(is, boost::get<2>(item), nType, nVersion);
-}
-
-
-
-//
-// 4 tuple
-//
-template<typename T0, typename T1, typename T2, typename T3>
-unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
-{
- unsigned int nSize = 0;
- nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
- nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
- nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
- nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion);
- return nSize;
-}
-
-template<typename Stream, typename T0, typename T1, typename T2, typename T3>
-void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
-{
- Serialize(os, boost::get<0>(item), nType, nVersion);
- Serialize(os, boost::get<1>(item), nType, nVersion);
- Serialize(os, boost::get<2>(item), nType, nVersion);
- Serialize(os, boost::get<3>(item), nType, nVersion);
-}
-
-template<typename Stream, typename T0, typename T1, typename T2, typename T3>
-void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
-{
- Unserialize(is, boost::get<0>(item), nType, nVersion);
- Unserialize(is, boost::get<1>(item), nType, nVersion);
- Unserialize(is, boost::get<2>(item), nType, nVersion);
- Unserialize(is, boost::get<3>(item), nType, nVersion);
-}
-
-
-
-//
// map
//
template<typename K, typename T, typename Pred, typename A>
@@ -1193,14 +1116,21 @@ public:
}
}
+ /** Get wrapped FILE* with transfer of ownership.
+ * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
+ * of this function to clean up the returned FILE*.
+ */
FILE* release() { FILE* ret = file; file = NULL; return ret; }
- operator FILE*() { return file; }
- FILE* operator->() { return file; }
- FILE& operator*() { return *file; }
- FILE** operator&() { return &file; }
- FILE* operator=(FILE* pnew) { return file = pnew; }
- bool operator!() { return (file == NULL); }
+ /** Get wrapped FILE* without transfer of ownership.
+ * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
+ * CAutoFile outlives use of the passed pointer.
+ */
+ FILE* Get() const { return file; }
+
+ /** Return true if the wrapped FILE* is NULL, false otherwise.
+ */
+ bool IsNull() const { return (file == NULL); }
//
// Stream subset
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 7bec12b665..f9746fdaa5 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -106,51 +106,6 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
BOOST_CHECK(!CNode::IsBanned(addr));
}
-static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
-{
- if (time1 > time2)
- return CheckNBits(nbits2, time2, nbits1, time1);
- int64_t deltaTime = time2-time1;
-
- return CheckMinWork(nbits2, nbits1, deltaTime);
-}
-
-BOOST_AUTO_TEST_CASE(DoS_checknbits)
-{
- using namespace boost::assign; // for 'map_list_of()'
-
- // Timestamps,nBits from the bitcoin block chain.
- // These are the block-chain checkpoint blocks
- typedef std::map<int64_t, unsigned int> BlockData;
- BlockData chainData =
- map_list_of(1239852051,486604799)(1262749024,486594666)
- (1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
- (1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
- (1313172719,436789733);
-
- // Make sure CheckNBits considers every combination of block-chain-lock-in-points
- // "sane":
- BOOST_FOREACH(const BlockData::value_type& i, chainData)
- {
- BOOST_FOREACH(const BlockData::value_type& j, chainData)
- {
- BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
- }
- }
-
- // Test a couple of insane combinations:
- BlockData::value_type firstcheck = *(chainData.begin());
- BlockData::value_type lastcheck = *(chainData.rbegin());
-
- // First checkpoint difficulty at or a while after the last checkpoint time should fail when
- // compared to last checkpoint
- BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
- BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
-
- // ... but OK if enough time passed for difficulty to adjust downward:
- BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
-}
-
CTransaction RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 2cdafa4bdd..99b21a23a0 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -14,6 +14,7 @@
#include <vector>
#include <boost/test/unit_test.hpp>
+#include <boost/tuple/tuple.hpp>
using namespace std;
using namespace boost::tuples;
diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp
deleted file mode 100644
index a17099de72..0000000000
--- a/src/test/canonical_tests.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2012-2013 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-//
-// Unit tests for canonical signatures
-//
-
-#include "data/sig_noncanonical.json.h"
-#include "data/sig_canonical.json.h"
-#include "key.h"
-#include "random.h"
-#include "script/interpreter.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include <boost/foreach.hpp>
-#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_writer_template.h"
-#include <openssl/ecdsa.h>
-
-using namespace std;
-using namespace json_spirit;
-
-// In script_tests.cpp
-extern Array read_json(const std::string& jsondata);
-
-BOOST_AUTO_TEST_SUITE(canonical_tests)
-
-// OpenSSL-based test for canonical signature (without test for hashtype byte)
-bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig)
-{
- if (vchSig.size() == 0)
- return false;
- const unsigned char *input = &vchSig[0];
- ECDSA_SIG *psig = NULL;
- d2i_ECDSA_SIG(&psig, &input, vchSig.size());
- if (psig == NULL)
- return false;
- unsigned char buf[256];
- unsigned char *pbuf = buf;
- unsigned int nLen = i2d_ECDSA_SIG(psig, NULL);
- if (nLen != vchSig.size()) {
- ECDSA_SIG_free(psig);
- return false;
- }
- nLen = i2d_ECDSA_SIG(psig, &pbuf);
- ECDSA_SIG_free(psig);
- return (memcmp(&vchSig[0], &buf[0], nLen) == 0);
-}
-
-// OpenSSL-based test for canonical signature
-bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) {
- if (vchSignature.size() < 1)
- return false;
- if (vchSignature.size() > 127)
- return false;
- if (vchSignature[vchSignature.size() - 1] & 0x7C)
- return false;
-
- std::vector<unsigned char> vchSig(vchSignature);
- vchSig.pop_back();
- if (!IsCanonicalSignature_OpenSSL_inner(vchSig))
- return false;
- return true;
-}
-
-BOOST_AUTO_TEST_CASE(script_canon)
-{
- Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical)));
-
- BOOST_FOREACH(Value &tv, tests) {
- string test = tv.get_str();
- if (IsHex(test)) {
- std::vector<unsigned char> sig = ParseHex(test);
- BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
- BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE(script_noncanon)
-{
- Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical)));
-
- BOOST_FOREACH(Value &tv, tests) {
- string test = tv.get_str();
- if (IsHex(test)) {
- std::vector<unsigned char> sig = ParseHex(test);
- BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
- BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE(script_signstrict)
-{
- for (int i=0; i<100; i++) {
- CKey key;
- key.MakeNewKey(i & 1);
- std::vector<unsigned char> sig;
- uint256 hash = GetRandHash();
-
- BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature.
- BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it.
- sig.push_back(0x01); // Append a sighash type.
-
- BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S));
- BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig));
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 67d40a45c7..9151fdc0c8 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -36,7 +36,7 @@ bool read_block(const std::string& filename, CBlock& block)
fseek(fp, 8, SEEK_SET); // skip msgheader/size
CAutoFile filein(fp, SER_DISK, CLIENT_VERSION);
- if (!filein) return false;
+ if (filein.IsNull()) return false;
filein >> block;
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
new file mode 100644
index 0000000000..3ecd301bc7
--- /dev/null
+++ b/src/test/coins_tests.cpp
@@ -0,0 +1,178 @@
+// Copyright (c) 2014 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 "coins.h"
+#include "random.h"
+#include "uint256.h"
+
+#include <vector>
+#include <map>
+
+#include <boost/test/unit_test.hpp>
+
+namespace
+{
+class CCoinsViewTest : public CCoinsView
+{
+ uint256 hashBestBlock_;
+ std::map<uint256, CCoins> map_;
+
+public:
+ bool GetCoins(const uint256& txid, CCoins& coins) const
+ {
+ std::map<uint256, CCoins>::const_iterator it = map_.find(txid);
+ if (it == map_.end()) {
+ return false;
+ }
+ coins = it->second;
+ if (coins.IsPruned() && insecure_rand() % 2 == 0) {
+ // Randomly return false in case of an empty entry.
+ return false;
+ }
+ return true;
+ }
+
+ bool HaveCoins(const uint256& txid) const
+ {
+ CCoins coins;
+ return GetCoins(txid, coins);
+ }
+
+ uint256 GetBestBlock() const { return hashBestBlock_; }
+
+ bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
+ {
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
+ map_[it->first] = it->second.coins;
+ if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) {
+ // Randomly delete empty entries on write.
+ map_.erase(it->first);
+ }
+ mapCoins.erase(it++);
+ }
+ mapCoins.clear();
+ hashBestBlock_ = hashBlock;
+ return true;
+ }
+
+ bool GetStats(CCoinsStats& stats) const { return false; }
+};
+}
+
+BOOST_AUTO_TEST_SUITE(coins_tests)
+
+static const unsigned int NUM_SIMULATION_ITERATIONS = 40000;
+
+// This is a large randomized insert/remove simulation test on a variable-size
+// stack of caches on top of CCoinsViewTest.
+//
+// It will randomly create/update/delete CCoins entries to a tip of caches, with
+// txids picked from a limited list of random 256-bit hashes. Occasionally, a
+// new tip is added to the stack of caches, or the tip is flushed and removed.
+//
+// During the process, booleans are kept to make sure that the randomized
+// operation hits all branches.
+BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
+{
+ // Various coverage trackers.
+ bool removed_all_caches = false;
+ bool reached_4_caches = false;
+ bool added_an_entry = false;
+ bool removed_an_entry = false;
+ bool updated_an_entry = false;
+ bool found_an_entry = false;
+ bool missed_an_entry = false;
+
+ // A simple map to track what we expect the cache stack to represent.
+ std::map<uint256, CCoins> result;
+
+ // The cache stack.
+ CCoinsViewTest base; // A CCoinsViewTest at the bottom.
+ std::vector<CCoinsViewCache*> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(new CCoinsViewCache(&base)); // Start with one cache.
+
+ // Use a limited set of random transaction ids, so we do test overwriting entries.
+ std::vector<uint256> txids;
+ txids.resize(NUM_SIMULATION_ITERATIONS / 8);
+ for (unsigned int i = 0; i < txids.size(); i++) {
+ txids[i] = GetRandHash();
+ }
+
+ for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
+ // Do a random modification.
+ {
+ uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration.
+ CCoins& coins = result[txid];
+ CCoinsModifier entry = stack.back()->ModifyCoins(txid);
+ BOOST_CHECK(coins == *entry);
+ if (insecure_rand() % 5 == 0 || coins.IsPruned()) {
+ if (coins.IsPruned()) {
+ added_an_entry = true;
+ } else {
+ updated_an_entry = true;
+ }
+ coins.nVersion = insecure_rand();
+ coins.vout.resize(1);
+ coins.vout[0].nValue = insecure_rand();
+ *entry = coins;
+ } else {
+ coins.Clear();
+ entry->Clear();
+ removed_an_entry = true;
+ }
+ }
+
+ // Once every 1000 iterations and at the end, verify the full cache.
+ if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
+ for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) {
+ const CCoins* coins = stack.back()->AccessCoins(it->first);
+ if (coins) {
+ BOOST_CHECK(*coins == it->second);
+ found_an_entry = true;
+ } else {
+ BOOST_CHECK(it->second.IsPruned());
+ missed_an_entry = true;
+ }
+ }
+ }
+
+ if (insecure_rand() % 100 == 0) {
+ // Every 100 iterations, change the cache stack.
+ if (stack.size() > 0 && insecure_rand() % 2 == 0) {
+ stack.back()->Flush();
+ delete stack.back();
+ stack.pop_back();
+ }
+ if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
+ CCoinsView* tip = &base;
+ if (stack.size() > 0) {
+ tip = stack.back();
+ } else {
+ removed_all_caches = true;
+ }
+ stack.push_back(new CCoinsViewCache(tip));
+ if (stack.size() == 4) {
+ reached_4_caches = true;
+ }
+ }
+ }
+ }
+
+ // Clean up the stack.
+ while (stack.size() > 0) {
+ delete stack.back();
+ stack.pop_back();
+ }
+
+ // Verify coverage.
+ BOOST_CHECK(removed_all_caches);
+ BOOST_CHECK(reached_4_caches);
+ BOOST_CHECK(added_an_entry);
+ BOOST_CHECK(removed_an_entry);
+ BOOST_CHECK(updated_an_entry);
+ BOOST_CHECK(found_an_entry);
+ BOOST_CHECK(missed_an_entry);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 35a6794b01..b6447cb221 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,19 +384,126 @@ nSequences are max.
["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
-["0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK, bad sig"],
-["0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", "P2PKH, bad pubkey"],
-["0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay marked with normal hashtype"],
-["0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK), bad redeemscript"],
-["0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", "P2SH(P2PKH), bad sig"],
-["0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3, 2 sigs"],
-["0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3), 1 sig"],
-["0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much R padding"],
-["0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much S padding"],
-["0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too little R padding"],
-["0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S,STRICTENC", "P2PK with high S"],
-["0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", "3-of-3 with nonzero dummy"],
+[
+ "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
+ "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK, bad sig"
+],
+[
+ "0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
+ "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",
+ "",
+ "P2PKH, bad pubkey"
+],
+[
+ "0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK anyonecanpay marked with normal hashtype"
+],
+[
+ "0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
+ "P2SH",
+ "P2SH(P2PK), bad redeemscript"
+],
+[
+ "0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
+ "P2SH",
+ "P2SH(P2PKH), bad sig"
+],
+[
+ "0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3, 2 sigs"
+],
+[
+ "0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
+ "P2SH",
+ "P2SH(2-of-3), 1 sig"
+],
+[
+ "0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too much R padding"
+],
+[
+ "0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too much S padding"
+],
+[
+ "0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "STRICTENC",
+ "P2PK with too little R padding"
+],
+[
+ "0x47 0x30440220001d0f82c127470cb38316c96b1719b33382353687a1146a776dee8259606905022062cd1fc8eacef819d68f0f41cc9ae9fdc2e29b70c3c7ad2c6c18f39b4e35c42701",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "DERSIG",
+ "P2PK NOT with bad sig with too much R padding"
+],
+[
+ "0x47 0x30440220005d727e2a82d6e8a98a6da6fbc281325644d1a40455e386fdb17883a8e6bc4d02202d15cca42ce136047a980d288e60c679d7e84cce18c3ceffb6bc81b9e9ba517801",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "",
+ "P2PK NOT with too much R padding but no DERSIG"
+],
+[
+ "0x47 0x30440220006e8bc4f82032b12bd594847c16d8b2986de734aa3b0528bd89d664d41e6d1c02200cfd582694891bcfa2e630e899bda257486eba00a007222fae71144dba07dc2901",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "DERSIG",
+ "P2PK NOT with too much R padding"
+],
+[
+ "0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "LOW_S,STRICTENC",
+ "P2PK with high S"
+],
+[
+ "0x47 0x304402203aab50cd7c30cc1e1475dee615b295bcee6ccf8aa8a7f6cda6b696c70d79cbb40220558e43fe7596c31146e2d077698d5a9c38351d8ba567549a2ae43ca97231c39501",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "STRICTENC",
+ "P2PK with hybrid pubkey"
+],
+[
+ "0x47 0x304402205745e8f846110c185ee1185c01843a108588b81463d2c34d4a3f2445529f12fe02206ee6a2657bbc4e2bb74bfc44c3a5c4f410ed6356ca68982465de6ca807c807c201",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "",
+ "P2PK NOT with hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x304402201f82b99a813c9c48c8dee8d2c43b8f637b72353fe9bdcc084537bc17e2ab770402200c43b96a5f7e115f0114eabda32e068145965cb6c7b5ef64833bb4fcf9fc1b3b05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "STRICTENC",
+ "P2PK with undefined hashtype"
+],
+[
+ "0x47 0x30440220166848cd5b82a32b5944d90de3c35249354b43773c2ece1844ee8d1103e2f6c602203b6b046da4243c77adef80ada9201b27bbfdf7f9d5428f40434b060432afd62005",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with invalid sig and undefined hashtype"
+],
+[
+ "0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "NULLDUMMY",
+ "3-of-3 with nonzero dummy"
+],
+[
+ "0x01 0x01 0x47 0x304402201847fc3b8f7597768e7f543c58da1fca6e8e35eb28979431e6b637572ce6eaa4022048dd58608e040841d0bf52a70cfb70e1a9c8d2826fad068f4e9d2bf5c87766a501 0x47 0x30440220711311a72516affed73363763983d05c3d6a06a2eadf5d76b90b4354162ba94302204841a69e5955a7dc8e4ab3105fd0c86040c1dac6016297a51ddbf5079c28756801 0x47 0x30440220267e331a378191e7282fd10d61c97bf74bc97c233c5833d677936424ac08dee502201eee83d88b91988e1c4d9b979df2404aa190e0987a8ca09c4e5cd61da1d48ecc01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
+ "NULLDUMMY",
+ "3-of-3 NOT with invalid sig with nonzero dummy"
+],
["The End"]
-
]
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 653f60d982..88bec7238c 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -529,19 +529,126 @@ nSequences are max.
["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
-["0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK"],
-["0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", "", "P2PKH"],
-["0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay"],
-["0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK)"],
-["0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "", "P2SH(P2PKH), bad sig but no VERIFY_P2SH"],
-["0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3"],
-["0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3)"],
-["0x47 0x304402200001cae94b795baaafb05db38cf24cd75560cab2c36c91e29fac7d0fd2a723a3022058e2e56e568ce7c4b2b106210d114e1faa079407a6ed4154f230667c7d3583bc01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much R padding but no STRICTENC"],
-["0x48 0x304502206d01de7c2a40ac2bb1231ed97f3890a1782f421d4c28b97166deff317990288f0221005e720213b089355be2cf785d81a82c59307d30e1624f450ed9ca1ebbc11cca6d01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much S padding but no STRICTENC"],
-["0x47 0x30440220f3d8889602147d60d26c1d3b21b8db183eac02bf6d2fec1424c0ef377ca6fd7b02202bae8bfe39d00a432d4538a592e338b0ffc44c17d4b7056043d55063cf91f5ef01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too little R padding but no STRICTENC"],
-["0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "STRICTENC", "P2PK with high S but no LOW_S"],
-["0x48 0x304502205c3e81aaf2aad0673f349035b180eba783eba7797af91c979920dea6b17a16d6022100d1d46825c68da1b325f320a3503dad27bb818227f64a38d153554bfd360c0e5301", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S", "P2PK with high S but no STRICTENC"],
-["0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3 with nonzero dummy but no NULLDUMMY"],
+[
+ "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
+ "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK"
+],
+[
+ "0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",
+ "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG",
+ "",
+ "P2PKH"
+],
+[
+ "0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK anyonecanpay"
+],
+[
+ "0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",
+ "P2SH",
+ "P2SH(P2PK)"
+],
+[
+ "0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
+ "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
+ "",
+ "P2SH(P2PKH), bad sig but no VERIFY_P2SH"
+],
+[
+ "0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3"
+],
+[
+ "0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",
+ "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",
+ "P2SH",
+ "P2SH(2-of-3)"
+],
+[
+ "0x47 0x30440220001fff8863c84c0efc8eea5bffb7f388313f966f23a00ad3c0acc30ff5339684022016e6d78f51a3a1c362745931ca40b24f71cba2903dbfe5a6d392a9189127d83701",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too much R padding but no DERSIG"
+],
+[
+ "0x48 0x304502202323d56f293842b544cacedd06baafb999196dfa1c2975314848c158ac606655022100514bd98186b8a3a1cc87f4aff76aed797781389f13f50d87bf95b2df6e488fcc01",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too much S padding but no DERSIG"
+],
+[
+ "0x47 0x30440220d31c24bb6c08a496e7698a08fd41975115d7b55bfaa31cb2d573e09481e59a6702206a691239996434076b78a4e1cf46fc8e993b468a9c77fb1832186aa8040a61a201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "P2PK with too little R padding but no DERSIG"
+],
+[
+ "0x47 0x30440220007c2cc7aef1801c2937447703c87ef2a3744209ad98da2abadd4ba8bb2e3ea00220503a275582c9f9e9ff30260c81b7f64b8b696f22105605cc8241fb76a797316201",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",
+ "",
+ "P2PK NOT with bad sig with too much R padding but no DERSIG"
+],
+[
+ "0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "STRICTENC",
+ "P2PK with high S but no LOW_S"
+],
+[
+ "0x47 0x304402202163bc732c21b7de0251297d3c6c2ece182782e85fc5e19d6036f1130a79051e022033827811634924ebba68767537d78dd7bd9109ae2a89a60587927abdc25eb06401",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
+ "",
+ "P2PK with hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x3044022078033e4227aa05ded69d8da579966578e230d8a7fb44d5f1a0620c3853c24f78022006a2e3f4d872ac8dfdc529110aa37301d65a76255a4b6cce2992adacd4d2c4e201",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with hybrid pubkey"
+],
+[
+ "0x47 0x3044022078d6c447887e88dcbe1bc5b613645280df6f4e5935648bc226e9d91da71b3216022047d6b7ef0949b228fc1b359afb8d50500268711354298217b983c26970790c7601",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "",
+ "P2PK NOT with invalid hybrid pubkey but no STRICTENC"
+],
+[
+ "0x47 0x304402207592427de20e315d644839754f2a5cca5b978b983a15e6da82109ede01722baa022032ceaf78590faa3f7743821e1b47b897ed1a57f6ee1c8a7519d23774d8de3c4401",
+ "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",
+ "STRICTENC",
+ "P2PK NOT with invalid hybrid pubkey"
+],
+[
+ "0x47 0x304402204649e9517ef0377a8f8270bd423053fd98ddff62d74ea553e9579558abbb75e4022044a2b2344469c12e35ed898987711272b634733dd0f5e051288eceb04bd4669e05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
+ "",
+ "P2PK with undefined hashtype but no STRICTENC"
+],
+[
+ "0x47 0x304402207f1cf1866a2df0bb4b8d84d0ade72aa3abb6aaab0639d608b23d9e10ead0c48202203caa97f22c3439443eea4b89f7f6729854df0f567a8184d6ecc6e8b6c68c3e9d05",
+ "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",
+ "",
+ "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
+],
+[
+ "0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+ "",
+ "3-of-3 with nonzero dummy but no NULLDUMMY"
+],
+[
+ "0x01 0x01 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
+ "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
+ "",
+ "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
+],
["The End"]
]
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 203c20731a..b32f3774fe 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
CKey key1C = bsecret1C.GetKey();
BOOST_CHECK(key1C.IsCompressed() == true);
CKey key2C = bsecret2C.GetKey();
- BOOST_CHECK(key1C.IsCompressed() == true);
+ BOOST_CHECK(key2C.IsCompressed() == true);
CPubKey pubkey1 = key1. GetPubKey();
CPubKey pubkey2 = key2. GetPubKey();
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 6c32a263a9..f8361a0dc8 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
LOCK(cs_main);
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore;
CKey key[6];
vector<CPubKey> keys;
@@ -312,8 +312,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txFrom.vout[6].scriptPubKey = GetScriptForDestination(twentySigops.GetID());
txFrom.vout[6].nValue = 6000;
-
- coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
+ coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0);
CMutableTransaction txTo;
txTo.vout.resize(1);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 6ed3e03f53..a4b0212494 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -34,6 +34,9 @@ using namespace std;
using namespace json_spirit;
using namespace boost::algorithm;
+// Uncomment if you want to output updated JSON tests.
+// #define UPDATE_JSON_TESTS
+
static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags);
@@ -239,14 +242,15 @@ public:
return *this;
}
- operator std::string()
+ Array GetJSON()
{
DoPush();
- return "[\"" +
- FormatScript(spendTx.vin[0].scriptSig) + "\", \"" +
- FormatScript(creditTx.vout[0].scriptPubKey) + "\", \"" +
- FormatScriptFlags(flags) + "\", \"" +
- comment + "\"],\n";
+ Array array;
+ array.push_back(FormatScript(spendTx.vin[0].scriptSig));
+ array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
+ array.push_back(FormatScriptFlags(flags));
+ array.push_back(comment);
+ return array;
}
std::string GetComment()
@@ -316,40 +320,87 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key1).Num(0).PushRedeem());
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much R padding but no STRICTENC", 0
+ "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() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much R padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much S padding but no STRICTENC", 0
+ "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() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too much S padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too little R padding but no STRICTENC", 0
+ "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() << keys.pubkey1C << OP_CHECKSIG,
- "P2PK with too little R padding", SCRIPT_VERIFY_STRICTENC
+ "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
+ good.push_back(TestBuilder(CScript() << 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() << 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));
+ bad.push_back(TestBuilder(CScript() << 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"));
+ bad.push_back(TestBuilder(CScript() << 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"));
good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S but no LOW_S", SCRIPT_VERIFY_STRICTENC
- ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
- good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S but no STRICTENC", SCRIPT_VERIFY_LOW_S
+ "P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG,
- "P2PK with high S", SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC
+ "P2PK with high S", SCRIPT_VERIFY_LOW_S
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG,
+ "P2PK with hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG,
+ "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0
+ ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
+ good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
+
+ good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG,
+ "P2PK with undefined hashtype but no STRICTENC", 0
+ ).PushSig(keys.key1, 5));
+ bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG,
+ "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key1, 5));
+ good.push_back(TestBuilder(CScript() << 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() << keys.pubkey1 << OP_CHECKSIG << OP_NOT,
+ "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC
+ ).PushSig(keys.key1, 5).DamagePush(10));
+
good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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));
+ good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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));
std::map<std::string, Array> tests_good;
std::map<std::string, Array> tests_bad;
@@ -377,18 +428,30 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- BOOST_CHECK_MESSAGE(tests_good.count(test.GetComment()) > 0, "Missing auto script_valid test: " + test.GetComment());
- BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment());
- strGood += test;
+ if (tests_good.count(test.GetComment()) == 0) {
+#ifndef UPDATE_JSON_TESTS
+ BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
+#endif
+ strGood += write_string(Value(test.GetJSON()), true) + ",\n";
+ } else {
+ BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment());
+ strGood += write_string(Value(tests_good[test.GetComment()]), true) + ",\n";
+ }
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- BOOST_CHECK_MESSAGE(tests_bad.count(test.GetComment()) > 0, "Missing auto script_invalid test: " + test.GetComment());
- BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment());
- strBad += test;
+ if (tests_bad.count(test.GetComment()) == 0) {
+#ifndef UPDATE_JSON_TESTS
+ BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
+#endif
+ strBad += write_string(Value(test.GetJSON()), true) + ",\n";
+ } else {
+ BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment());
+ strBad += write_string(Value(tests_bad[test.GetComment()]), true) + ",\n";
+ }
}
-#if 0
+#ifdef UPDATE_JSON_TESTS
FILE* valid = fopen("script_valid.json.gen", "w");
fputs(strGood.c_str(), valid);
fclose(valid);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 6e5f0e3fac..e50218d8ef 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -41,13 +41,13 @@ struct TestingSetup {
mapArgs["-datadir"] = pathTemp.string();
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ pcoinsTip = new CCoinsViewCache(pcoinsdbview);
InitBlockIndex();
#ifdef ENABLE_WALLET
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
pwalletMain->LoadWallet(fFirstRun);
- RegisterWallet(pwalletMain);
+ RegisterValidationInterface(pwalletMain);
#endif
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 823afa1680..18cb8f3d1b 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -31,6 +31,7 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
(string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH)
(string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
+ (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
(string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY);
@@ -242,7 +243,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEYHASH.
//
static std::vector<CMutableTransaction>
-SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
+SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
{
std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
@@ -261,14 +262,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG;
dummyTransactions[0].vout[1].nValue = 50*CENT;
dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG;
- coinsRet.SetCoins(dummyTransactions[0].GetHash(), CCoins(dummyTransactions[0], 0));
+ coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21*CENT;
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
dummyTransactions[1].vout[1].nValue = 22*CENT;
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
- coinsRet.SetCoins(dummyTransactions[1].GetHash(), CCoins(dummyTransactions[1], 0));
+ coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
return dummyTransactions;
}
@@ -277,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
{
CBasicKeyStore keystore;
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CMutableTransaction t1;
@@ -312,7 +313,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
LOCK(cs_main);
CBasicKeyStore keystore;
CCoinsView coinsDummy;
- CCoinsViewCache coins(coinsDummy);
+ CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CMutableTransaction t;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 6378bd0941..61daa0a3fe 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -9,6 +9,7 @@
#include "sync.h"
#include "utilstrencodings.h"
#include "utilmoneystr.h"
+#include "version.h"
#include <stdint.h>
#include <vector>
@@ -341,4 +342,15 @@ BOOST_AUTO_TEST_CASE(test_FormatParagraph)
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
}
+BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
+{
+ std::vector<std::string> comments;
+ comments.push_back(std::string("comment1"));
+ std::vector<std::string> comments2;
+ comments2.push_back(std::string("comment1"));
+ comments2.push_back(std::string("comment2"));
+ BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/"));
+ BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/"));
+ BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/"));
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txdb.cpp b/src/txdb.cpp
index d5f424fabd..cb9f150011 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -33,12 +33,6 @@ bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
return db.Read(make_pair('c', txid), coins);
}
-bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
- CLevelDBBatch batch;
- BatchWriteCoins(batch, txid, coins);
- return db.WriteBatch(batch);
-}
-
bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
return db.Exists(make_pair('c', txid));
}
@@ -50,24 +44,23 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
-bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) {
- CLevelDBBatch batch;
- BatchWriteHashBestChain(batch, hashBlock);
- return db.WriteBatch(batch);
-}
-
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
- LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
-
CLevelDBBatch batch;
+ size_t count = 0;
+ size_t changed = 0;
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- BatchWriteCoins(batch, it->first, it->second);
+ if (it->second.flags & CCoinsCacheEntry::DIRTY) {
+ BatchWriteCoins(batch, it->first, it->second.coins);
+ changed++;
+ }
+ count++;
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
}
if (hashBlock != uint256(0))
BatchWriteHashBestChain(batch, hashBlock);
+ LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return db.WriteBatch(batch);
}
diff --git a/src/txdb.h b/src/txdb.h
index f0b6b9e1dd..8f2bd9af4d 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -33,10 +33,8 @@ public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
- bool SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats) const;
};
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index d923c2204a..fa1802ad31 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -631,7 +631,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash)
}
-CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
+CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
diff --git a/src/txmempool.h b/src/txmempool.h
index c35ea52d4e..ad190eea9d 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -52,6 +52,19 @@ public:
class CMinerPolicyEstimator;
+/** An inpoint - a combination of a transaction and an index n into its vin */
+class CInPoint
+{
+public:
+ const CTransaction* ptx;
+ uint32_t n;
+
+ CInPoint() { SetNull(); }
+ CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; }
+ void SetNull() { ptx = NULL; n = (uint32_t) -1; }
+ bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); }
+};
+
/*
* CTxMemPool stores valid-according-to-the-current-best-chain
* transactions that may be included in the next block.
@@ -144,7 +157,7 @@ protected:
CTxMemPool &mempool;
public:
- CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
+ CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};
diff --git a/src/ui_interface.h b/src/ui_interface.h
index f5224ba57d..1231d5ed0b 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -63,6 +63,9 @@ public:
/** Force blocking, modal message box dialog (not just OS notification) */
MODAL = 0x10000000U,
+ /** Do not print contents of message to debug log */
+ SECURE = 0x40000000U,
+
/** Predefined combinations for certain default usage cases */
MSG_INFORMATION = ICON_INFORMATION,
MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL),
diff --git a/src/util.cpp b/src/util.cpp
index 632d0965bf..544ffc98b8 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -395,7 +395,8 @@ boost::filesystem::path GetDefaultDataDir()
#endif
}
-static boost::filesystem::path pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1];
+static boost::filesystem::path pathCached;
+static boost::filesystem::path pathCachedNetSpecific;
static CCriticalSection csPathCached;
const boost::filesystem::path &GetDataDir(bool fNetSpecific)
@@ -404,10 +405,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
LOCK(csPathCached);
- int nNet = CBaseChainParams::MAX_NETWORK_TYPES;
- if (fNetSpecific) nNet = BaseParams().NetworkID();
-
- fs::path &path = pathCached[nNet];
+ fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
// This can be called during exceptions by LogPrintf(), so we cache the
// value so we don't have to do memory allocations after that.
@@ -433,8 +431,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
void ClearDatadirCache()
{
- std::fill(&pathCached[0], &pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1],
- boost::filesystem::path());
+ pathCached = boost::filesystem::path();
+ pathCachedNetSpecific = boost::filesystem::path();
}
boost::filesystem::path GetConfigFile()
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index b9e64c5fe1..81e156f43f 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -9,8 +9,8 @@
#include <errno.h>
#include <limits>
-
-#include <boost/foreach.hpp>
+#include <cstdlib>
+#include <cstring>
using namespace std;
@@ -53,9 +53,9 @@ signed char HexDigit(char c)
bool IsHex(const string& str)
{
- BOOST_FOREACH(char c, str)
+ for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)
{
- if (HexDigit(c) < 0)
+ if (HexDigit(*it) < 0)
return false;
}
return (str.size() > 0) && (str.size()%2 == 0);
diff --git a/src/version.cpp b/src/version.cpp
index 95632fdab7..d12b681e5c 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -8,8 +8,6 @@
#include <string>
-#include <boost/algorithm/string/join.hpp>
-
// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
@@ -94,7 +92,13 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const
ss << "/";
ss << name << ":" << FormatVersion(nClientVersion);
if (!comments.empty())
- ss << "(" << boost::algorithm::join(comments, "; ") << ")";
+ {
+ std::vector<std::string>::const_iterator it(comments.begin());
+ ss << "(" << *it;
+ for(++it; it != comments.end(); ++it)
+ ss << "; " << *it;
+ ss << ")";
+ }
ss << "/";
return ss.str();
}
diff --git a/src/version.h b/src/version.h
index 75cbec39b7..a1e440de24 100644
--- a/src/version.h
+++ b/src/version.h
@@ -33,8 +33,11 @@ static const int PROTOCOL_VERSION = 70002;
// initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
+// In this version, 'getheaders' was introduced.
+static const int GETHEADERS_VERSION = 31800;
+
// disconnect from peers older than this proto version
-static const int MIN_PEER_PROTO_VERSION = 209;
+static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION;
// nTime field added to CAddress, starting with this version;
// if possible, avoid requesting addresses nodes older than this
diff --git a/src/wallet.cpp b/src/wallet.cpp
index b20b0007ce..19e43f6ec2 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -15,6 +15,8 @@
#include "util.h"
#include "utilmoneystr.h"
+#include <assert.h>
+
#include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp>
@@ -87,6 +89,13 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
+
+ // check if we need to remove from watch-only
+ CScript script;
+ script = GetScriptForDestination(pubkey.GetID());
+ if (HaveWatchOnly(script))
+ RemoveWatchOnly(script);
+
if (!fFileBacked)
return true;
if (!IsCrypted()) {
@@ -169,6 +178,20 @@ bool CWallet::AddWatchOnly(const CScript &dest)
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
}
+bool CWallet::RemoveWatchOnly(const CScript &dest)
+{
+ AssertLockHeld(cs_wallet);
+ if (!CCryptoKeyStore::RemoveWatchOnly(dest))
+ return false;
+ if (!HaveWatchOnly())
+ NotifyWatchonlyChanged(false);
+ if (fFileBacked)
+ if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
+ return false;
+
+ return true;
+}
+
bool CWallet::LoadWatchOnly(const CScript &dest)
{
return CCryptoKeyStore::AddWatchOnly(dest);
@@ -426,17 +449,25 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
+ assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile);
- if (!pwalletdbEncryption->TxnBegin())
+ if (!pwalletdbEncryption->TxnBegin()) {
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = NULL;
return false;
+ }
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
- if (fFileBacked)
+ if (fFileBacked) {
pwalletdbEncryption->TxnAbort();
- exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
+ delete pwalletdbEncryption;
+ }
+ // We now probably have half of our keys encrypted in memory, and half not...
+ // die and let the user reload their unencrypted wallet.
+ assert(false);
}
// Encryption was introduced in version 0.4.0
@@ -444,8 +475,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
if (fFileBacked)
{
- if (!pwalletdbEncryption->TxnCommit())
- exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
+ if (!pwalletdbEncryption->TxnCommit()) {
+ delete pwalletdbEncryption;
+ // We now have keys encrypted in memory, but no on disk...
+ // die to avoid confusion and let the user reload their unencrypted wallet.
+ assert(false);
+ }
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
@@ -1068,7 +1103,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
-
+
return nTotal;
}
diff --git a/src/wallet.h b/src/wallet.h
index f3fffb2253..06706655f8 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -95,7 +95,7 @@ public:
/** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet : public CCryptoKeyStore, public CWalletInterface
+class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
@@ -143,6 +143,7 @@ public:
{
SetNull();
}
+
CWallet(std::string strWalletFileIn)
{
SetNull();
@@ -150,6 +151,13 @@ public:
strWalletFile = strWalletFileIn;
fFileBacked = true;
}
+
+ ~CWallet()
+ {
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = NULL;
+ }
+
void SetNull()
{
nWalletVersion = FEATURE_BASE;
@@ -222,6 +230,7 @@ public:
// Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript &dest);
+ bool RemoveWatchOnly(const CScript &dest);
// Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
@@ -701,18 +710,37 @@ public:
return debit;
}
- CAmount GetCredit(bool fUseCache=true) const
+ CAmount GetCredit(const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
- // GetBalance can assume transactions in mapWallet won't change
- if (fUseCache && fCreditCached)
- return nCreditCached;
- nCreditCached = pwallet->GetCredit(*this, ISMINE_ALL);
- fCreditCached = true;
- return nCreditCached;
+ int64_t credit = 0;
+ if (filter & ISMINE_SPENDABLE)
+ {
+ // GetBalance can assume transactions in mapWallet won't change
+ if (fCreditCached)
+ credit += nCreditCached;
+ else
+ {
+ nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
+ fCreditCached = true;
+ credit += nCreditCached;
+ }
+ }
+ if (filter & ISMINE_WATCH_ONLY)
+ {
+ if (fWatchCreditCached)
+ credit += nWatchCreditCached;
+ else
+ {
+ nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ fWatchCreditCached = true;
+ credit += nWatchCreditCached;
+ }
+ }
+ return credit;
}
CAmount GetImmatureCredit(bool fUseCache=true) const
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 3e5a664a5d..ffddd8106b 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -15,11 +15,11 @@
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
-using namespace std;
using namespace boost;
-
+using namespace std;
static uint64_t nAccountingEntryNumber = 0;
@@ -121,6 +121,12 @@ bool CWalletDB::WriteWatchOnly(const CScript &dest)
return Write(std::make_pair(std::string("watchs"), dest), '1');
}
+bool CWalletDB::EraseWatchOnly(const CScript &dest)
+{
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("watchs"), dest));
+}
+
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
@@ -179,7 +185,7 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
{
- return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry);
+ return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
}
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
@@ -212,7 +218,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
- ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64_t(0));
+ ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
@@ -918,7 +924,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
bool fSuccess = allOK;
- Db* pdbCopy = new Db(&dbenv.dbenv, 0);
+ boost::scoped_ptr<Db> pdbCopy(new Db(&dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
@@ -959,7 +965,6 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
}
ptxn->commit(0);
pdbCopy->close(0);
- delete pdbCopy;
return fSuccess;
}
@@ -972,11 +977,11 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename)
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
{
nWalletDBUpdated++;
- return Write(boost::make_tuple(std::string("destdata"), address, key), value);
+ return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
}
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
{
nWalletDBUpdated++;
- return Erase(boost::make_tuple(string("destdata"), address, key));
+ return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
}
diff --git a/src/walletdb.h b/src/walletdb.h
index f3d6e61f8b..7ff41c7c8d 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -96,6 +96,7 @@ public:
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
bool WriteWatchOnly(const CScript &script);
+ bool EraseWatchOnly(const CScript &script);
bool WriteBestBlock(const CBlockLocator& locator);
bool ReadBestBlock(CBlockLocator& locator);