aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.qt.include6
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/alert.cpp1
-rw-r--r--src/amount.cpp4
-rw-r--r--src/amount.h2
-rw-r--r--src/base58.h9
-rw-r--r--src/bitcoin-cli.cpp33
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/bloom.cpp34
-rw-r--r--src/bloom.h16
-rw-r--r--src/chainparams.cpp105
-rw-r--r--src/chainparams.h5
-rw-r--r--src/chainparamsbase.cpp5
-rw-r--r--src/checkpoints.cpp1
-rw-r--r--src/coins.cpp14
-rw-r--r--src/coins.h4
-rw-r--r--src/compat.h8
-rw-r--r--src/core_memusage.h62
-rw-r--r--src/init.cpp153
-rw-r--r--src/main.cpp267
-rw-r--r--src/main.h52
-rw-r--r--src/memusage.h31
-rw-r--r--src/miner.cpp64
-rw-r--r--src/miner.h4
-rw-r--r--src/net.cpp282
-rw-r--r--src/net.h111
-rw-r--r--src/netbase.cpp10
-rw-r--r--src/netbase.h12
-rw-r--r--src/policy/fees.cpp5
-rw-r--r--src/policy/policy.cpp178
-rw-r--r--src/policy/policy.h58
-rw-r--r--src/primitives/transaction.h7
-rw-r--r--src/qt/addressbookpage.cpp29
-rw-r--r--src/qt/addressbookpage.h9
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/addresstablemodel.h2
-rw-r--r--src/qt/askpassphrasedialog.h2
-rw-r--r--src/qt/bitcoin.cpp60
-rw-r--r--src/qt/bitcoinamountfield.cpp4
-rw-r--r--src/qt/bitcoinamountfield.h4
-rw-r--r--src/qt/bitcoingui.cpp79
-rw-r--r--src/qt/bitcoingui.h15
-rw-r--r--src/qt/clientmodel.cpp17
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/coincontroldialog.cpp40
-rw-r--r--src/qt/coincontroldialog.h7
-rw-r--r--src/qt/editaddressdialog.h2
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/intro.cpp13
-rw-r--r--src/qt/intro.h6
-rw-r--r--src/qt/macdockiconhandler.h2
-rw-r--r--src/qt/macdockiconhandler.mm2
-rw-r--r--src/qt/networkstyle.cpp1
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/openuridialog.h4
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/optionsdialog.h4
-rw-r--r--src/qt/optionsmodel.cpp8
-rw-r--r--src/qt/optionsmodel.h2
-rw-r--r--src/qt/overviewpage.cpp17
-rw-r--r--src/qt/overviewpage.h9
-rw-r--r--src/qt/paymentrequestplus.cpp4
-rw-r--r--src/qt/paymentserver.cpp64
-rw-r--r--src/qt/paymentserver.h6
-rw-r--r--src/qt/peertablemodel.cpp8
-rw-r--r--src/qt/peertablemodel.h4
-rw-r--r--src/qt/platformstyle.cpp147
-rw-r--r--src/qt/platformstyle.h55
-rw-r--r--src/qt/qvalidatedlineedit.h4
-rw-r--r--src/qt/qvaluecombobox.cpp2
-rw-r--r--src/qt/qvaluecombobox.h4
-rw-r--r--src/qt/receivecoinsdialog.cpp34
-rw-r--r--src/qt/receivecoinsdialog.h9
-rw-r--r--src/qt/receiverequestdialog.h4
-rw-r--r--src/qt/recentrequeststablemodel.cpp4
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/rpcconsole.cpp38
-rw-r--r--src/qt/rpcconsole.h10
-rw-r--r--src/qt/scicon.cpp98
-rw-r--r--src/qt/scicon.h24
-rw-r--r--src/qt/sendcoinsdialog.cpp38
-rw-r--r--src/qt/sendcoinsdialog.h12
-rw-r--r--src/qt/sendcoinsentry.cpp26
-rw-r--r--src/qt/sendcoinsentry.h10
-rw-r--r--src/qt/signverifymessagedialog.cpp35
-rw-r--r--src/qt/signverifymessagedialog.h6
-rw-r--r--src/qt/splashscreen.h2
-rw-r--r--src/qt/test/paymentservertests.cpp2
-rw-r--r--src/qt/test/paymentservertests.h4
-rw-r--r--src/qt/test/uritests.h2
-rw-r--r--src/qt/trafficgraphwidget.cpp4
-rw-r--r--src/qt/trafficgraphwidget.h2
-rw-r--r--src/qt/transactiondesc.cpp6
-rw-r--r--src/qt/transactiontablemodel.cpp21
-rw-r--r--src/qt/transactiontablemodel.h6
-rw-r--r--src/qt/transactionview.cpp67
-rw-r--r--src/qt/transactionview.h9
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/utilitydialog.h2
-rw-r--r--src/qt/walletframe.cpp7
-rw-r--r--src/qt/walletframe.h7
-rw-r--r--src/qt/walletmodel.cpp24
-rw-r--r--src/qt/walletmodel.h7
-rw-r--r--src/qt/walletmodeltransaction.cpp2
-rw-r--r--src/qt/walletview.cpp37
-rw-r--r--src/qt/walletview.h8
-rw-r--r--src/rest.cpp22
-rw-r--r--src/rpcblockchain.cpp148
-rw-r--r--src/rpcclient.cpp1
-rw-r--r--src/rpcmining.cpp56
-rw-r--r--src/rpcmisc.cpp5
-rw-r--r--src/rpcnet.cpp21
-rw-r--r--src/rpcprotocol.cpp67
-rw-r--r--src/rpcprotocol.h10
-rw-r--r--src/rpcrawtransaction.cpp11
-rw-r--r--src/rpcserver.cpp69
-rw-r--r--src/rpcserver.h1
-rw-r--r--src/script/script.h9
-rw-r--r--src/script/sign.cpp3
-rw-r--r--src/script/standard.cpp20
-rw-r--r--src/script/standard.h18
-rw-r--r--src/sync.cpp49
-rw-r--r--src/sync.h8
-rw-r--r--src/test/DoS_tests.cpp5
-rw-r--r--src/test/README.md14
-rw-r--r--src/test/alert_tests.cpp5
-rw-r--r--src/test/bip32_tests.cpp11
-rw-r--r--src/test/bloom_tests.cpp6
-rw-r--r--src/test/checkblock_tests.cpp3
-rw-r--r--src/test/coins_tests.cpp4
-rw-r--r--src/test/data/bitcoin-util-test.json2
-rw-r--r--src/test/data/tx_invalid.json8
-rw-r--r--src/test/data/txcreatesign.hex2
-rw-r--r--src/test/getarg_tests.cpp22
-rw-r--r--src/test/mempool_tests.cpp1
-rw-r--r--src/test/miner_tests.cpp5
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp11
-rw-r--r--src/test/pow_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp48
-rw-r--r--src/test/script_P2SH_tests.cpp1
-rw-r--r--src/test/script_tests.cpp2
-rw-r--r--src/test/sighash_tests.cpp5
-rw-r--r--src/test/skiplist_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp58
-rw-r--r--src/test/test_bitcoin.h28
-rw-r--r--src/test/transaction_tests.cpp4
-rw-r--r--src/test/txvalidationcache_tests.cpp86
-rw-r--r--src/test/univalue_tests.cpp6
-rw-r--r--src/test/util_tests.cpp66
-rw-r--r--src/txdb.cpp1
-rw-r--r--src/txmempool.cpp20
-rw-r--r--src/txmempool.h7
-rw-r--r--src/univalue/univalue.cpp5
-rw-r--r--src/univalue/univalue.h3
-rw-r--r--src/univalue/univalue_write.cpp7
-rw-r--r--src/util.cpp170
-rw-r--r--src/util.h8
-rw-r--r--src/utilstrencodings.cpp131
-rw-r--r--src/utilstrencodings.h7
-rw-r--r--src/validationinterface.cpp6
-rw-r--r--src/validationinterface.h8
-rw-r--r--src/wallet/crypter.cpp2
-rw-r--r--src/wallet/rpcdump.cpp3
-rw-r--r--src/wallet/rpcwallet.cpp53
-rw-r--r--src/wallet/wallet.cpp30
-rw-r--r--src/wallet/wallet.h20
-rw-r--r--src/wallet/wallet_ismine.h3
-rw-r--r--src/wallet/walletdb.cpp2
-rw-r--r--src/wallet/walletdb.h1
173 files changed, 2927 insertions, 1273 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 59618c4940..cc8dded413 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,6 +94,7 @@ BITCOIN_CORE_H = \
consensus/params.h \
consensus/validation.h \
core_io.h \
+ core_memusage.h \
eccryptoverify.h \
ecwrapper.h \
hash.h \
@@ -111,6 +112,7 @@ BITCOIN_CORE_H = \
netbase.h \
noui.h \
policy/fees.h \
+ policy/policy.h \
pow.h \
primitives/block.h \
primitives/transaction.h \
@@ -176,6 +178,7 @@ libbitcoin_server_a_SOURCES = \
net.cpp \
noui.cpp \
policy/fees.cpp \
+ policy/policy.cpp \
pow.cpp \
rest.cpp \
rpcblockchain.cpp \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 6b7c42285d..748f2b14d5 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -185,13 +185,13 @@ BITCOIN_QT_H = \
qt/paymentrequestplus.h \
qt/paymentserver.h \
qt/peertablemodel.h \
+ qt/platformstyle.h \
qt/qvalidatedlineedit.h \
qt/qvaluecombobox.h \
qt/receivecoinsdialog.h \
qt/receiverequestdialog.h \
qt/recentrequeststablemodel.h \
qt/rpcconsole.h \
- qt/scicon.h \
qt/sendcoinsdialog.h \
qt/sendcoinsentry.h \
qt/signverifymessagedialog.h \
@@ -273,10 +273,10 @@ BITCOIN_QT_CPP = \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
qt/peertablemodel.cpp \
+ qt/platformstyle.cpp \
qt/qvalidatedlineedit.cpp \
qt/qvaluecombobox.cpp \
qt/rpcconsole.cpp \
- qt/scicon.cpp \
qt/splashscreen.cpp \
qt/trafficgraphwidget.cpp \
qt/utilitydialog.cpp
@@ -322,7 +322,7 @@ RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png)
BITCOIN_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \
- -I$(builddir)/qt/forms
+ -I$(builddir)/qt/forms -DQT_NO_KEYWORDS
qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 0997148117..f9384a09a4 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -73,6 +73,7 @@ BITCOIN_TESTS =\
test/test_bitcoin.h \
test/timedata_tests.cpp \
test/transaction_tests.cpp \
+ test/txvalidationcache_tests.cpp \
test/uint256_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp
diff --git a/src/alert.cpp b/src/alert.cpp
index ad81e74226..91e54a9178 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -11,6 +11,7 @@
#include "timedata.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <stdint.h>
#include <algorithm>
diff --git a/src/amount.cpp b/src/amount.cpp
index 0a394c96fc..b469181984 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -7,6 +7,8 @@
#include "tinyformat.h"
+const std::string CURRENCY_UNIT = "BTC";
+
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
{
if (nSize > 0)
@@ -27,5 +29,5 @@ CAmount CFeeRate::GetFee(size_t nSize) const
std::string CFeeRate::ToString() const
{
- return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
+ return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
}
diff --git a/src/amount.h b/src/amount.h
index 7dc62edac4..90e6b5aa8e 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -16,6 +16,8 @@ typedef int64_t CAmount;
static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000;
+extern const std::string CURRENCY_UNIT;
+
/** No amount larger than this (in satoshi) is valid.
*
* Note that this constant is *not* the total money supply, which in Bitcoin
diff --git a/src/base58.h b/src/base58.h
index 787979c827..90014b9496 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -146,7 +146,10 @@ public:
K GetKey() {
K ret;
- ret.Decode(&vchData[0], &vchData[Size]);
+ if (vchData.size() == Size) {
+ //if base58 encouded data not holds a ext key, return a !IsValid() key
+ ret.Decode(&vchData[0]);
+ }
return ret;
}
@@ -154,6 +157,10 @@ public:
SetKey(key);
}
+ CBitcoinExtKeyBase(const std::string& strBase58c) {
+ SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
+ }
+
CBitcoinExtKeyBase() {}
};
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index d451720141..1c5a312874 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -97,12 +97,6 @@ static bool AppInitRPC(int argc, char* argv[])
UniValue CallRPC(const string& strMethod, const UniValue& params)
{
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
- throw runtime_error(strprintf(
- _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
- "If the file does not exist, create it with owner-readable-only file permissions."),
- GetConfigFile().string().c_str()));
-
// Connect to localhost
bool fUseSSL = GetBoolArg("-rpcssl", false);
boost::asio::io_service io_service;
@@ -116,10 +110,24 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
if (!fConnected)
throw CConnectionFailed("couldn't connect to server");
+ // Find credentials to use
+ std::string strRPCUserColonPass;
+ if (mapArgs["-rpcpassword"] == "") {
+ // Try fall back to cookie-based authentication if no password is provided
+ if (!GetAuthCookie(&strRPCUserColonPass)) {
+ throw runtime_error(strprintf(
+ _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions."),
+ GetConfigFile().string().c_str()));
+
+ }
+ } else {
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ }
+
// HTTP basic authentication
- string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
map<string, string> mapRequestHeaders;
- mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+ mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass);
// Send request
string strRequest = JSONRPCRequest(strMethod, params, 1);
@@ -190,6 +198,15 @@ int CommandLineRPC(int argc, char *argv[])
throw CConnectionFailed("server in warmup");
strPrint = "error: " + error.write();
nRet = abs(code);
+ if (error.isObject())
+ {
+ UniValue errCode = find_value(error, "code");
+ UniValue errMsg = find_value(error, "message");
+ strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
+
+ if (errMsg.isStr())
+ strPrint += "error message:\n"+errMsg.get_str();
+ }
} else {
// Result
if (result.isNull())
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 45990f6bd8..e389d51a73 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,6 +8,7 @@
#include "consensus/consensus.h"
#include "core_io.h"
#include "keystore.h"
+#include "policy/policy.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
@@ -142,13 +143,14 @@ static void RegisterLoad(const string& strInput)
valStr.insert(valStr.size(), buf, bread);
}
- if (ferror(f)) {
+ int error = ferror(f);
+ fclose(f);
+
+ if (error) {
string strErr = "Error reading file " + filename;
throw runtime_error(strErr);
}
- fclose(f);
-
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index cce687ac98..39bb301f44 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chainparams.h"
#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
-#include "main.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 36cba491c4..de87206592 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -8,6 +8,7 @@
#include "hash.h"
#include "script/script.h"
#include "script/standard.h"
+#include "random.h"
#include "streams.h"
#include <math.h>
@@ -121,6 +122,12 @@ void CBloomFilter::clear()
isEmpty = true;
}
+void CBloomFilter::reset(unsigned int nNewTweak)
+{
+ clear();
+ nTweak = nNewTweak;
+}
+
bool CBloomFilter::IsWithinSizeConstraints() const
{
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
@@ -209,15 +216,17 @@ void CBloomFilter::UpdateEmptyFull()
isEmpty = empty;
}
-CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate, unsigned int nTweak) :
- b1(nElements * 2, fpRate, nTweak), b2(nElements * 2, fpRate, nTweak)
+CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) :
+ b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0)
{
// Implemented using two bloom filters of 2 * nElements each.
// We fill them up, and clear them, staggered, every nElements
// inserted, so at least one always contains the last nElements
// inserted.
- nBloomSize = nElements * 2;
nInsertions = 0;
+ nBloomSize = nElements * 2;
+
+ reset();
}
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
@@ -234,6 +243,12 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
}
}
+void CRollingBloomFilter::insert(const uint256& hash)
+{
+ vector<unsigned char> data(hash.begin(), hash.end());
+ insert(data);
+}
+
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
if (nInsertions < nBloomSize / 2) {
@@ -242,9 +257,16 @@ bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
return b1.contains(vKey);
}
-void CRollingBloomFilter::clear()
+bool CRollingBloomFilter::contains(const uint256& hash) const
+{
+ vector<unsigned char> data(hash.begin(), hash.end());
+ return contains(data);
+}
+
+void CRollingBloomFilter::reset()
{
- b1.clear();
- b2.clear();
+ unsigned int nNewTweak = GetRand(std::numeric_limits<unsigned int>::max());
+ b1.reset(nNewTweak);
+ b2.reset(nNewTweak);
nInsertions = 0;
}
diff --git a/src/bloom.h b/src/bloom.h
index bb17f59c86..a4dba8cb4f 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -89,6 +89,7 @@ public:
bool contains(const uint256& hash) const;
void clear();
+ void reset(unsigned int nNewTweak);
//! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
//! (catch a filter which was just deserialized which was too big)
@@ -103,7 +104,11 @@ public:
/**
* RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
- * Construct it with the number of items to keep track of, and a false-positive rate.
+ * Construct it with the number of items to keep track of, and a false-positive
+ * rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically
+ * secure random value for you. Similarly rather than clear() the method
+ * reset() is provided, which also changes nTweak to decrease the impact of
+ * false-positives.
*
* contains(item) will always return true if item was one of the last N things
* insert()'ed ... but may also return true for items that were not inserted.
@@ -111,12 +116,17 @@ public:
class CRollingBloomFilter
{
public:
- CRollingBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak);
+ // A random bloom filter calls GetRand() at creation time.
+ // Don't create global CRollingBloomFilter objects, as they may be
+ // constructed before the randomizer is properly initialized.
+ CRollingBloomFilter(unsigned int nElements, double nFPRate);
void insert(const std::vector<unsigned char>& vKey);
+ void insert(const uint256& hash);
bool contains(const std::vector<unsigned char>& vKey) const;
+ bool contains(const uint256& hash) const;
- void clear();
+ void reset();
private:
unsigned int nBloomSize;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 7785417518..623104690a 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -16,6 +16,45 @@ using namespace std;
#include "chainparamsseeds.h"
+static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ CMutableTransaction txNew;
+ txNew.nVersion = 1;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].nValue = genesisReward;
+ txNew.vout[0].scriptPubKey = genesisOutputScript;
+
+ CBlock genesis;
+ genesis.nTime = nTime;
+ genesis.nBits = nBits;
+ genesis.nNonce = nNonce;
+ genesis.nVersion = nVersion;
+ genesis.vtx.push_back(txNew);
+ genesis.hashPrevBlock.SetNull();
+ genesis.hashMerkleRoot = genesis.BuildMerkleTree();
+ return genesis;
+}
+
+/**
+ * Build the genesis block. Note that the output of its generation
+ * transaction cannot be spent since it did not originally exist in the
+ * database.
+ *
+ * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
+ * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
+ * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
+ * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
+ * vMerkleTree: 4a5e1e
+ */
+static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
+ const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
+}
+
/**
* Main network
*/
@@ -50,36 +89,9 @@ public:
pchMessageStart[3] = 0xd9;
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
- nMinerThreads = 0;
nPruneAfterHeight = 100000;
- /**
- * Build the genesis block. Note that the output of its generation
- * transaction cannot be spent since it did not originally exist in the
- * database.
- *
- * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- * vMerkleTree: 4a5e1e
- */
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- CMutableTransaction txNew;
- txNew.nVersion = 1;
- txNew.vin.resize(1);
- txNew.vout.resize(1);
- txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
- txNew.vout[0].nValue = 50 * COIN;
- txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- genesis.vtx.push_back(txNew);
- genesis.hashPrevBlock.SetNull();
- genesis.hashMerkleRoot = genesis.BuildMerkleTree();
- genesis.nVersion = 1;
- genesis.nTime = 1231006505;
- genesis.nBits = 0x1d00ffff;
- genesis.nNonce = 2083236893;
-
+ genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
@@ -99,7 +111,6 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
- fRequireRPCPassword = true;
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
@@ -133,13 +144,17 @@ static CMainParams mainParams;
/**
* Testnet (v3)
*/
-class CTestNetParams : public CMainParams {
+class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
+ consensus.nSubsidyHalvingInterval = 210000;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 100;
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
@@ -147,14 +162,12 @@ public:
pchMessageStart[3] = 0x07;
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333;
- nMinerThreads = 0;
nPruneAfterHeight = 1000;
- //! Modify the testnet genesis block so the timestamp is valid for a later start.
- genesis.nTime = 1296688602;
- genesis.nNonce = 414098458;
+ genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
vFixedSeeds.clear();
vSeeds.clear();
@@ -171,7 +184,6 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
- fRequireRPCPassword = true;
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
@@ -193,7 +205,7 @@ static CTestNetParams testNetParams;
/**
* Regression test
*/
-class CRegTestParams : public CTestNetParams {
+class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
@@ -202,23 +214,25 @@ public:
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = true;
+
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
- nMinerThreads = 1;
- genesis.nTime = 1296688602;
- genesis.nBits = 0x207fffff;
- genesis.nNonce = 2;
- consensus.hashGenesisBlock = genesis.GetHash();
nDefaultPort = 18444;
- assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
nPruneAfterHeight = 1000;
+ genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds.
- fRequireRPCPassword = false;
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
fRequireStandard = false;
@@ -232,6 +246,11 @@ public:
0,
0
};
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
+ base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
}
};
static CRegTestParams regTestParams;
diff --git a/src/chainparams.h b/src/chainparams.h
index 8044b553e1..66d865b620 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -50,10 +50,7 @@ public:
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
- /** Used if GenerateBitcoins is called with a negative number of threads */
- int DefaultMinerThreads() const { return nMinerThreads; }
const CBlock& GenesisBlock() const { return genesis; }
- bool RequireRPCPassword() const { return fRequireRPCPassword; }
/** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
/** Default value for -checkmempool and -checkblockindex argument */
@@ -79,14 +76,12 @@ protected:
//! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
- int nMinerThreads;
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
- bool fRequireRPCPassword;
bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 7d82d689ec..9c87bf2154 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -25,7 +25,7 @@ static CBaseMainParams mainParams;
/**
* Testnet (v3)
*/
-class CBaseTestNetParams : public CBaseMainParams
+class CBaseTestNetParams : public CBaseChainParams
{
public:
CBaseTestNetParams()
@@ -39,11 +39,12 @@ static CBaseTestNetParams testNetParams;
/*
* Regression test
*/
-class CBaseRegTestParams : public CBaseTestNetParams
+class CBaseRegTestParams : public CBaseChainParams
{
public:
CBaseRegTestParams()
{
+ nRPCPort = 18332;
strDataDir = "regtest";
}
};
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 87f4ad7f2e..a9822eed89 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -4,6 +4,7 @@
#include "checkpoints.h"
+#include "chain.h"
#include "chainparams.h"
#include "main.h"
#include "uint256.h"
diff --git a/src/coins.cpp b/src/coins.cpp
index a41d5a310d..f02949de53 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -83,7 +83,7 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
// version as fresh.
ret->second.flags = CCoinsCacheEntry::FRESH;
}
- cachedCoinsUsage += memusage::DynamicUsage(ret->second.coins);
+ cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage();
return ret;
}
@@ -110,7 +110,7 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
ret.first->second.flags = CCoinsCacheEntry::FRESH;
}
} else {
- cachedCoinUsage = memusage::DynamicUsage(ret.first->second.coins);
+ cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage();
}
// Assume that whenever ModifyCoins is called, the entry will be modified.
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
@@ -159,7 +159,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
assert(it->second.flags & CCoinsCacheEntry::FRESH);
CCoinsCacheEntry& entry = cacheCoins[it->first];
entry.coins.swap(it->second.coins);
- cachedCoinsUsage += memusage::DynamicUsage(entry.coins);
+ cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
}
} else {
@@ -167,13 +167,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
// 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.
- cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coins);
+ cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
cacheCoins.erase(itUs);
} else {
// A normal modification.
- cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coins);
+ cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
itUs->second.coins.swap(it->second.coins);
- cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coins);
+ cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage();
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
}
}
@@ -261,6 +261,6 @@ CCoinsModifier::~CCoinsModifier()
cache.cacheCoins.erase(it);
} else {
// If the coin still exists after the modification, add the new usage
- cache.cachedCoinsUsage += memusage::DynamicUsage(it->second.coins);
+ cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();
}
}
diff --git a/src/coins.h b/src/coins.h
index a4671645df..bf4a777b8a 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -7,6 +7,7 @@
#define BITCOIN_COINS_H
#include "compressor.h"
+#include "core_memusage.h"
#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
@@ -257,8 +258,7 @@ public:
size_t DynamicMemoryUsage() const {
size_t ret = memusage::DynamicUsage(vout);
BOOST_FOREACH(const CTxOut &out, vout) {
- const std::vector<unsigned char> *script = &out.scriptPubKey;
- ret += memusage::DynamicUsage(*script);
+ ret += RecursiveDynamicUsage(out.scriptPubKey);
}
return ret;
}
diff --git a/src/compat.h b/src/compat.h
index 7a5438a11e..5378c2c761 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -92,4 +92,12 @@ typedef u_int SOCKET;
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
+bool static inline IsSelectableSocket(SOCKET s) {
+#ifdef WIN32
+ return true;
+#else
+ return (s < FD_SETSIZE);
+#endif
+}
+
#endif // BITCOIN_COMPAT_H
diff --git a/src/core_memusage.h b/src/core_memusage.h
new file mode 100644
index 0000000000..711135bb44
--- /dev/null
+++ b/src/core_memusage.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CORE_MEMUSAGE_H
+#define BITCOIN_CORE_MEMUSAGE_H
+
+#include "primitives/transaction.h"
+#include "primitives/block.h"
+#include "memusage.h"
+
+static inline size_t RecursiveDynamicUsage(const CScript& script) {
+ return memusage::DynamicUsage(*static_cast<const std::vector<unsigned char>*>(&script));
+}
+
+static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
+ return 0;
+}
+
+static inline size_t RecursiveDynamicUsage(const CTxIn& in) {
+ return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout);
+}
+
+static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
+ return RecursiveDynamicUsage(out.scriptPubKey);
+}
+
+static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
+ for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
+ for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CBlock& block) {
+ size_t mem = memusage::DynamicUsage(block.vtx) + memusage::DynamicUsage(block.vMerkleTree);
+ for (std::vector<CTransaction>::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) {
+ return memusage::DynamicUsage(locator.vHave);
+}
+
+#endif // BITCOIN_CORE_MEMUSAGE_H
diff --git a/src/init.cpp b/src/init.cpp
index c4e3573de3..ef1c39db25 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -11,6 +11,8 @@
#include "addrman.h"
#include "amount.h"
+#include "chain.h"
+#include "chainparams.h"
#include "checkpoints.h"
#include "compat/sanity.h"
#include "consensus/validation.h"
@@ -18,15 +20,19 @@
#include "main.h"
#include "miner.h"
#include "net.h"
+#include "policy/policy.h"
#include "rpcserver.h"
#include "script/standard.h"
#include "scheduler.h"
#include "txdb.h"
+#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
#include "utilmoneystr.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
+#include "wallet/db.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
@@ -156,8 +162,8 @@ void Shutdown()
#ifdef ENABLE_WALLET
if (pwalletMain)
pwalletMain->Flush(false);
- GenerateBitcoins(false, NULL, 0);
#endif
+ GenerateBitcoins(false, 0, Params());
StopNode();
UnregisterNodeSignals(GetNodeSignals());
@@ -283,7 +289,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-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));
+ -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "bitcoind.pid"));
#endif
@@ -308,7 +314,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address"));
strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0));
strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"));
- strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), 125));
+ strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000));
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000));
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
@@ -329,22 +335,24 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("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"));
+ strUsage += HelpMessageOpt("-whiteconnections=<n>", strprintf(_("Reserve this many inbound connections for whitelisted peers (default: %d)"), 0));
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
if (showDebug)
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)",
- FormatMoney(CWallet::minTxFee.GetFeePerK())));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
+ CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup"));
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
- strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
- FormatMoney(maxTxFee)));
+ strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(maxTxFee)));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true));
@@ -370,10 +378,8 @@ std::string HelpMessage(HelpMessageMode mode)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
-#ifdef ENABLE_WALLET
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
-#endif
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
@@ -383,7 +389,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
}
- strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug)
{
@@ -396,6 +403,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
strUsage += HelpMessageGroup(_("Node relay options:"));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -434,6 +443,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-min", _("Start minimized"));
strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)"));
strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)");
+ }
}
return strUsage;
@@ -666,6 +678,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fLogTimestamps = GetBoolArg("-logtimestamps", true);
fLogIPs = GetBoolArg("-logips", false);
+ LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+ LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if (mapArgs.count("-bind")) {
@@ -724,16 +739,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
}
- // Make sure enough file descriptors are available
- int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
- nMaxConnections = GetArg("-maxconnections", 125);
- nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
- int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
- if (nFD < MIN_CORE_FILEDESCRIPTORS)
- return InitError(_("Not enough file descriptors available."));
- if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
- nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
-
// if using block pruning, then disable txindex
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false))
@@ -744,6 +749,47 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
}
+
+ // Make sure enough file descriptors are available
+ int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
+ int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
+ nMaxConnections = std::max(nUserMaxConnections, 0);
+ int nUserWhiteConnections = GetArg("-whiteconnections", 0);
+ nWhiteConnections = std::max(nUserWhiteConnections, 0);
+
+ if ((mapArgs.count("-whitelist")) || (mapArgs.count("-whitebind"))) {
+ if (!(mapArgs.count("-maxconnections"))) {
+ // User is using whitelist feature,
+ // but did not specify -maxconnections parameter.
+ // Silently increase the default to compensate,
+ // so that the whitelist connection reservation feature
+ // does not inadvertently reduce the default
+ // inbound connection capacity of the network.
+ nMaxConnections += nWhiteConnections;
+ }
+ } else {
+ // User not using whitelist feature.
+ // Silently disable connection reservation,
+ // for the same reason as above.
+ nWhiteConnections = 0;
+ }
+
+ // Trim requested connection counts, to fit into system limitations
+ nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
+ int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
+ if (nFD < MIN_CORE_FILEDESCRIPTORS)
+ return InitError(_("Not enough file descriptors available."));
+ nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
+
+ if (nMaxConnections < nUserMaxConnections)
+ InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
+
+ // Connection capacity is prioritized in this order:
+ // outbound connections (hardcoded to 8),
+ // then whitelisted connections,
+ // then non-whitelisted connections get whatever's left (if any).
+ if ((nWhiteConnections > 0) && (nWhiteConnections >= (nMaxConnections - 8)))
+ InitWarning(strprintf(_("All non-whitelisted incoming connections will be dropped, because -whiteconnections is %d and -maxconnections is only %d."), nWhiteConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
@@ -774,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
- nScriptCheckThreads += boost::thread::hardware_concurrency();
+ nScriptCheckThreads += GetNumCores();
if (nScriptCheckThreads <= 1)
nScriptCheckThreads = 0;
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
@@ -819,6 +865,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
}
+ fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
+ if (Params().RequireStandard() && !fRequireStandard)
+ return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
+
#ifdef ENABLE_WALLET
if (mapArgs.count("-mintxfee"))
{
@@ -904,8 +954,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#endif
if (GetBoolArg("-shrinkdebugfile", !fDebug))
ShrinkDebugFile();
- LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
+ if (fPrintToDebugLog)
+ OpenDebugLog();
+
LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
#ifdef ENABLE_WALLET
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
@@ -916,6 +968,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Using data directory %s\n", strDataDir);
LogPrintf("Using config file %s\n", GetConfigFile().string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
+ if (nWhiteConnections > 0)
+ LogPrintf("Reserving %i of these connections for whitelisted inbound peers\n", nWhiteConnections);
std::ostringstream strErrors;
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
@@ -966,6 +1020,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterNodeSignals(GetNodeSignals());
+ // format user agent, check total size
+ strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, mapMultiArgs.count("-uacomment") ? mapMultiArgs["-uacomment"] : std::vector<string>());
+ if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
+ return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.",
+ strSubVersion.size(), MAX_SUBVERSION_LENGTH));
+ }
+
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) {
@@ -1176,6 +1237,18 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288));
}
+
+ {
+ LOCK(cs_main);
+ CBlockIndex* tip = chainActive.Tip();
+ if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
+ strLoadError = _("The block database contains a block which appears to be from the future. "
+ "This may be due to your computer's date and time being set incorrectly. "
+ "Only rebuild the block database if you are sure that your computer's date and time are correct");
+ break;
+ }
+ }
+
if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3),
GetArg("-checkblocks", 288))) {
strLoadError = _("Corrupted block database detected");
@@ -1226,15 +1299,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
mempool.ReadFeeEstimates(est_filein);
fFeeEstimatesInitialized = true;
- // if prune mode, unset NODE_NETWORK and prune block files
- if (fPruneMode) {
- LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
- nLocalServices &= ~NODE_NETWORK;
- if (!fReindex) {
- PruneAndFlush();
- }
- }
-
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
if (fDisableWallet) {
@@ -1388,7 +1452,21 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#else // ENABLE_WALLET
LogPrintf("No wallet support compiled in!\n");
#endif // !ENABLE_WALLET
- // ********************************************************* Step 9: import blocks
+
+ // ********************************************************* Step 9: data directory maintenance
+
+ // if pruning, unset the service bit and perform the initial blockstore prune
+ // after any wallet rescanning has taken place.
+ if (fPruneMode) {
+ uiInterface.InitMessage(_("Pruning blockstore..."));
+ LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
+ nLocalServices &= ~NODE_NETWORK;
+ if (!fReindex) {
+ PruneAndFlush();
+ }
+ }
+
+ // ********************************************************* Step 10: import blocks
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
@@ -1412,7 +1490,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
MilliSleep(10);
}
- // ********************************************************* Step 10: start node
+ // ********************************************************* Step 11: start node
if (!CheckDiskSpace())
return false;
@@ -1439,11 +1517,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing);
-#ifdef ENABLE_WALLET
// Generate coins in the background
- if (pwalletMain)
- GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1));
-#endif
+ GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params());
// ********************************************************* Step 11: finished
diff --git a/src/main.cpp b/src/main.cpp
index 4bf5883692..79cc606856 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,17 +11,27 @@
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
+#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "hash.h"
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/policy.h"
#include "pow.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
+#include "script/script.h"
+#include "script/sigcache.h"
+#include "script/standard.h"
+#include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
#include <sstream>
@@ -57,6 +67,7 @@ bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = true;
+bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = true;
size_t nCoinCacheUsage = 5000 * 300;
@@ -72,9 +83,9 @@ struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
-map<uint256, COrphanTx> mapOrphanTransactions;
-map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
-void EraseOrphansFor(NodeId peer);
+map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);;
+map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
+void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Returns true if there are nRequired or more blocks of minVersion or above
@@ -151,6 +162,29 @@ namespace {
*/
map<uint256, NodeId> mapBlockSource;
+ /**
+ * Filter for transactions that were recently rejected by
+ * AcceptToMemoryPool. These are not rerequested until the chain tip
+ * changes, at which point the entire filter is reset. Protected by
+ * cs_main.
+ *
+ * Without this filter we'd be re-requesting txs from each of our peers,
+ * increasing bandwidth consumption considerably. For instance, with 100
+ * peers, half of which relay a tx we don't accept, that might be a 50x
+ * bandwidth increase. A flooding attacker attempting to roll-over the
+ * filter using minimum-sized, 60byte, transactions might manage to send
+ * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
+ * two minute window to send invs to us.
+ *
+ * Decreasing the false positive rate is fairly cheap, so we pick one in a
+ * million to make it highly unlikely for users to have issues with this
+ * filter.
+ *
+ * Memory used: 1.7MB
+ */
+ boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ uint256 hashRecentRejectsChainTip;
+
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
@@ -524,7 +558,7 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
//
-bool AddOrphanTx(const CTransaction& tx, NodeId peer)
+bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
@@ -554,7 +588,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer)
return true;
}
-void static EraseOrphanTx(uint256 hash)
+void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
@@ -588,7 +622,7 @@ void EraseOrphansFor(NodeId peer)
}
-unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
+unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
@@ -604,76 +638,6 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
return nEvicted;
}
-
-
-
-
-
-
-bool IsStandardTx(const CTransaction& tx, string& reason)
-{
- if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
- reason = "version";
- return false;
- }
-
- // Extremely large transactions with lots of inputs can cost the network
- // almost as much to process as they cost the sender in fees, because
- // computing signature hashes is O(ninputs*txsize). Limiting transactions
- // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
- unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
- if (sz >= MAX_STANDARD_TX_SIZE) {
- reason = "tx-size";
- return false;
- }
-
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys. (remember the 520 byte limit on redeemScript size) That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
- // bytes of scriptSig, which we round off to 1650 bytes for some minor
- // future-proofing. That's also enough to spend a 20-of-20
- // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard)
- if (txin.scriptSig.size() > 1650) {
- reason = "scriptsig-size";
- return false;
- }
- if (!txin.scriptSig.IsPushOnly()) {
- reason = "scriptsig-not-pushonly";
- return false;
- }
- }
-
- unsigned int nDataOut = 0;
- txnouttype whichType;
- BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
- reason = "scriptpubkey";
- return false;
- }
-
- if (whichType == TX_NULL_DATA)
- nDataOut++;
- else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
- reason = "bare-multisig";
- return false;
- } else if (txout.IsDust(::minRelayTxFee)) {
- reason = "dust";
- return false;
- }
- }
-
- // only one OP_RETURN txout is permitted
- if (nDataOut > 1) {
- reason = "multi-op-return";
- return false;
- }
-
- return true;
-}
-
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
if (tx.nLockTime == 0)
@@ -692,74 +656,6 @@ bool CheckFinalTx(const CTransaction &tx)
return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime());
}
-/**
- * Check transaction inputs to mitigate two
- * potential denial-of-service attacks:
- *
- * 1. scriptSigs with extra data stuffed into them,
- * not consumed by scriptPubKey (or P2SH script)
- * 2. P2SH scripts with a crazy number of expensive
- * CHECKSIG/CHECKMULTISIG operations
- */
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
-{
- if (tx.IsCoinBase())
- return true; // Coinbases don't use vin normally
-
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
-
- vector<vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
- return false;
- int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
- if (nArgsExpected < 0)
- return false;
-
- // Transactions with extra stuff in their scriptSigs are
- // non-standard. Note that this EvalScript() call will
- // be quick, because if there are any operations
- // beside "push data" in the scriptSig
- // IsStandardTx() will have already returned false
- // and this method isn't called.
- vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
- return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
- if (stack.empty())
- return false;
- CScript subscript(stack.back().begin(), stack.back().end());
- vector<vector<unsigned char> > vSolutions2;
- txnouttype whichType2;
- if (Solver(subscript, whichType2, vSolutions2))
- {
- int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
- if (tmpExpected < 0)
- return false;
- nArgsExpected += tmpExpected;
- }
- else
- {
- // Any other Script with less than 15 sigops OK:
- unsigned int sigops = subscript.GetSigOpCount(true);
- // ... extra data left on the stack after execution is OK, too:
- return (sigops <= MAX_P2SH_SIGOPS);
- }
- }
-
- if (stack.size() != (unsigned int)nArgsExpected)
- return false;
- }
-
- return true;
-}
-
unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
@@ -900,7 +796,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
- if (Params().RequireStandard() && !IsStandardTx(tx, reason))
+ if (fRequireStandard && !IsStandardTx(tx, reason))
return state.DoS(0,
error("AcceptToMemoryPool: nonstandard transaction: %s", reason),
REJECT_NONSTANDARD, reason);
@@ -971,7 +867,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
// Check for non-standard pay-to-script-hash in inputs
- if (Params().RequireStandard() && !AreInputsStandard(tx, view))
+ if (fRequireStandard && !AreInputsStandard(tx, view))
return error("AcceptToMemoryPool: nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of
@@ -2196,7 +2092,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
CCoinsViewCache view(pcoinsTip);
- CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
bool rv = ConnectBlock(*pblock, state, pindexNew, view);
GetMainSignals().BlockChecked(*pblock, state);
if (!rv) {
@@ -2204,7 +2099,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
InvalidBlockFound(pindexNew, state);
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
- mapBlockSource.erase(inv.hash);
+ mapBlockSource.erase(pindexNew->GetBlockHash());
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
assert(view.Flush());
@@ -2864,9 +2759,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
// Try to process all requested blocks that we don't have, but only
// process an unrequested block if it's new and has enough work to
- // advance our tip.
+ // advance our tip, and isn't too many blocks ahead.
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
+ // Blocks that are too out-of-order needlessly limit the effectiveness of
+ // pruning, because pruning will not delete block files that contain any
+ // blocks which are too close in height to the tip. Apply this test
+ // regardless of whether pruning is enabled; it should generally be safe to
+ // not process unrequested blocks.
+ bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));
// TODO: deal better with return value and error conditions for duplicate
// and unrequested blocks.
@@ -2874,6 +2775,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (!fRequested) { // If we didn't ask for it:
if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
if (!fHasMoreWork) return true; // Don't process less-work chains
+ if (fTooFarAhead) return true; // Block height is too high
}
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
@@ -3371,6 +3273,7 @@ void UnloadBlockIndex()
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
mapNodeState.clear();
+ recentRejects.reset(NULL);
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
delete entry.second;
@@ -3391,6 +3294,10 @@ bool LoadBlockIndex()
bool InitBlockIndex() {
const CChainParams& chainparams = Params();
LOCK(cs_main);
+
+ // Initialize global variables that cannot be constructed at startup.
+ recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+
// Check whether we're already initialized
if (chainActive.Genesis() != NULL)
return true;
@@ -3521,7 +3428,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
} catch (const std::exception& e) {
- LogPrintf("%s: Deserialize or I/O error - %s", __func__, e.what());
+ LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what());
}
}
} catch (const std::runtime_error& e) {
@@ -3787,16 +3694,27 @@ std::string GetWarnings(const std::string& strFor)
//
-bool static AlreadyHave(const CInv& inv)
+bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
switch (inv.type)
{
case MSG_TX:
{
- bool txInMap = false;
- txInMap = mempool.exists(inv.hash);
- return txInMap || mapOrphanTransactions.count(inv.hash) ||
- pcoinsTip->HaveCoins(inv.hash);
+ assert(recentRejects);
+ if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
+ {
+ // If the chain tip has changed previously rejected transactions
+ // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
+ // or a double-spend. Reset the rejects filter and give those
+ // txs a second chance.
+ hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash();
+ recentRejects->reset();
+ }
+
+ return recentRejects->contains(inv.hash) ||
+ mempool.exists(inv.hash) ||
+ mapOrphanTransactions.count(inv.hash) ||
+ pcoinsTip->HaveCoins(inv.hash);
}
case MSG_BLOCK:
return mapBlockIndex.count(inv.hash);
@@ -3982,7 +3900,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
- vRecv >> LIMITED_STRING(pfrom->strSubVer, 256);
+ vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
}
if (!vRecv.empty())
@@ -4396,6 +4314,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
+ assert(recentRejects);
+ recentRejects->insert(orphanHash);
}
mempool.check(pcoinsTip);
}
@@ -4413,11 +4333,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
if (nEvicted > 0)
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
- } else if (pfrom->fWhitelisted) {
- // Always relay transactions received from whitelisted peers, even
- // if they are already in the mempool (allowing the node to function
- // as a gateway for nodes hidden behind it).
- RelayTransaction(tx);
+ } else {
+ // AcceptToMemoryPool() returned false, possibly because the tx is
+ // already in the mempool; if the tx isn't in the mempool that
+ // means it was rejected and we shouldn't ask for it again.
+ if (!mempool.exists(tx.GetHash())) {
+ assert(recentRejects);
+ recentRejects->insert(tx.GetHash());
+ }
+ if (pfrom->fWhitelisted) {
+ // Always relay transactions received from whitelisted peers, even
+ // if they were rejected from the mempool, allowing the node to
+ // function as a gateway for nodes hidden behind it.
+ //
+ // FIXME: This includes invalid transactions, which means a
+ // whitelisted peer could get us banned! We may want to change
+ // that.
+ RelayTransaction(tx);
+ }
}
int nDoS = 0;
if (state.IsInvalid(nDoS))
@@ -4498,8 +4431,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->AddInventoryKnown(inv);
CValidationState state;
- // Process all blocks from whitelisted peers, even if not requested.
- ProcessNewBlock(state, pfrom, &block, pfrom->fWhitelisted, NULL);
+ // Process all blocks from whitelisted peers, even if not requested,
+ // unless we're still syncing with the network.
+ // Such an unrequested block may still be processed, subject to the
+ // conditions in AcceptBlock().
+ bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
@@ -4916,7 +4853,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
{
// Periodically clear addrKnown to allow refresh broadcasts
if (nLastRebroadcast)
- pnode->addrKnown.clear();
+ pnode->addrKnown.reset();
// Rebroadcast our address
AdvertizeLocal(pnode);
@@ -4961,7 +4898,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else
{
- CNode::Ban(pto->addr);
+ CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
}
}
state.fShouldBan = false;
diff --git a/src/main.h b/src/main.h
index e11d5c857d..eec7e6fa59 100644
--- a/src/main.h
+++ b/src/main.h
@@ -12,19 +12,10 @@
#include "amount.h"
#include "chain.h"
-#include "chainparams.h"
#include "coins.h"
-#include "consensus/consensus.h"
#include "net.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sigcache.h"
-#include "script/standard.h"
+#include "script/script_error.h"
#include "sync.h"
-#include "tinyformat.h"
-#include "txmempool.h"
-#include "uint256.h"
#include <algorithm>
#include <exception>
@@ -42,24 +33,14 @@ class CBlockTreeDB;
class CBloomFilter;
class CInv;
class CScriptCheck;
+class CTxMemPool;
class CValidationInterface;
class CValidationState;
struct CNodeStateStats;
-/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
-static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
-/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
-static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
/** Default for accepting alerts from the P2P network. */
static const bool DEFAULT_ALERTS = true;
-/** The maximum size for transactions we're willing to relay/mine */
-static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
-/** Maximum number of signature check operations in an IsStandard() P2SH script */
-static const unsigned int MAX_P2SH_SIGOPS = 15;
-/** The maximum number of sigops we're willing to relay/mine in a single tx */
-static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
/** The maximum size of a blk?????.dat file (since 0.8) */
@@ -111,6 +92,7 @@ extern bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
+extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
@@ -131,7 +113,7 @@ extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
-static const signed int MIN_BLOCKS_TO_KEEP = 288;
+static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
@@ -141,7 +123,7 @@ static const signed int MIN_BLOCKS_TO_KEEP = 288;
// full block file chunks, we need the high water mark which triggers the prune to be
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
// Setting the target to > than 550MB will make it likely we can respect the target.
-static const signed int MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
+static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
/** Register with a network node to receive its signals */
void RegisterNodeSignals(CNodeSignals& nodeSignals);
@@ -273,25 +255,6 @@ struct CDiskTxPos : public CDiskBlockPos
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-/**
- * Check transaction inputs, and make sure any
- * pay-to-script-hash transactions are evaluating IsStandard scripts
- *
- * Why bother? To avoid denial-of-service attacks; an attacker
- * can submit a standard HASH... OP_EQUAL transaction,
- * which will get accepted into blocks. The redemption
- * script can be anything; an attacker could use a very
- * expensive-to-check-upon-redemption script like:
- * DUP CHECKSIG DROP ... repeated 100 times... OP_1
- */
-
-/**
- * Check for standard transaction types
- * @param[in] mapInputs Map of previous transactions that have outputs we're spending
- * @return True if all inputs (scriptSigs) use only standard transaction forms
- */
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
@@ -323,11 +286,6 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
-/** Check for standard transaction types
- * @return True if all outputs (scriptPubKeys) use only standard transaction forms
- */
-bool IsStandardTx(const CTransaction& tx, std::string& reason);
-
/**
* Check if transaction is final and can be included in a block with the
* specified height and time. Consensus critical.
diff --git a/src/memusage.h b/src/memusage.h
index 9f7de9e2e1..be3964df1b 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -11,6 +11,7 @@
#include <set>
#include <vector>
+#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
@@ -20,19 +21,27 @@ namespace memusage
/** Compute the total memory used by allocating alloc bytes. */
static size_t MallocUsage(size_t alloc);
+/** Dynamic memory usage for built-in types is zero. */
+static inline size_t DynamicUsage(const int8_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint8_t& v) { return 0; }
+static inline size_t DynamicUsage(const int16_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint16_t& v) { return 0; }
+static inline size_t DynamicUsage(const int32_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint32_t& v) { return 0; }
+static inline size_t DynamicUsage(const int64_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint64_t& v) { return 0; }
+static inline size_t DynamicUsage(const float& v) { return 0; }
+static inline size_t DynamicUsage(const double& v) { return 0; }
+template<typename X> static inline size_t DynamicUsage(X * const &v) { return 0; }
+template<typename X> static inline size_t DynamicUsage(const X * const &v) { return 0; }
+
/** Compute the memory used for dynamically allocated but owned data structures.
* For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >)
* will compute the memory used for the vector<int>'s, but not for the ints inside.
* This is for efficiency reasons, as these functions are intended to be fast. If
* application data structures require more accurate inner accounting, they should
- * do the recursion themselves, or use more efficient caching + updating on modification.
+ * iterate themselves, or use more efficient caching + updating on modification.
*/
-template<typename X> static size_t DynamicUsage(const std::vector<X>& v);
-template<typename X> static size_t DynamicUsage(const std::set<X>& s);
-template<typename X, typename Y> static size_t DynamicUsage(const std::map<X, Y>& m);
-template<typename X, typename Y> static size_t DynamicUsage(const boost::unordered_set<X, Y>& s);
-template<typename X, typename Y, typename Z> static size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& s);
-template<typename X> static size_t DynamicUsage(const X& x);
static inline size_t MallocUsage(size_t alloc)
{
@@ -98,14 +107,6 @@ static inline size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& m)
return MallocUsage(sizeof(boost_unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
}
-// Dispatch to class method as fallback
-
-template<typename X>
-static inline size_t DynamicUsage(const X& x)
-{
- return x.DynamicMemoryUsage();
-}
-
}
#endif
diff --git a/src/miner.cpp b/src/miner.cpp
index f5919ca3af..e44f3392c8 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -6,20 +6,23 @@
#include "miner.h"
#include "amount.h"
+#include "chain.h"
#include "chainparams.h"
+#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "hash.h"
#include "main.h"
#include "net.h"
+#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
+#include "script/standard.h"
#include "timedata.h"
+#include "txmempool.h"
#include "util.h"
#include "utilmoneystr.h"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
+#include "validationinterface.h"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
@@ -362,7 +365,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
-#ifdef ENABLE_WALLET
//////////////////////////////////////////////////////////////////////////////
//
// Internal miner
@@ -401,17 +403,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas
}
}
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
-{
- CPubKey pubkey;
- if (!reservekey.GetReservedKey(pubkey))
- return NULL;
-
- CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
- return CreateNewBlock(scriptPubKey);
-}
-
-static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
@@ -423,14 +415,8 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
return error("BitcoinMiner: generated block is stale");
}
- // Remove key from key pool
- reservekey.KeepKey();
-
- // Track how many getdata requests this block gets
- {
- LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
- }
+ // Inform about the new block
+ GetMainSignals().BlockFound(pblock->GetHash());
// Process this block the same as if we had received it from another node
CValidationState state;
@@ -440,18 +426,22 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
return true;
}
-void static BitcoinMiner(CWallet *pwallet)
+void static BitcoinMiner(const CChainParams& chainparams)
{
LogPrintf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("bitcoin-miner");
- const CChainParams& chainparams = Params();
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
try {
+ //throw an error if no script was provided
+ if (!coinbaseScript->reserveScript.size())
+ throw std::runtime_error("No coinbase script available (mining requires a wallet)");
+
while (true) {
if (chainparams.MiningRequiresPeers()) {
// Busy-wait for the network to come online so we don't waste time mining
@@ -474,7 +464,7 @@ void static BitcoinMiner(CWallet *pwallet)
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip();
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
{
LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
@@ -506,8 +496,9 @@ void static BitcoinMiner(CWallet *pwallet)
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("BitcoinMiner:\n");
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- ProcessBlockFound(pblock, *pwallet, reservekey);
+ ProcessBlockFound(pblock, chainparams);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ coinbaseScript->KeepScript();
// In regression test mode, stop mining after a block is found.
if (chainparams.MineBlocksOnDemand())
@@ -551,17 +542,12 @@ void static BitcoinMiner(CWallet *pwallet)
}
}
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
+void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams)
{
static boost::thread_group* minerThreads = NULL;
- if (nThreads < 0) {
- // In regtest threads defaults to 1
- if (Params().DefaultMinerThreads())
- nThreads = Params().DefaultMinerThreads();
- else
- nThreads = boost::thread::hardware_concurrency();
- }
+ if (nThreads < 0)
+ nThreads = GetNumCores();
if (minerThreads != NULL)
{
@@ -575,7 +561,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
+ minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
}
-
-#endif // ENABLE_WALLET
diff --git a/src/miner.h b/src/miner.h
index 96a6b70ecd..777a091967 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -11,6 +11,7 @@
#include <stdint.h>
class CBlockIndex;
+class CChainParams;
class CReserveKey;
class CScript;
class CWallet;
@@ -24,10 +25,9 @@ struct CBlockTemplate
};
/** Run the miner threads */
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
+void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
diff --git a/src/net.cpp b/src/net.cpp
index 0511256e55..e4ead3c92e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -12,10 +12,12 @@
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
+#include "crypto/common.h"
+#include "hash.h"
#include "primitives/transaction.h"
#include "scheduler.h"
#include "ui_interface.h"
-#include "crypto/common.h"
+#include "utilstrencodings.h"
#ifdef WIN32
#include <string.h>
@@ -78,8 +80,10 @@ static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
-int nMaxConnections = 125;
+int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
+int nWhiteConnections = 0;
bool fAddressesInitialized = false;
+std::string strSubVersion;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@@ -385,6 +389,12 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
{
+ if (!IsSelectableSocket(hSocket)) {
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ CloseSocket(hSocket);
+ return NULL;
+ }
+
addrman.Attempt(addrConnect);
// Add node
@@ -436,20 +446,22 @@ void CNode::PushVersion()
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true);
+ nLocalHostNonce, strSubVersion, nBestHeight, true);
}
-std::map<CSubNet, int64_t> CNode::setBanned;
+banmap_t CNode::setBanned;
CCriticalSection CNode::cs_setBanned;
+bool CNode::setBannedIsDirty;
void CNode::ClearBanned()
{
LOCK(cs_setBanned);
setBanned.clear();
+ setBannedIsDirty = true;
}
bool CNode::IsBanned(CNetAddr ip)
@@ -457,12 +469,12 @@ bool CNode::IsBanned(CNetAddr ip)
bool fResult = false;
{
LOCK(cs_setBanned);
- for (std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); it != setBanned.end(); it++)
+ for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++)
{
CSubNet subNet = (*it).first;
- int64_t t = (*it).second;
+ CBanEntry banEntry = (*it).second;
- if(subNet.Match(ip) && GetTime() < t)
+ if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil)
fResult = true;
}
}
@@ -474,50 +486,99 @@ bool CNode::IsBanned(CSubNet subnet)
bool fResult = false;
{
LOCK(cs_setBanned);
- std::map<CSubNet, int64_t>::iterator i = setBanned.find(subnet);
+ banmap_t::iterator i = setBanned.find(subnet);
if (i != setBanned.end())
{
- int64_t t = (*i).second;
- if (GetTime() < t)
+ CBanEntry banEntry = (*i).second;
+ if (GetTime() < banEntry.nBanUntil)
fResult = true;
}
}
return fResult;
}
-void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
- Ban(subNet, bantimeoffset, sinceUnixEpoch);
+void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+ CSubNet subNet(addr);
+ Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
}
-void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) {
- int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
- if (bantimeoffset > 0)
- banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
+void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+ CBanEntry banEntry(GetTime());
+ banEntry.banReason = banReason;
+ if (bantimeoffset <= 0)
+ {
+ bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban
+ sinceUnixEpoch = false;
+ }
+ banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
+
LOCK(cs_setBanned);
- if (setBanned[subNet] < banTime)
- setBanned[subNet] = banTime;
+ if (setBanned[subNet].nBanUntil < banEntry.nBanUntil)
+ setBanned[subNet] = banEntry;
+
+ setBannedIsDirty = true;
}
bool CNode::Unban(const CNetAddr &addr) {
- CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
+ CSubNet subNet(addr);
return Unban(subNet);
}
bool CNode::Unban(const CSubNet &subNet) {
LOCK(cs_setBanned);
if (setBanned.erase(subNet))
+ {
+ setBannedIsDirty = true;
return true;
+ }
return false;
}
-void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap)
+void CNode::GetBanned(banmap_t &banMap)
{
LOCK(cs_setBanned);
banMap = setBanned; //create a thread safe copy
}
+void CNode::SetBanned(const banmap_t &banMap)
+{
+ LOCK(cs_setBanned);
+ setBanned = banMap;
+ setBannedIsDirty = true;
+}
+
+void CNode::SweepBanned()
+{
+ int64_t now = GetTime();
+
+ LOCK(cs_setBanned);
+ banmap_t::iterator it = setBanned.begin();
+ while(it != setBanned.end())
+ {
+ CBanEntry banEntry = (*it).second;
+ if(now > banEntry.nBanUntil)
+ {
+ setBanned.erase(it++);
+ setBannedIsDirty = true;
+ }
+ else
+ ++it;
+ }
+}
+
+bool CNode::BannedSetIsDirty()
+{
+ LOCK(cs_setBanned);
+ return setBannedIsDirty;
+}
+
+void CNode::SetBannedSetDirty(bool dirty)
+{
+ LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
+ setBannedIsDirty = dirty;
+}
+
std::vector<CSubNet> CNode::vWhitelistedRange;
CCriticalSection CNode::cs_vWhitelistedRange;
@@ -877,6 +938,7 @@ void ThreadSocketHandler()
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
+ int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@@ -896,8 +958,19 @@ void ThreadSocketHandler()
if (nErr != WSAEWOULDBLOCK)
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
}
- else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
+ else if (!IsSelectableSocket(hSocket))
+ {
+ LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
+ CloseSocket(hSocket);
+ }
+ else if (nInbound >= nMaxInbound)
{
+ LogPrint("net", "connection from %s dropped (full)\n", addr.ToString());
+ CloseSocket(hSocket);
+ }
+ else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections)))
+ {
+ LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString());
CloseSocket(hSocket);
}
else if (CNode::IsBanned(addr) && !whitelisted)
@@ -911,6 +984,8 @@ void ThreadSocketHandler()
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
+ LogPrint("net", "connection from %s accepted\n", addr.ToString());
+
{
LOCK(cs_vNodes);
vNodes.push_back(pnode);
@@ -1212,6 +1287,17 @@ void DumpAddresses()
addrman.size(), GetTimeMillis() - nStart);
}
+void DumpData()
+{
+ DumpAddresses();
+
+ if (CNode::BannedSetIsDirty())
+ {
+ DumpBanlist();
+ CNode::SetBannedSetDirty(false);
+ }
+}
+
void static ProcessOneShot()
{
string strDest;
@@ -1525,6 +1611,13 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
LogPrintf("%s\n", strError);
return false;
}
+ if (!IsSelectableSocket(hListenSocket))
+ {
+ strError = "Error: Couldn't create a listenable socket for incoming connections";
+ LogPrintf("%s\n", strError);
+ return false;
+ }
+
#ifndef WIN32
#ifdef SO_NOSIGPIPE
@@ -1650,6 +1743,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!adb.Read(addrman))
LogPrintf("Invalid or missing peers.dat; recreating\n");
}
+
+ //try to read stored banlist
+ CBanDB bandb;
+ banmap_t banmap;
+ if (!bandb.Read(banmap))
+ LogPrintf("Invalid or missing banlist.dat; recreating\n");
+
+ CNode::SetBanned(banmap); //thread save setter
+ CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data
+ CNode::SweepBanned(); //sweap out unused entries
+
LogPrintf("Loaded %i addresses from peers.dat %dms\n",
addrman.size(), GetTimeMillis() - nStart);
fAddressesInitialized = true;
@@ -1690,7 +1794,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
// Dump network addresses
- scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL);
+ scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL);
}
bool StopNode()
@@ -1703,7 +1807,7 @@ bool StopNode()
if (fAddressesInitialized)
{
- DumpAddresses();
+ DumpData();
fAddressesInitialized = false;
}
@@ -1907,11 +2011,11 @@ bool CAddrDB::Read(CAddrMan& addr)
return error("%s: Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer
- int fileSize = boost::filesystem::file_size(pathAddr);
- int dataSize = fileSize - sizeof(uint256);
+ uint64_t fileSize = boost::filesystem::file_size(pathAddr);
+ uint64_t dataSize = 0;
// Don't try to resize to a negative number if file is small
- if (dataSize < 0)
- dataSize = 0;
+ if (fileSize >= sizeof(uint256))
+ dataSize = fileSize - sizeof(uint256);
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -1957,7 +2061,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
- addrKnown(5000, 0.001, insecure_rand()),
+ addrKnown(5000, 0.001),
setInventoryKnown(SendBufferSize() / 1000)
{
nServices = 0;
@@ -2082,8 +2186,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
Fuzz(GetArg("-fuzzmessagestest", 10));
if (ssSend.size() == 0)
+ {
+ LEAVE_CRITICAL_SECTION(cs_vSend);
return;
-
+ }
// Set the size
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
@@ -2107,3 +2213,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
LEAVE_CRITICAL_SECTION(cs_vSend);
}
+
+//
+// CBanDB
+//
+
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
+
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("banlist.dat.%04x", randv);
+
+ // serialize banlist, checksum data up to that point, then append csum
+ CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
+ ssBanlist << FLATDATA(Params().MessageStart());
+ ssBanlist << banSet;
+ uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
+ ssBanlist << hash;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
+ if (fileout.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathTmp.string());
+
+ // Write and commit header, data
+ try {
+ fileout << ssBanlist;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing banlist.dat, if any, with new banlist.dat.XXXX
+ if (!RenameOver(pathTmp, pathBanlist))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CBanDB::Read(banmap_t& banSet)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathBanlist.string().c_str(), "rb");
+ CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathBanlist.string());
+
+ // use file size to size memory buffer
+ uint64_t fileSize = boost::filesystem::file_size(pathBanlist);
+ uint64_t dataSize = 0;
+ // Don't try to resize to a negative number if file is small
+ if (fileSize >= sizeof(uint256))
+ dataSize = fileSize - sizeof(uint256);
+ vector<unsigned char> vchData;
+ vchData.resize(dataSize);
+ uint256 hashIn;
+
+ // read data and checksum from file
+ try {
+ filein.read((char *)&vchData[0], dataSize);
+ filein >> hashIn;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+ filein.fclose();
+
+ CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION);
+
+ // verify stored checksum matches input data
+ uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end());
+ if (hashIn != hashTmp)
+ return error("%s: Checksum mismatch, data corrupted", __func__);
+
+ unsigned char pchMsgTmp[4];
+ try {
+ // de-serialize file header (network specific magic number) and ..
+ ssBanlist >> FLATDATA(pchMsgTmp);
+
+ // ... verify the network matches ours
+ if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
+ return error("%s: Invalid network magic number", __func__);
+
+ // de-serialize address data into one CAddrMan object
+ ssBanlist >> banSet;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+void DumpBanlist()
+{
+ int64_t nStart = GetTimeMillis();
+
+ CNode::SweepBanned(); //clean unused entires (if bantime has expired)
+
+ CBanDB bandb;
+ banmap_t banmap;
+ CNode::GetBanned(banmap);
+ bandb.Write(banmap);
+
+ LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+}
diff --git a/src/net.h b/src/net.h
index 69e4c592a9..efa2e29bb5 100644
--- a/src/net.h
+++ b/src/net.h
@@ -8,7 +8,6 @@
#include "bloom.h"
#include "compat.h"
-#include "hash.h"
#include "limitedmap.h"
#include "mruset.h"
#include "netbase.h"
@@ -17,7 +16,6 @@
#include "streams.h"
#include "sync.h"
#include "uint256.h"
-#include "utilstrencodings.h"
#include <deque>
#include <stdint.h>
@@ -31,7 +29,6 @@
#include <boost/signals2/signal.hpp>
class CAddrMan;
-class CBlockIndex;
class CScheduler;
class CNode;
@@ -49,6 +46,8 @@ static const unsigned int MAX_INV_SZ = 50000;
static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
+/** Maximum length of strSubVer in `version` message */
+static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -59,6 +58,8 @@ static const bool DEFAULT_UPNP = false;
#endif
/** The maximum number of entries in mapAskFor */
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
+/** The maximum number of peer connections to maintain. */
+static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
@@ -141,7 +142,20 @@ extern bool fListen;
extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
+
+// The allocation of connections against the maximum allowed (nMaxConnections)
+// is prioritized as follows:
+// 1st: Outbound connections (MAX_OUTBOUND_CONNECTIONS)
+// 2nd: Inbound connections from whitelisted peers (nWhiteConnections)
+// 3rd: Inbound connections from non-whitelisted peers
+// Thus, the number of connection slots for the general public to use is:
+// nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + nWhiteConnections)
+// Any additional inbound connections beyond limits will be immediately closed
+
+/** Maximum number of connections to simultaneously allow (aka connection slots) */
extern int nMaxConnections;
+/** Number of connection slots to reserve for inbound from whitelisted peers */
+extern int nWhiteConnections;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
@@ -156,6 +170,9 @@ extern CCriticalSection cs_vAddedNodes;
extern NodeId nLastNodeId;
extern CCriticalSection cs_nLastNodeId;
+/** Subversion as sent to the P2P network in `version` messages */
+extern std::string strSubVersion;
+
struct LocalServiceInfo {
int nScore;
int nPort;
@@ -228,8 +245,66 @@ public:
};
+typedef enum BanReason
+{
+ BanReasonUnknown = 0,
+ BanReasonNodeMisbehaving = 1,
+ BanReasonManuallyAdded = 2
+} BanReason;
+
+class CBanEntry
+{
+public:
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ int64_t nCreateTime;
+ int64_t nBanUntil;
+ uint8_t banReason;
+
+ CBanEntry()
+ {
+ SetNull();
+ }
+
+ CBanEntry(int64_t nCreateTimeIn)
+ {
+ SetNull();
+ nCreateTime = nCreateTimeIn;
+ }
+ ADD_SERIALIZE_METHODS;
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(nCreateTime);
+ READWRITE(nBanUntil);
+ READWRITE(banReason);
+ }
+
+ void SetNull()
+ {
+ nVersion = CBanEntry::CURRENT_VERSION;
+ nCreateTime = 0;
+ nBanUntil = 0;
+ banReason = BanReasonUnknown;
+ }
+
+ std::string banReasonToString()
+ {
+ switch (banReason) {
+ case BanReasonNodeMisbehaving:
+ return "node misbehabing";
+ case BanReasonManuallyAdded:
+ return "manually added";
+ default:
+ return "unknown";
+ }
+ }
+};
+
+typedef std::map<CSubNet, CBanEntry> banmap_t;
/** Information about a peer */
class CNode
@@ -285,8 +360,9 @@ protected:
// Denial-of-service detection/prevention
// Key is IP address, value is banned-until-time
- static std::map<CSubNet, int64_t> setBanned;
+ static banmap_t setBanned;
static CCriticalSection cs_setBanned;
+ static bool setBannedIsDirty;
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
@@ -608,11 +684,19 @@ public:
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
static bool IsBanned(CSubNet subnet);
- static void Ban(const CNetAddr &ip, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- static void Ban(const CSubNet &subNet, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
static bool Unban(const CNetAddr &ip);
static bool Unban(const CSubNet &ip);
- static void GetBanned(std::map<CSubNet, int64_t> &banmap);
+ static void GetBanned(banmap_t &banmap);
+ static void SetBanned(const banmap_t &banmap);
+
+ //!check is the banlist has unwritten changes
+ static bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ static void SetBannedSetDirty(bool dirty=true);
+ //!clean unused entires (if bantime has expired)
+ static void SweepBanned();
void copyStats(CNodeStats &stats);
@@ -644,4 +728,17 @@ public:
bool Read(CAddrMan& addr);
};
+/** Access to the banlist database (banlist.dat) */
+class CBanDB
+{
+private:
+ boost::filesystem::path pathBanlist;
+public:
+ CBanDB();
+ bool Write(const banmap_t& banSet);
+ bool Read(banmap_t& banSet);
+};
+
+void DumpBanlist();
+
#endif // BITCOIN_NET_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index adac5c2d07..b7e2e57917 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -266,6 +266,9 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
} else { // Other error or blocking
int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
+ if (!IsSelectableSocket(hSocket)) {
+ return false;
+ }
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset;
FD_ZERO(&fdset);
@@ -1291,6 +1294,13 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
network.ip[x] &= netmask[x];
}
+CSubNet::CSubNet(const CNetAddr &addr):
+ valid(addr.IsValid())
+{
+ memset(netmask, 255, sizeof(netmask));
+ network = addr;
+}
+
bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid())
diff --git a/src/netbase.h b/src/netbase.h
index 27f0eac2a2..6f8882b852 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -118,6 +118,9 @@ class CSubNet
CSubNet();
explicit CSubNet(const std::string &strSubnet, bool fAllowLookup = false);
+ //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ explicit CSubNet(const CNetAddr &addr);
+
bool Match(const CNetAddr &addr) const;
std::string ToString() const;
@@ -126,6 +129,15 @@ class CSubNet
friend bool operator==(const CSubNet& a, const CSubNet& b);
friend bool operator!=(const CSubNet& a, const CSubNet& b);
friend bool operator<(const CSubNet& a, const CSubNet& b);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(network);
+ READWRITE(FLATDATA(netmask));
+ READWRITE(FLATDATA(valid));
+ }
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index b1491cec01..cdee541d2f 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -249,7 +249,7 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
unsigned int bucketindex = bucketMap.lower_bound(val)->second;
unsigned int blockIndex = nBlockHeight % unconfTxs.size();
unconfTxs[blockIndex][bucketindex]++;
- LogPrint("estimatefee", "adding to %s\n", dataTypeString);
+ LogPrint("estimatefee", "adding to %s", dataTypeString);
return bucketindex;
}
@@ -390,8 +390,9 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
}
else {
- LogPrint("estimatefee", "not adding\n");
+ LogPrint("estimatefee", "not adding");
}
+ LogPrint("estimatefee", "\n");
}
void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
new file mode 100644
index 0000000000..169fef4af4
--- /dev/null
+++ b/src/policy/policy.cpp
@@ -0,0 +1,178 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
+
+#include "policy/policy.h"
+
+#include "main.h"
+#include "tinyformat.h"
+#include "util.h"
+#include "utilstrencodings.h"
+
+#include <boost/foreach.hpp>
+
+ /**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 2. P2SH scripts with a crazy number of expensive
+ * CHECKSIG/CHECKMULTISIG operations
+ *
+ * Check transaction inputs, and make sure any
+ * pay-to-script-hash transactions are evaluating IsStandard scripts
+ *
+ * Why bother? To avoid denial-of-service attacks; an attacker
+ * can submit a standard HASH... OP_EQUAL transaction,
+ * which will get accepted into blocks. The redemption
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
+
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
+{
+ std::vector<std::vector<unsigned char> > vSolutions;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_MULTISIG)
+ {
+ unsigned char m = vSolutions.front()[0];
+ unsigned char n = vSolutions.back()[0];
+ // Support up to x-of-3 multisig txns as standard
+ if (n < 1 || n > 3)
+ return false;
+ if (m < 1 || m > n)
+ return false;
+ }
+
+ return whichType != TX_NONSTANDARD;
+}
+
+bool IsStandardTx(const CTransaction& tx, std::string& reason)
+{
+ if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
+ reason = "version";
+ return false;
+ }
+
+ // Extremely large transactions with lots of inputs can cost the network
+ // almost as much to process as they cost the sender in fees, because
+ // computing signature hashes is O(ninputs*txsize). Limiting transactions
+ // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
+ unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
+ if (sz >= MAX_STANDARD_TX_SIZE) {
+ reason = "tx-size";
+ return false;
+ }
+
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
+ // keys. (remember the 520 byte limit on redeemScript size) That works
+ // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
+ // bytes of scriptSig, which we round off to 1650 bytes for some minor
+ // future-proofing. That's also enough to spend a 20-of-20
+ // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
+ // considered standard)
+ if (txin.scriptSig.size() > 1650) {
+ reason = "scriptsig-size";
+ return false;
+ }
+ if (!txin.scriptSig.IsPushOnly()) {
+ reason = "scriptsig-not-pushonly";
+ return false;
+ }
+ }
+
+ unsigned int nDataOut = 0;
+ txnouttype whichType;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout) {
+ if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ reason = "scriptpubkey";
+ return false;
+ }
+
+ if (whichType == TX_NULL_DATA)
+ nDataOut++;
+ else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
+ reason = "bare-multisig";
+ return false;
+ } else if (txout.IsDust(::minRelayTxFee)) {
+ reason = "dust";
+ return false;
+ }
+ }
+
+ // only one OP_RETURN txout is permitted
+ if (nDataOut > 1) {
+ reason = "multi-op-return";
+ return false;
+ }
+
+ return true;
+}
+
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+{
+ if (tx.IsCoinBase())
+ return true; // Coinbases don't use vin normally
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
+
+ std::vector<std::vector<unsigned char> > vSolutions;
+ txnouttype whichType;
+ // get the scriptPubKey corresponding to this input:
+ const CScript& prevScript = prev.scriptPubKey;
+ if (!Solver(prevScript, whichType, vSolutions))
+ return false;
+ int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+ if (nArgsExpected < 0)
+ return false;
+
+ // Transactions with extra stuff in their scriptSigs are
+ // non-standard. Note that this EvalScript() call will
+ // be quick, because if there are any operations
+ // beside "push data" in the scriptSig
+ // IsStandardTx() will have already returned false
+ // and this method isn't called.
+ std::vector<std::vector<unsigned char> > stack;
+ if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
+ return false;
+
+ if (whichType == TX_SCRIPTHASH)
+ {
+ if (stack.empty())
+ return false;
+ CScript subscript(stack.back().begin(), stack.back().end());
+ std::vector<std::vector<unsigned char> > vSolutions2;
+ txnouttype whichType2;
+ if (Solver(subscript, whichType2, vSolutions2))
+ {
+ int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
+ }
+ else
+ {
+ // Any other Script with less than 15 sigops OK:
+ unsigned int sigops = subscript.GetSigOpCount(true);
+ // ... extra data left on the stack after execution is OK, too:
+ return (sigops <= MAX_P2SH_SIGOPS);
+ }
+ }
+
+ if (stack.size() != (unsigned int)nArgsExpected)
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/policy/policy.h b/src/policy/policy.h
new file mode 100644
index 0000000000..1551aecde8
--- /dev/null
+++ b/src/policy/policy.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_POLICY_H
+#define BITCOIN_POLICY_H
+
+#include "consensus/consensus.h"
+#include "script/interpreter.h"
+#include "script/standard.h"
+
+#include <string>
+
+class CCoinsViewCache;
+
+/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
+static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
+static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
+/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
+static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
+/** The maximum size for transactions we're willing to relay/mine */
+static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
+/** Maximum number of signature check operations in an IsStandard() P2SH script */
+static const unsigned int MAX_P2SH_SIGOPS = 15;
+/** The maximum number of sigops we're willing to relay/mine in a single tx */
+static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
+/**
+ * Standard script verification flags that standard transactions will comply
+ * with. However scripts violating these flags may still be present in valid
+ * blocks and we must accept those blocks.
+ */
+static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
+ SCRIPT_VERIFY_DERSIG |
+ SCRIPT_VERIFY_STRICTENC |
+ SCRIPT_VERIFY_MINIMALDATA |
+ SCRIPT_VERIFY_NULLDUMMY |
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
+ SCRIPT_VERIFY_CLEANSTACK |
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+
+/** For convenience, standard but not mandatory verify flags. */
+static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
+
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
+ /**
+ * Check for standard transaction types
+ * @return True if all outputs (scriptPubKeys) use only standard transaction forms
+ */
+bool IsStandardTx(const CTransaction& tx, std::string& reason);
+ /**
+ * Check for standard transaction types
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return True if all inputs (scriptSigs) use only standard transaction forms
+ */
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+
+#endif // BITCOIN_POLICY_H
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 6cfd93a9a1..2a457cdae7 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -141,10 +141,13 @@ public:
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
- // A typical txout is 34 bytes big, and will
+ // A typical spendable txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
- // so dust is a txout less than 546 satoshis
+ // so dust is a spendable txout less than 546 satoshis
// with default minRelayTxFee.
+ if (scriptPubKey.IsUnspendable())
+ return 0;
+
size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
return 3*minRelayTxFee.GetFee(nSize);
}
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 5485d89f3e..8bd1586446 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -14,14 +14,14 @@
#include "csvmodelwriter.h"
#include "editaddressdialog.h"
#include "guiutil.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>
-AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
+AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
@@ -30,17 +30,17 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->newAddress->setIcon(QIcon());
- ui->copyAddress->setIcon(QIcon());
- ui->deleteAddress->setIcon(QIcon());
- ui->exportButton->setIcon(QIcon());
-#else
- ui->newAddress->setIcon(SingleColorIcon(":/icons/add"));
- ui->copyAddress->setIcon(SingleColorIcon(":/icons/editcopy"));
- ui->deleteAddress->setIcon(SingleColorIcon(":/icons/remove"));
- ui->exportButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->newAddress->setIcon(QIcon());
+ ui->copyAddress->setIcon(QIcon());
+ ui->deleteAddress->setIcon(QIcon());
+ ui->exportButton->setIcon(QIcon());
+ } else {
+ ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
+ ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
+ ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
switch(mode)
{
@@ -254,8 +254,7 @@ void AddressBookPage::done(int retval)
// Figure out which address was selected, and return it
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
- foreach (QModelIndex index, indexes)
- {
+ Q_FOREACH (const QModelIndex& index, indexes) {
QVariant address = table->model()->data(index);
returnValue = address.toString();
}
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index 5105f09ced..92e6cab9ac 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -9,6 +9,7 @@
class AddressTableModel;
class OptionsModel;
+class PlatformStyle;
namespace Ui {
class AddressBookPage;
@@ -39,13 +40,13 @@ public:
ForEditing /**< Open address book for editing */
};
- explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent);
+ explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent);
~AddressBookPage();
void setModel(AddressTableModel *model);
const QString &getReturnValue() const { return returnValue; }
-public slots:
+public Q_SLOTS:
void done(int retval);
private:
@@ -59,7 +60,7 @@ private:
QAction *deleteAction; // to be able to explicitly disable it
QString newAddressToSelect;
-private slots:
+private Q_SLOTS:
/** Delete currently selected address entry */
void on_deleteAddress_clicked();
/** Create a new address for receiving coins and / or add a new address book entry */
@@ -80,7 +81,7 @@ private slots:
/** New entry/entries were added to address table */
void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/);
-signals:
+Q_SIGNALS:
void sendCoins(QString addr);
};
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 8e20836c65..c5ac07cfc2 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -450,5 +450,5 @@ int AddressTableModel::lookupAddress(const QString &address) const
void AddressTableModel::emitDataChanged(int idx)
{
- emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
+ Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 6b34b2eac2..2b7475c4e2 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -84,7 +84,7 @@ private:
/** Notify listeners that data changed. */
void emitDataChanged(int index);
-public slots:
+public Q_SLOTS:
/* Update address list from core.
*/
void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 74d54d18f7..d4d832825a 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -40,7 +40,7 @@ private:
WalletModel *model;
bool fCapsLock;
-private slots:
+private Q_SLOTS:
void textChanged();
protected:
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 8740b98b70..1da2d3e344 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -8,12 +8,14 @@
#include "bitcoingui.h"
+#include "chainparams.h"
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
#include "networkstyle.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "splashscreen.h"
#include "utilitydialog.h"
#include "winshutdownmonitor.h"
@@ -24,7 +26,6 @@
#endif
#include "init.h"
-#include "main.h"
#include "rpcserver.h"
#include "scheduler.h"
#include "ui_interface.h"
@@ -48,6 +49,7 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
+#include <QSslConfiguration>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -58,7 +60,9 @@ Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#else
+#if QT_VERSION < 0x050400
Q_IMPORT_PLUGIN(AccessibleFactory)
+#endif
#if defined(QT_QPA_PLATFORM_XCB)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
#elif defined(QT_QPA_PLATFORM_WINDOWS)
@@ -168,11 +172,11 @@ class BitcoinCore: public QObject
public:
explicit BitcoinCore();
-public slots:
+public Q_SLOTS:
void initialize();
void shutdown();
-signals:
+Q_SIGNALS:
void initializeResult(int retval);
void shutdownResult(int retval);
void runawayException(const QString &message);
@@ -215,13 +219,13 @@ public:
/// Get window identifier of QMainWindow (BitcoinGUI)
WId getMainWinId() const;
-public slots:
+public Q_SLOTS:
void initializeResult(int retval);
void shutdownResult(int retval);
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
-signals:
+Q_SIGNALS:
void requestedInitialize();
void requestedShutdown();
void stopThread();
@@ -238,6 +242,7 @@ private:
WalletModel *walletModel;
#endif
int returnValue;
+ const PlatformStyle *platformStyle;
void startThread();
};
@@ -252,7 +257,7 @@ BitcoinCore::BitcoinCore():
void BitcoinCore::handleRunawayException(const std::exception *e)
{
PrintExceptionContinue(e, "Runaway exception");
- emit runawayException(QString::fromStdString(strMiscWarning));
+ Q_EMIT runawayException(QString::fromStdString(strMiscWarning));
}
void BitcoinCore::initialize()
@@ -268,7 +273,7 @@ void BitcoinCore::initialize()
*/
StartDummyRPCThread();
}
- emit initializeResult(rv);
+ Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
@@ -285,7 +290,7 @@ void BitcoinCore::shutdown()
threadGroup.join_all();
Shutdown();
qDebug() << __func__ << ": Shutdown finished";
- emit shutdownResult(1);
+ Q_EMIT shutdownResult(1);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
@@ -307,6 +312,22 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv):
returnValue(0)
{
setQuitOnLastWindowClosed(false);
+
+ // UI per-platform customization
+ // This must be done inside the BitcoinApplication constructor, or after it, because
+ // PlatformStyle::instantiate requires a QApplication
+#if defined(Q_OS_MAC)
+ std::string platformName = "macosx";
+#elif defined(Q_OS_WIN)
+ std::string platformName = "windows";
+#else
+ std::string platformName = "other";
+#endif
+ platformName = GetArg("-uiplatform", platformName);
+ platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
+ if (!platformStyle) // Fall back to "other" if specified name not found
+ platformStyle = PlatformStyle::instantiate("other");
+ assert(platformStyle);
}
BitcoinApplication::~BitcoinApplication()
@@ -314,7 +335,7 @@ BitcoinApplication::~BitcoinApplication()
if(coreThread)
{
qDebug() << __func__ << ": Stopping thread";
- emit stopThread();
+ Q_EMIT stopThread();
coreThread->wait();
qDebug() << __func__ << ": Stopped thread";
}
@@ -327,6 +348,8 @@ BitcoinApplication::~BitcoinApplication()
#endif
delete optionsModel;
optionsModel = 0;
+ delete platformStyle;
+ platformStyle = 0;
}
#ifdef ENABLE_WALLET
@@ -343,7 +366,7 @@ void BitcoinApplication::createOptionsModel()
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
{
- window = new BitcoinGUI(networkStyle, 0);
+ window = new BitcoinGUI(platformStyle, networkStyle, 0);
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
@@ -385,7 +408,7 @@ void BitcoinApplication::requestInitialize()
{
qDebug() << __func__ << ": Requesting initialize";
startThread();
- emit requestedInitialize();
+ Q_EMIT requestedInitialize();
}
void BitcoinApplication::requestShutdown()
@@ -408,7 +431,7 @@ void BitcoinApplication::requestShutdown()
ShutdownWindow::showShutdownWindow(window);
// Request shutdown from core thread
- emit requestedShutdown();
+ Q_EMIT requestedShutdown();
}
void BitcoinApplication::initializeResult(int retval)
@@ -418,6 +441,8 @@ void BitcoinApplication::initializeResult(int retval)
returnValue = retval ? 0 : 1;
if(retval)
{
+ // Log this only after AppInit2 finishes, as then logging setup is guaranteed complete
+ qWarning() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
PaymentServer::LoadRootCAs();
paymentServer->setOptionsModel(optionsModel);
@@ -429,7 +454,7 @@ void BitcoinApplication::initializeResult(int retval)
#ifdef ENABLE_WALLET
if(pwalletMain)
{
- walletModel = new WalletModel(pwalletMain, optionsModel);
+ walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel);
window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
@@ -448,7 +473,7 @@ void BitcoinApplication::initializeResult(int retval)
{
window->show();
}
- emit splashFinished(window);
+ Q_EMIT splashFinished(window);
#ifdef ENABLE_WALLET
// Now that initialization/startup is done, process any command-line
@@ -515,6 +540,13 @@ int main(int argc, char *argv[])
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
+#if QT_VERSION >= 0x050500
+ // Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/),
+ // so set SSL protocols to TLS1.0+.
+ QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration();
+ sslconf.setProtocol(QSsl::TlsV1_0OrLater);
+ QSslConfiguration::setDefaultConfiguration(sslconf);
+#endif
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index d31a1e018b..d19b9fd4af 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -61,7 +61,7 @@ public:
void setValue(const CAmount& value)
{
lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways));
- emit valueChanged();
+ Q_EMIT valueChanged();
}
void stepBy(int steps)
@@ -184,7 +184,7 @@ protected:
return rv;
}
-signals:
+Q_SIGNALS:
void valueChanged();
};
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index b047e6c51a..3703b1f8d7 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -56,7 +56,7 @@ public:
*/
QWidget *setupTabChain(QWidget *prev);
-signals:
+Q_SIGNALS:
void valueChanged();
protected:
@@ -67,7 +67,7 @@ private:
AmountSpinBox *amount;
QValueComboBox *unit;
-private slots:
+private Q_SLOTS:
void unitChanged(int idx);
};
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index efba0f5e18..1d3f7762ab 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -13,8 +13,8 @@
#include "openuridialog.h"
#include "optionsdialog.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "rpcconsole.h"
-#include "scicon.h"
#include "utilitydialog.h"
#ifdef ENABLE_WALLET
@@ -60,7 +60,7 @@
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
walletFrame(0),
@@ -98,7 +98,8 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
notificator(0),
rpcConsole(0),
prevBlocks(0),
- spinnerFrame(0)
+ spinnerFrame(0),
+ platformStyle(platformStyle)
{
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
@@ -130,12 +131,12 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
setUnifiedTitleAndToolBarOnMac(true);
#endif
- rpcConsole = new RPCConsole(0);
+ rpcConsole = new RPCConsole(platformStyle, 0);
#ifdef ENABLE_WALLET
if(enableWallet)
{
/** Create wallet frame and make it the central widget */
- walletFrame = new WalletFrame(this);
+ walletFrame = new WalletFrame(platformStyle, this);
setCentralWidget(walletFrame);
} else
#endif // ENABLE_WALLET
@@ -175,7 +176,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
- unitDisplayControl = new UnitDisplayStatusBarControl();
+ unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
@@ -247,36 +248,36 @@ void BitcoinGUI::createActions()
{
QActionGroup *tabGroup = new QActionGroup(this);
- overviewAction = new QAction(SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
+ overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
overviewAction->setStatusTip(tr("Show general overview of wallet"));
overviewAction->setToolTip(overviewAction->statusTip());
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
- sendCoinsAction = new QAction(SingleColorIcon(":/icons/send"), tr("&Send"), this);
+ sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
- sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
+ sendCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
- receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
+ receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
- receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
+ receiveCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
- historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
+ historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setStatusTip(tr("Browse transaction history"));
historyAction->setToolTip(historyAction->statusTip());
historyAction->setCheckable(true);
@@ -300,46 +301,46 @@ void BitcoinGUI::createActions()
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
#endif // ENABLE_WALLET
- quitAction = new QAction(TextColorIcon(":/icons/quit"), tr("E&xit"), this);
+ quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this);
+ aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin Core"));
aboutAction->setMenuRole(QAction::AboutRole);
- aboutQtAction = new QAction(TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
+ aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
- optionsAction = new QAction(TextColorIcon(":/icons/options"), tr("&Options..."), this);
+ optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin Core"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- toggleHideAction = new QAction(TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
+ toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
- encryptWalletAction = new QAction(TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
+ encryptWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
encryptWalletAction->setCheckable(true);
- backupWalletAction = new QAction(TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
+ backupWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
- changePassphraseAction = new QAction(TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
+ changePassphraseAction = new QAction(platformStyle->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
- signMessageAction = new QAction(TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
+ signMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
- verifyMessageAction = new QAction(TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
+ verifyMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
- openRPCConsoleAction = new QAction(TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
+ openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
- usedSendingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
+ usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
- usedReceivingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
+ usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
- openAction = new QAction(TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
+ openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
- showHelpMessageAction = new QAction(TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
+ showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options"));
@@ -600,7 +601,7 @@ void BitcoinGUI::openClicked()
OpenURIDialog dlg(this);
if(dlg.exec())
{
- emit receivedURI(dlg.getURI());
+ Q_EMIT receivedURI(dlg.getURI());
}
}
@@ -650,7 +651,7 @@ void BitcoinGUI::setNumConnections(int count)
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
default: icon = ":/icons/connect_4"; break;
}
- labelConnectionsIcon->setPixmap(SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelConnectionsIcon->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
@@ -691,7 +692,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
if(secs < 90*60)
{
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
- labelBlocksIcon->setPixmap(SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
+ labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
#ifdef ENABLE_WALLET
if(walletFrame)
@@ -737,7 +738,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
if(count != prevBlocks)
{
- labelBlocksIcon->setPixmap(SingleColorIcon(QString(
+ labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(QString(
":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
.pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
@@ -886,9 +887,9 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls())
{
- foreach(const QUrl &uri, event->mimeData()->urls())
+ Q_FOREACH(const QUrl &uri, event->mimeData()->urls())
{
- emit receivedURI(uri.toString());
+ Q_EMIT receivedURI(uri.toString());
}
}
event->acceptProposedAction();
@@ -931,7 +932,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
case WalletModel::Unlocked:
labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
@@ -939,7 +940,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
case WalletModel::Locked:
labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
@@ -1041,7 +1042,7 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
-UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
optionsModel(0),
menu(0)
{
@@ -1050,13 +1051,13 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
int max_width = 0;
const QFontMetrics fm(font());
- foreach (const BitcoinUnits::Unit unit, units)
+ Q_FOREACH (const BitcoinUnits::Unit unit, units)
{
max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit)));
}
setMinimumSize(max_width, 0);
setAlignment(Qt::AlignRight | Qt::AlignVCenter);
- setStyleSheet(QString("QLabel { color : %1 }").arg(SingleColor().name()));
+ setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle->SingleColor().name()));
}
/** So that it responds to button clicks */
@@ -1069,7 +1070,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
void UnitDisplayStatusBarControl::createContextMenu()
{
menu = new QMenu();
- foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
menuAction->setData(QVariant(u));
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 494541f002..dd0d4bb0e2 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -22,6 +22,7 @@ class ClientModel;
class NetworkStyle;
class Notificator;
class OptionsModel;
+class PlatformStyle;
class RPCConsole;
class SendCoinsRecipient;
class UnitDisplayStatusBarControl;
@@ -47,7 +48,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
- explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0);
+ explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
@@ -117,6 +118,8 @@ private:
int prevBlocks;
int spinnerFrame;
+ const PlatformStyle *platformStyle;
+
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and sub-menus. */
@@ -136,11 +139,11 @@ private:
/** Disconnect core signals from GUI client */
void unsubscribeFromCoreSignals();
-signals:
+Q_SIGNALS:
/** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri);
-public slots:
+public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
@@ -168,7 +171,7 @@ public slots:
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label);
#endif // ENABLE_WALLET
-private slots:
+private Q_SLOTS:
#ifdef ENABLE_WALLET
/** Switch to overview (home) page */
void gotoOverviewPage();
@@ -215,7 +218,7 @@ class UnitDisplayStatusBarControl : public QLabel
Q_OBJECT
public:
- explicit UnitDisplayStatusBarControl();
+ explicit UnitDisplayStatusBarControl(const PlatformStyle *platformStyle);
/** Lets the control know about the Options Model (and its signals) */
void setOptionsModel(OptionsModel *optionsModel);
@@ -232,7 +235,7 @@ private:
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
void createContextMenu();
-private slots:
+private Q_SLOTS:
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
void updateDisplayUnit(int newUnits);
/** Tells underlying optionsModel to update its current display unit. */
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 8e29cdeb06..41dc2ea77e 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -11,7 +11,6 @@
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
-#include "main.h"
#include "net.h"
#include "ui_interface.h"
#include "util.h"
@@ -53,9 +52,9 @@ int ClientModel::getNumConnections(unsigned int flags) const
return vNodes.size();
int nNum = 0;
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
- nNum++;
+ BOOST_FOREACH(const CNode* pnode, vNodes)
+ if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
+ nNum++;
return nNum;
}
@@ -117,15 +116,15 @@ void ClientModel::updateTimer()
cachedReindexing = fReindex;
cachedImporting = fImporting;
- emit numBlocksChanged(newNumBlocks, newBlockDate);
+ Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate);
}
- emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
+ Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
void ClientModel::updateNumConnections(int numConnections)
{
- emit numConnectionsChanged(numConnections);
+ Q_EMIT numConnectionsChanged(numConnections);
}
void ClientModel::updateAlert(const QString &hash, int status)
@@ -138,11 +137,11 @@ void ClientModel::updateAlert(const QString &hash, int status)
CAlert alert = CAlert::getAlertByHash(hash_256);
if(!alert.IsNull())
{
- emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
+ Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
}
}
- emit alertsChanged(getStatusBarWarnings());
+ Q_EMIT alertsChanged(getStatusBarWarnings());
}
bool ClientModel::inInitialBlockDownload() const
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 214701810c..68434f404c 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -82,7 +82,7 @@ private:
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
-signals:
+Q_SIGNALS:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, const QDateTime& blockDate);
void alertsChanged(const QString &warnings);
@@ -94,7 +94,7 @@ signals:
// Show progress dialog e.g. for verifychain
void showProgress(const QString &title, int nProgress);
-public slots:
+public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status);
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7531fbddcb..51008ad2de 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -9,12 +9,13 @@
#include "bitcoinunits.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
+#include "txmempool.h"
#include "walletmodel.h"
#include "coincontrol.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "wallet/wallet.h"
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
@@ -30,15 +31,15 @@
#include <QTreeWidget>
#include <QTreeWidgetItem>
-using namespace std;
QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
bool CoinControlDialog::fSubtractFeeFromAmount = false;
-CoinControlDialog::CoinControlDialog(QWidget *parent) :
+CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::CoinControlDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
@@ -118,7 +119,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) :
// (un)select all
connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
- // change coin control first column label due Qt4 bug.
+ // change coin control first column label due Qt4 bug.
// see https://github.com/bitcoin/bitcoin/issues/5716
ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
@@ -280,7 +281,7 @@ void CoinControlDialog::lockCoin()
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
model->lockCoin(outpt);
contextMenuItem->setDisabled(true);
- contextMenuItem->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed"));
+ contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
updateLabelLocked();
}
@@ -442,7 +443,7 @@ QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEsti
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
- vector<COutPoint> vOutpts;
+ std::vector<COutPoint> vOutpts;
model->listLockedCoins(vOutpts);
if (vOutpts.size() > 0)
{
@@ -461,13 +462,13 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nPayAmount = 0;
bool fDust = false;
CMutableTransaction txDummy;
- foreach(const CAmount &amount, CoinControlDialog::payAmounts)
+ Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts)
{
nPayAmount += amount;
if (amount > 0)
{
- CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0));
+ CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
if (txout.IsDust(::minRelayTxFee))
fDust = true;
@@ -487,13 +488,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
int nQuantityUncompressed = 0;
bool fAllowFree = false;
- vector<COutPoint> vCoinControl;
- vector<COutput> vOutputs;
+ std::vector<COutPoint> vCoinControl;
+ std::vector<COutput> vOutputs;
coinControl->ListSelected(vCoinControl);
model->getOutputs(vCoinControl, vOutputs);
- BOOST_FOREACH(const COutput& out, vOutputs)
- {
+ BOOST_FOREACH(const COutput& out, vOutputs) {
// unselect already spent, very unlikely scenario, this could happen
// when selected are spent elsewhere, like rpc or another computer
uint256 txhash = out.tx->GetHash();
@@ -569,7 +569,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Never create dust outputs; if we would, just add the dust to the fee.
if (nChange > 0 && nChange < CENT)
{
- CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0));
+ CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
if (txout.IsDust(::minRelayTxFee))
{
if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
@@ -688,11 +688,10 @@ void CoinControlDialog::updateView()
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget);
- map<QString, vector<COutput> > mapCoins;
+ std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
- BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins)
- {
+ BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
QString sWalletAddress = coins.first;
@@ -719,8 +718,7 @@ void CoinControlDialog::updateView()
double dPrioritySum = 0;
int nChildren = 0;
int nInputSum = 0;
- BOOST_FOREACH(const COutput& out, coins.second)
- {
+ BOOST_FOREACH(const COutput& out, coins.second) {
int nInputSize = 0;
nSum += out.tx->vout[out.i].nValue;
nChildren++;
@@ -794,7 +792,7 @@ void CoinControlDialog::updateView()
COutPoint outpt(txhash, out.i);
coinControl->UnSelect(outpt); // just to be sure
itemOutput->setDisabled(true);
- itemOutput->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed"));
+ itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
}
// set checkbox
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 5ec382838f..8ff1eac709 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -16,6 +16,7 @@
#include <QString>
#include <QTreeWidgetItem>
+class PlatformStyle;
class WalletModel;
class CCoinControl;
@@ -32,7 +33,7 @@ class CoinControlDialog : public QDialog
Q_OBJECT
public:
- explicit CoinControlDialog(QWidget *parent = 0);
+ explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~CoinControlDialog();
void setModel(WalletModel *model);
@@ -57,6 +58,8 @@ private:
QAction *lockAction;
QAction *unlockAction;
+ const PlatformStyle *platformStyle;
+
QString strPad(QString, int, QString);
void sortView(int, Qt::SortOrder);
void updateView();
@@ -102,7 +105,7 @@ private:
return column;
}
-private slots:
+private Q_SLOTS:
void showMenu(const QPoint &);
void copyAmount();
void copyLabel();
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index 13c6da8eda..d59fce2d41 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -40,7 +40,7 @@ public:
QString getAddress() const;
void setAddress(const QString &address);
-public slots:
+public Q_SLOTS:
void accept();
private:
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 581d2321bc..550dbacf93 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -11,7 +11,7 @@
#include "primitives/transaction.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "protocol.h"
#include "script/script.h"
#include "script/standard.h"
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 55df64a256..0ac3db6327 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -169,7 +169,7 @@ namespace GUIUtil
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode);
void resizeColumn(int nColumnIndex, int width);
- private slots:
+ private Q_SLOTS:
void on_sectionResized(int logicalIndex, int oldSize, int newSize);
void on_geometriesChanged();
};
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 9f72602b4d..4ab87e0f32 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -6,7 +6,6 @@
#include "ui_intro.h"
#include "guiutil.h"
-#include "scicon.h"
#include "util.h"
@@ -42,10 +41,10 @@ public:
ST_ERROR
};
-public slots:
+public Q_SLOTS:
void check();
-signals:
+Q_SIGNALS:
void reply(int status, const QString &message, quint64 available);
private:
@@ -102,7 +101,7 @@ void FreespaceChecker::check()
replyStatus = ST_ERROR;
replyMessage = tr("Cannot create data directory here.");
}
- emit reply(replyStatus, replyMessage, freeBytesAvailable);
+ Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}
@@ -121,7 +120,7 @@ Intro::~Intro()
{
delete ui;
/* Ensure thread is finished before it is deleted */
- emit stopThread();
+ Q_EMIT stopThread();
thread->wait();
}
@@ -168,7 +167,7 @@ void Intro::pickDataDirectory()
/* If current default data directory does not exist, let the user choose one */
Intro intro;
intro.setDataDirectory(dataDir);
- intro.setWindowIcon(SingleColorIcon(":icons/bitcoin"));
+ intro.setWindowIcon(QIcon(":icons/bitcoin"));
while(true)
{
@@ -277,7 +276,7 @@ void Intro::checkPath(const QString &dataDir)
if(!signalled)
{
signalled = true;
- emit requestCheck();
+ Q_EMIT requestCheck();
}
mutex.unlock();
}
diff --git a/src/qt/intro.h b/src/qt/intro.h
index c9735615b6..50783f7225 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -43,14 +43,14 @@ public:
*/
static QString getDefaultDataDirectory();
-signals:
+Q_SIGNALS:
void requestCheck();
void stopThread();
-public slots:
+public Q_SLOTS:
void setStatus(int status, const QString &message, quint64 bytesAvailable);
-private slots:
+private Q_SLOTS:
void on_dataDirectory_textChanged(const QString &arg1);
void on_ellipsisButton_clicked();
void on_dataDirDefault_clicked();
diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h
index 15a6583ca4..8bd867c103 100644
--- a/src/qt/macdockiconhandler.h
+++ b/src/qt/macdockiconhandler.h
@@ -30,7 +30,7 @@ public:
static void cleanup();
void handleDockIconClickEvent();
-signals:
+Q_SIGNALS:
void dockIconClicked();
private:
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 58a0365d3d..a41d39d51e 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -130,5 +130,5 @@ void MacDockIconHandler::handleDockIconClickEvent()
this->mainWindow->show();
}
- emit this->dockIconClicked();
+ Q_EMIT this->dockIconClicked();
}
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index e28f903b2e..4541c75886 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -5,7 +5,6 @@
#include "networkstyle.h"
#include "guiconstants.h"
-#include "scicon.h"
#include <QApplication>
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index 182e948c7d..f2a15e9c34 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -40,7 +40,7 @@ public:
Critical /**< An error occurred */
};
-public slots:
+public Q_SLOTS:
/** Show notification message.
@param[in] cls general message class
@param[in] title title shown with message
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index d5c434ba9c..28b8f56ca6 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -21,10 +21,10 @@ public:
QString getURI();
-protected slots:
+protected Q_SLOTS:
void accept();
-private slots:
+private Q_SLOTS:
void on_selectFileButton_clicked();
private:
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index efb2bf4158..062c4540ee 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -13,7 +13,7 @@
#include "guiutil.h"
#include "optionsmodel.h"
-#include "main.h" // for MAX_SCRIPTCHECK_THREADS
+#include "main.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
@@ -42,7 +42,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Main elements init */
ui->databaseCache->setMinimum(nMinDbCache);
ui->databaseCache->setMaximum(nMaxDbCache);
- ui->threadsScriptVerif->setMinimum(-(int)boost::thread::hardware_concurrency());
+ ui->threadsScriptVerif->setMinimum(-GetNumCores());
ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
/* Network elements init */
@@ -73,7 +73,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Display elements init */
QDir translations(":translations");
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
- foreach(const QString &langStr, translations.entryList())
+ Q_FOREACH(const QString &langStr, translations.entryList())
{
QLocale locale(langStr);
@@ -281,7 +281,7 @@ bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
if(object == ui->proxyIp)
{
- emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
+ Q_EMIT proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
}
}
return QDialog::eventFilter(object, event);
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index f4e5157595..fa983e798c 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -33,7 +33,7 @@ public:
protected:
bool eventFilter(QObject *object, QEvent *event);
-private slots:
+private Q_SLOTS:
/* enable OK button */
void enableOkButton();
/* disable OK button */
@@ -48,7 +48,7 @@ private slots:
void clearStatusLabel();
void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
-signals:
+Q_SIGNALS:
void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
private:
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 41d6acf358..6191edc44c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -13,7 +13,7 @@
#include "amount.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS
#include "net.h"
#include "txdb.h" // for -dbcache defaults
@@ -286,7 +286,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case CoinControlFeatures:
fCoinControlFeatures = value.toBool();
settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
- emit coinControlFeaturesChanged(fCoinControlFeatures);
+ Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures);
break;
case DatabaseCache:
if (settings.value("nDatabaseCache") != value) {
@@ -311,7 +311,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
- emit dataChanged(index, index);
+ Q_EMIT dataChanged(index, index);
return successful;
}
@@ -324,7 +324,7 @@ void OptionsModel::setDisplayUnit(const QVariant &value)
QSettings settings;
nDisplayUnit = value.toInt();
settings.setValue("nDisplayUnit", nDisplayUnit);
- emit displayUnitChanged(nDisplayUnit);
+ Q_EMIT displayUnitChanged(nDisplayUnit);
}
}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index bf892768ed..fc26d65b04 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -81,7 +81,7 @@ private:
/// Add option to list of GUI options overridden through command line/config file
void addOverriddenOption(const std::string &option);
-signals:
+Q_SIGNALS:
void displayUnitChanged(int unit);
void coinControlFeaturesChanged(bool);
};
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 2e33b9adf8..a56c80ac63 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -10,7 +10,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
#include "walletmodel.h"
@@ -25,7 +25,9 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
+ TxViewDelegate(const PlatformStyle *platformStyle):
+ QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
+ platformStyle(platformStyle)
{
}
@@ -43,7 +45,7 @@ public:
int halfheight = (mainRect.height() - 2*ypad)/2;
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
- icon = SingleColorIcon(icon, SingleColor());
+ icon = platformStyle->SingleColorIcon(icon);
icon.paint(painter, decorationRect);
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
@@ -101,11 +103,12 @@ public:
}
int unit;
+ const PlatformStyle *platformStyle;
};
#include "overviewpage.moc"
-OverviewPage::OverviewPage(QWidget *parent) :
+OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
clientModel(0),
@@ -116,13 +119,13 @@ OverviewPage::OverviewPage(QWidget *parent) :
currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1),
- txdelegate(new TxViewDelegate()),
+ txdelegate(new TxViewDelegate(platformStyle)),
filter(0)
{
ui->setupUi(this);
// use a SingleColorIcon for the "out of sync warning" icon
- QIcon icon = SingleColorIcon(":/icons/warning");
+ QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
ui->labelTransactionsStatus->setIcon(icon);
ui->labelWalletStatus->setIcon(icon);
@@ -142,7 +145,7 @@ OverviewPage::OverviewPage(QWidget *parent) :
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
if(filter)
- emit transactionClicked(filter->mapToSource(index));
+ Q_EMIT transactionClicked(filter->mapToSource(index));
}
OverviewPage::~OverviewPage()
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 64cb1dc4e0..4139eb35d3 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -12,6 +12,7 @@
class ClientModel;
class TransactionFilterProxy;
class TxViewDelegate;
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -28,18 +29,18 @@ class OverviewPage : public QWidget
Q_OBJECT
public:
- explicit OverviewPage(QWidget *parent = 0);
+ explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = 0);
~OverviewPage();
void setClientModel(ClientModel *clientModel);
void setWalletModel(WalletModel *walletModel);
void showOutOfSyncWarning(bool fShow);
-public slots:
+public Q_SLOTS:
void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
-signals:
+Q_SIGNALS:
void transactionClicked(const QModelIndex &index);
private:
@@ -56,7 +57,7 @@ private:
TxViewDelegate *txdelegate;
TransactionFilterProxy *filter;
-private slots:
+private Q_SLOTS:
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings);
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 7e9729eeb9..78a783dea4 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -19,8 +19,6 @@
#include <QDebug>
#include <QSslCertificate>
-using namespace std;
-
class SSLVerifyError : public std::runtime_error
{
public:
@@ -49,7 +47,7 @@ bool PaymentRequestPlus::parse(const QByteArray& data)
return true;
}
-bool PaymentRequestPlus::SerializeToString(string* output) const
+bool PaymentRequestPlus::SerializeToString(std::string* output) const
{
return paymentRequest.SerializeToString(output);
}
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 09e9949b10..0827d99125 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -10,7 +10,7 @@
#include "base58.h"
#include "chainparams.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "ui_interface.h"
#include "util.h"
#include "wallet/wallet.h"
@@ -46,8 +46,6 @@
#include <QUrlQuery>
#endif
-using namespace std;
-
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
// BIP70 payment protocol messages
@@ -148,7 +146,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
- foreach (const QSslCertificate& cert, certList) {
+ Q_FOREACH (const QSslCertificate& cert, certList) {
// Don't log NULL certificates
if (cert.isNull())
continue;
@@ -201,7 +199,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// when uiReady() is called.
//
// Warning: ipcSendCommandLine() is called early in init,
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
@@ -269,7 +267,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
bool PaymentServer::ipcSendCommandLine()
{
bool fResult = false;
- foreach (const QString& r, savedPaymentRequests)
+ Q_FOREACH (const QString& r, savedPaymentRequests)
{
QLocalSocket* socket = new QLocalSocket();
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
@@ -326,7 +324,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
uriServer = new QLocalServer(this);
if (!uriServer->listen(name)) {
- // constructor is called early in init, so don't use "emit message()" here
+ // constructor is called early in init, so don't use "Q_EMIT message()" here
QMessageBox::critical(0, tr("Payment request error"),
tr("Cannot start bitcoin: click-to-pay handler"));
}
@@ -394,7 +392,7 @@ void PaymentServer::uiReady()
initNetManager();
saveURIs = false;
- foreach (const QString& s, savedPaymentRequests)
+ Q_FOREACH (const QString& s, savedPaymentRequests)
{
handleURIOrFile(s);
}
@@ -431,7 +429,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
else
{
qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
- emit message(tr("URI handling"),
+ Q_EMIT message(tr("URI handling"),
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING);
}
@@ -445,14 +443,14 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
CBitcoinAddress address(recipient.address.toStdString());
if (!address.IsValid()) {
- emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
+ Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
else
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
}
else
- emit message(tr("URI handling"),
+ Q_EMIT message(tr("URI handling"),
tr("URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
CClientUIInterface::ICON_WARNING);
@@ -466,12 +464,12 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (!readPaymentRequestFromFile(s, request))
{
- emit message(tr("Payment request file handling"),
+ Q_EMIT message(tr("Payment request file handling"),
tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
CClientUIInterface::ICON_WARNING);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -500,7 +498,7 @@ void PaymentServer::handleURIConnection()
//
// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
{
@@ -533,7 +531,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
if (request.IsInitialized()) {
// Payment request network matches client network?
if (!verifyNetwork(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -542,13 +540,13 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Make sure any payment requests involved are still valid.
// This is re-checked just before sending coins in WalletModel::sendCoins().
if (verifyExpired(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request expired."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."),
CClientUIInterface::MSG_ERROR);
return false;
}
} else {
- emit message(tr("Payment request error"), tr("Payment request is not initialized."),
+ Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -562,7 +560,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
- foreach(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ Q_FOREACH(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
// Extract and check destination addresses
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
@@ -573,7 +571,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Unauthenticated payment requests to custom bitcoin addresses are not supported
// (there is no good way to tell the user where they are paying in a way they'd
// have a chance of understanding).
- emit message(tr("Payment request rejected"),
+ Q_EMIT message(tr("Payment request rejected"),
tr("Unverified payment requests to custom payment scripts are unsupported."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -583,14 +581,14 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range
// and no overflow has happened.
if (!verifyAmount(sendingTo.second)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
if (txOut.IsDust(::minRelayTxFee)) {
- emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
+ Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR);
@@ -600,7 +598,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.amount += sendingTo.second;
// Also verify that the final amount is still in a valid range after adding additional amounts.
if (!verifyAmount(recipient.amount)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
}
@@ -647,7 +645,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
// Create a new refund address, or re-use:
QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant);
std::string strAccount = account.toStdString();
- set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
+ std::set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
if (!refundAddresses.empty()) {
CScript s = GetScriptForDestination(*refundAddresses.begin());
payments::Output* refund_to = payment.add_refund_to();
@@ -694,7 +692,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg;
- emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -704,7 +702,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->errorString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -718,12 +716,12 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
if (!request.parse(data))
{
qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
- emit message(tr("Payment request error"),
+ Q_EMIT message(tr("Payment request error"),
tr("Payment request cannot be parsed!"),
CClientUIInterface::MSG_ERROR);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -736,11 +734,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->request().url().toString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
}
else
{
- emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
+ Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
}
}
}
@@ -750,11 +748,11 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_UNUSED(reply);
QString errString;
- foreach (const QSslError& err, errs) {
+ Q_FOREACH (const QSslError& err, errs) {
qWarning() << "PaymentServer::reportSslErrors: " << err;
errString += err.errorString() + "\n";
}
- emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
@@ -765,7 +763,7 @@ void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
{
// currently we don't futher process or store the paymentACK message
- emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
+ Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
}
bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 32ed27983e..5df0a14cf7 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -98,7 +98,7 @@ public:
// Verify the payment request amount is valid
static bool verifyAmount(const CAmount& requestAmount);
-signals:
+Q_SIGNALS:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
@@ -108,7 +108,7 @@ signals:
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
-public slots:
+public Q_SLOTS:
// Signal this when the main window's UI is ready
// to display payment requests to the user
void uiReady();
@@ -119,7 +119,7 @@ public slots:
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
-private slots:
+private Q_SLOTS:
void handleURIConnection();
void netRequestFinished(QNetworkReply*);
void reportSslErrors(QNetworkReply*, const QList<QSslError> &);
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index f5904a4d8e..85339166b0 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -63,7 +63,7 @@ public:
#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vNodes.size());
#endif
- foreach (CNode* pnode, vNodes)
+ Q_FOREACH (CNode* pnode, vNodes)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
@@ -92,7 +92,7 @@ public:
// build index map
mapNodeRows.clear();
int row = 0;
- foreach (const CNodeCombinedStats& stats, cachedNodeStats)
+ Q_FOREACH (const CNodeCombinedStats& stats, cachedNodeStats)
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
}
@@ -220,9 +220,9 @@ const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
void PeerTableModel::refresh()
{
- emit layoutAboutToBeChanged();
+ Q_EMIT layoutAboutToBeChanged();
priv->refreshPeers();
- emit layoutChanged();
+ Q_EMIT layoutChanged();
}
int PeerTableModel::getRowByNodeId(NodeId nodeid)
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index bff7bb824e..5f149ea873 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_PEERTABLEMODEL_H
#define BITCOIN_QT_PEERTABLEMODEL_H
-#include "main.h"
+#include "main.h" // For CNodeStateStats
#include "net.h"
#include <QAbstractTableModel>
@@ -68,7 +68,7 @@ public:
void sort(int column, Qt::SortOrder order);
/*@}*/
-public slots:
+public Q_SLOTS:
void refresh();
private:
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
new file mode 100644
index 0000000000..11cbc7a47c
--- /dev/null
+++ b/src/qt/platformstyle.cpp
@@ -0,0 +1,147 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "platformstyle.h"
+
+#include "guiconstants.h"
+
+#include <QApplication>
+#include <QColor>
+#include <QIcon>
+#include <QImage>
+#include <QPalette>
+#include <QPixmap>
+
+static const struct {
+ const char *platformId;
+ /** Show images on push buttons */
+ const bool imagesOnButtons;
+ /** Colorize single-color icons */
+ const bool colorizeIcons;
+ /** Extra padding/spacing in transactionview */
+ const bool useExtraSpacing;
+} platform_styles[] = {
+ {"macosx", false, false, true},
+ {"windows", true, false, false},
+ /* Other: linux, unix, ... */
+ {"other", true, true, false}
+};
+static const unsigned platform_styles_count = sizeof(platform_styles)/sizeof(*platform_styles);
+
+namespace {
+/* Local functions for colorizing single-color images */
+
+void MakeSingleColorImage(QImage& img, const QColor& colorbase)
+{
+ img = img.convertToFormat(QImage::Format_ARGB32);
+ for (int x = img.width(); x--; )
+ {
+ for (int y = img.height(); y--; )
+ {
+ const QRgb rgb = img.pixel(x, y);
+ img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb)));
+ }
+ }
+}
+
+QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase)
+{
+ QIcon new_ico;
+ QSize sz;
+ Q_FOREACH(sz, ico.availableSizes())
+ {
+ QImage img(ico.pixmap(sz).toImage());
+ MakeSingleColorImage(img, colorbase);
+ new_ico.addPixmap(QPixmap::fromImage(img));
+ }
+ return new_ico;
+}
+
+QImage ColorizeImage(const QString& filename, const QColor& colorbase)
+{
+ QImage img(filename);
+ MakeSingleColorImage(img, colorbase);
+ return img;
+}
+
+QIcon ColorizeIcon(const QString& filename, const QColor& colorbase)
+{
+ return QIcon(QPixmap::fromImage(ColorizeImage(filename, colorbase)));
+}
+
+}
+
+
+PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing):
+ name(name),
+ imagesOnButtons(imagesOnButtons),
+ colorizeIcons(colorizeIcons),
+ useExtraSpacing(useExtraSpacing),
+ singleColor(0,0,0),
+ textColor(0,0,0)
+{
+ // Determine icon highlighting color
+ if (colorizeIcons) {
+ const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
+ const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
+ const QColor colorText(QApplication::palette().color(QPalette::WindowText));
+ const int colorTextLightness = colorText.lightness();
+ QColor colorbase;
+ if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness))
+ colorbase = colorHighlightBg;
+ else
+ colorbase = colorHighlightFg;
+ singleColor = colorbase;
+ }
+ // Determine text color
+ textColor = QColor(QApplication::palette().color(QPalette::WindowText));
+}
+
+QImage PlatformStyle::SingleColorImage(const QString& filename) const
+{
+ if (!colorizeIcons)
+ return QImage(filename);
+ return ColorizeImage(filename, SingleColor());
+}
+
+QIcon PlatformStyle::SingleColorIcon(const QString& filename) const
+{
+ if (!colorizeIcons)
+ return QIcon(filename);
+ return ColorizeIcon(filename, SingleColor());
+}
+
+QIcon PlatformStyle::SingleColorIcon(const QIcon& icon) const
+{
+ if (!colorizeIcons)
+ return icon;
+ return ColorizeIcon(icon, SingleColor());
+}
+
+QIcon PlatformStyle::TextColorIcon(const QString& filename) const
+{
+ return ColorizeIcon(filename, TextColor());
+}
+
+QIcon PlatformStyle::TextColorIcon(const QIcon& icon) const
+{
+ return ColorizeIcon(icon, TextColor());
+}
+
+const PlatformStyle *PlatformStyle::instantiate(const QString &platformId)
+{
+ for (unsigned x=0; x<platform_styles_count; ++x)
+ {
+ if (platformId == platform_styles[x].platformId)
+ {
+ return new PlatformStyle(
+ platform_styles[x].platformId,
+ platform_styles[x].imagesOnButtons,
+ platform_styles[x].colorizeIcons,
+ platform_styles[x].useExtraSpacing);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/qt/platformstyle.h b/src/qt/platformstyle.h
new file mode 100644
index 0000000000..4e763e760e
--- /dev/null
+++ b/src/qt/platformstyle.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_PLATFORMSTYLE_H
+#define BITCOIN_QT_PLATFORMSTYLE_H
+
+#include <QIcon>
+#include <QPixmap>
+#include <QString>
+
+/* Coin network-specific GUI style information */
+class PlatformStyle
+{
+public:
+ /** Get style associated with provided platform name, or 0 if not known */
+ static const PlatformStyle *instantiate(const QString &platformId);
+
+ const QString &getName() const { return name; }
+
+ bool getImagesOnButtons() const { return imagesOnButtons; }
+ bool getUseExtraSpacing() const { return useExtraSpacing; }
+
+ QColor TextColor() const { return textColor; }
+ QColor SingleColor() const { return singleColor; }
+
+ /** Colorize an image (given filename) with the icon color */
+ QImage SingleColorImage(const QString& filename) const;
+
+ /** Colorize an icon (given filename) with the icon color */
+ QIcon SingleColorIcon(const QString& filename) const;
+
+ /** Colorize an icon (given object) with the icon color */
+ QIcon SingleColorIcon(const QIcon& icon) const;
+
+ /** Colorize an icon (given filename) with the text color */
+ QIcon TextColorIcon(const QString& filename) const;
+
+ /** Colorize an icon (given object) with the text color */
+ QIcon TextColorIcon(const QIcon& icon) const;
+
+private:
+ PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing);
+
+ QString name;
+ bool imagesOnButtons;
+ bool colorizeIcons;
+ bool useExtraSpacing;
+ QColor singleColor;
+ QColor textColor;
+ /* ... more to come later */
+};
+
+#endif // BITCOIN_QT_PLATFORMSTYLE_H
+
diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h
index f63568d27f..8665acda5e 100644
--- a/src/qt/qvalidatedlineedit.h
+++ b/src/qt/qvalidatedlineedit.h
@@ -27,11 +27,11 @@ private:
bool valid;
const QValidator *checkValidator;
-public slots:
+public Q_SLOTS:
void setValid(bool valid);
void setEnabled(bool enabled);
-private slots:
+private Q_SLOTS:
void markValid();
void checkValidity();
};
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index f73268c958..800436661f 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -27,5 +27,5 @@ void QValueComboBox::setRole(int role)
void QValueComboBox::handleSelectionChanged(int idx)
{
- emit valueChanged();
+ Q_EMIT valueChanged();
}
diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h
index dc85d64cb5..5b20e6a5a4 100644
--- a/src/qt/qvaluecombobox.h
+++ b/src/qt/qvaluecombobox.h
@@ -24,13 +24,13 @@ public:
/** Specify model role to use as ordinal value (defaults to Qt::UserRole) */
void setRole(int role);
-signals:
+Q_SIGNALS:
void valueChanged();
private:
int role;
-private slots:
+private Q_SLOTS:
void handleSelectionChanged(int idx);
};
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 28cbd3abed..7fb68cc32a 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -10,9 +10,9 @@
#include "bitcoinunits.h"
#include "guiutil.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "receiverequestdialog.h"
#include "recentrequeststablemodel.h"
-#include "scicon.h"
#include "walletmodel.h"
#include <QAction>
@@ -22,24 +22,25 @@
#include <QScrollBar>
#include <QTextDocument>
-ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) :
+ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveCoinsDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->clearButton->setIcon(QIcon());
- ui->receiveButton->setIcon(QIcon());
- ui->showRequestButton->setIcon(QIcon());
- ui->removeRequestButton->setIcon(QIcon());
-#else
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->receiveButton->setIcon(SingleColorIcon(":/icons/receiving_addresses"));
- ui->showRequestButton->setIcon(SingleColorIcon(":/icons/edit"));
- ui->removeRequestButton->setIcon(SingleColorIcon(":/icons/remove"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->clearButton->setIcon(QIcon());
+ ui->receiveButton->setIcon(QIcon());
+ ui->showRequestButton->setIcon(QIcon());
+ ui->removeRequestButton->setIcon(QIcon());
+ } else {
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
+ ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ }
// context menu actions
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
@@ -132,7 +133,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
if(ui->reuseAddress->isChecked())
{
/* Choose existing receiving address */
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
dlg.setModel(model->getAddressTableModel());
if(dlg.exec())
{
@@ -185,8 +186,7 @@ void ReceiveCoinsDialog::on_showRequestButton_clicked()
return;
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
- foreach (QModelIndex index, selection)
- {
+ Q_FOREACH (const QModelIndex& index, selection) {
on_recentRequestsView_doubleClicked(index);
}
}
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 70a1842fa2..eaaf129a91 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -16,6 +16,7 @@
#include <QVariant>
class OptionsModel;
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -39,12 +40,12 @@ public:
MINIMUM_COLUMN_WIDTH = 130
};
- explicit ReceiveCoinsDialog(QWidget *parent = 0);
+ explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~ReceiveCoinsDialog();
void setModel(WalletModel *model);
-public slots:
+public Q_SLOTS:
void clear();
void reject();
void accept();
@@ -57,10 +58,12 @@ private:
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
WalletModel *model;
QMenu *contextMenu;
+ const PlatformStyle *platformStyle;
+
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent *event);
-private slots:
+private Q_SLOTS:
void on_receiveButton_clicked();
void on_showRequestButton_clicked();
void on_removeRequestButton_clicked();
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 3e5f897be6..69f84ebbd7 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -32,7 +32,7 @@ public:
explicit QRImageWidget(QWidget *parent = 0);
QImage exportImage();
-public slots:
+public Q_SLOTS:
void saveImage();
void copyImage();
@@ -55,7 +55,7 @@ public:
void setModel(OptionsModel *model);
void setInfo(const SendCoinsRecipient &info);
-private slots:
+private Q_SLOTS:
void on_btnCopyURI_clicked();
void on_btnCopyAddress_clicked();
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 543b977d8f..5692a7aaef 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -119,7 +119,7 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien
void RecentRequestsTableModel::updateAmountColumnTitle()
{
columns[Amount] = getAmountTitle();
- emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+ Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
}
/** Gets title for amount column including current display unit if optionsModel reference available. */
@@ -214,7 +214,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient)
void RecentRequestsTableModel::sort(int column, Qt::SortOrder order)
{
qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order));
- emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+ Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
}
void RecentRequestsTableModel::updateDisplayUnit()
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 85bad126db..64faa72d45 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -89,7 +89,7 @@ public:
void addNewRequest(const std::string &recipient);
void addNewRequest(RecentRequestEntry &recipient);
-public slots:
+public Q_SLOTS:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
void updateDisplayUnit();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index f828ce2534..3231b392f2 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -8,9 +8,8 @@
#include "clientmodel.h"
#include "guiutil.h"
#include "peertablemodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
-#include "main.h"
#include "chainparams.h"
#include "rpcserver.h"
#include "rpcclient.h"
@@ -60,10 +59,10 @@ class RPCExecutor : public QObject
{
Q_OBJECT
-public slots:
+public Q_SLOTS:
void request(const QString &command);
-signals:
+Q_SIGNALS:
void reply(int category, const QString &command);
};
@@ -95,7 +94,7 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm
STATE_ESCAPE_DOUBLEQUOTED
} state = STATE_EATING_SPACES;
std::string curarg;
- foreach(char ch, strCommand)
+ Q_FOREACH(char ch, strCommand)
{
switch(state)
{
@@ -158,7 +157,7 @@ void RPCExecutor::request(const QString &command)
std::vector<std::string> args;
if(!parseCommandLine(args, command.toStdString()))
{
- emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
return;
}
if(args.empty())
@@ -180,7 +179,7 @@ void RPCExecutor::request(const QString &command)
else
strPrint = result.write(2);
- emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
}
catch (UniValue& objError)
{
@@ -188,34 +187,35 @@ void RPCExecutor::request(const QString &command)
{
int code = find_value(objError, "code").get_int();
std::string message = find_value(objError, "message").get_str();
- emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
}
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
{ // Show raw JSON object
- emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
}
}
catch (const std::exception& e)
{
- emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
}
}
-RPCConsole::RPCConsole(QWidget *parent) :
+RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
cachedNodeid(-1),
- contextMenu(0)
+ contextMenu(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
-#ifndef Q_OS_MAC
- ui->openDebugLogfileButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
+ if (platformStyle->getImagesOnButtons()) {
+ ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
// Install event filter for up and down arrow
ui->lineEdit->installEventFilter(this);
@@ -245,7 +245,7 @@ RPCConsole::RPCConsole(QWidget *parent) :
RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
- emit stopExecutor();
+ Q_EMIT stopExecutor();
delete ui;
}
@@ -364,7 +364,7 @@ void RPCConsole::clear()
ui->messagesWidget->document()->addResource(
QTextDocument::ImageResource,
QUrl(ICON_MAPPING[i].url),
- SingleColorImage(ICON_MAPPING[i].source, SingleColor()).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ platformStyle->SingleColorImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Set default style sheet
@@ -431,7 +431,7 @@ void RPCConsole::on_lineEdit_returnPressed()
if(!cmd.isEmpty())
{
message(CMD_REQUEST, cmd);
- emit cmdRequest(cmd);
+ Q_EMIT cmdRequest(cmd);
// Remove command, if already in history
history.removeOne(cmd);
// Append command to history
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index a309df7ba7..b94efee84a 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -13,6 +13,7 @@
#include <QWidget>
class ClientModel;
+class PlatformStyle;
namespace Ui {
class RPCConsole;
@@ -29,7 +30,7 @@ class RPCConsole: public QWidget
Q_OBJECT
public:
- explicit RPCConsole(QWidget *parent);
+ explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
void setClientModel(ClientModel *model);
@@ -46,7 +47,7 @@ protected:
virtual bool eventFilter(QObject* obj, QEvent *event);
void keyPressEvent(QKeyEvent *);
-private slots:
+private Q_SLOTS:
void on_lineEdit_returnPressed();
void on_tabWidget_currentChanged(int index);
/** open the debug.log from the current datadir */
@@ -61,7 +62,7 @@ private slots:
/** Show custom context menu on Peers tab */
void showMenu(const QPoint& point);
-public slots:
+public Q_SLOTS:
void clear();
void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
@@ -79,7 +80,7 @@ public slots:
/** Disconnect a selected node on the Peers tab */
void disconnectSelectedNode();
-signals:
+Q_SIGNALS:
// For RPC command executor
void stopExecutor();
void cmdRequest(const QString &command);
@@ -106,6 +107,7 @@ private:
int historyPtr;
NodeId cachedNodeid;
QMenu *contextMenu;
+ const PlatformStyle *platformStyle;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/scicon.cpp b/src/qt/scicon.cpp
deleted file mode 100644
index c493b5569e..0000000000
--- a/src/qt/scicon.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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 "scicon.h"
-
-#include <QApplication>
-#include <QColor>
-#include <QIcon>
-#include <QImage>
-#include <QPalette>
-#include <QPixmap>
-
-namespace {
-
-void MakeSingleColorImage(QImage& img, const QColor& colorbase)
-{
- img = img.convertToFormat(QImage::Format_ARGB32);
- for (int x = img.width(); x--; )
- {
- for (int y = img.height(); y--; )
- {
- const QRgb rgb = img.pixel(x, y);
- img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb)));
- }
- }
-}
-
-}
-
-QImage SingleColorImage(const QString& filename, const QColor& colorbase)
-{
- QImage img(filename);
-#if !defined(WIN32) && !defined(MAC_OSX)
- MakeSingleColorImage(img, colorbase);
-#endif
- return img;
-}
-
-QIcon SingleColorIcon(const QIcon& ico, const QColor& colorbase)
-{
-#if defined(WIN32) || defined(MAC_OSX)
- return ico;
-#else
- QIcon new_ico;
- QSize sz;
- Q_FOREACH(sz, ico.availableSizes())
- {
- QImage img(ico.pixmap(sz).toImage());
- MakeSingleColorImage(img, colorbase);
- new_ico.addPixmap(QPixmap::fromImage(img));
- }
- return new_ico;
-#endif
-}
-
-QIcon SingleColorIcon(const QString& filename, const QColor& colorbase)
-{
- return QIcon(QPixmap::fromImage(SingleColorImage(filename, colorbase)));
-}
-
-QColor SingleColor()
-{
-#if defined(WIN32) || defined(MAC_OSX)
- return QColor(0,0,0);
-#else
- const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
- const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
- const QColor colorText(QApplication::palette().color(QPalette::WindowText));
- const int colorTextLightness = colorText.lightness();
- QColor colorbase;
- if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness))
- colorbase = colorHighlightBg;
- else
- colorbase = colorHighlightFg;
- return colorbase;
-#endif
-}
-
-QIcon SingleColorIcon(const QString& filename)
-{
- return SingleColorIcon(filename, SingleColor());
-}
-
-static QColor TextColor()
-{
- return QColor(QApplication::palette().color(QPalette::WindowText));
-}
-
-QIcon TextColorIcon(const QString& filename)
-{
- return SingleColorIcon(filename, TextColor());
-}
-
-QIcon TextColorIcon(const QIcon& ico)
-{
- return SingleColorIcon(ico, TextColor());
-}
diff --git a/src/qt/scicon.h b/src/qt/scicon.h
deleted file mode 100644
index 1388069ddb..0000000000
--- a/src/qt/scicon.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 BITCOIN_QT_SCICON_H
-#define BITCOIN_QT_SCICON_H
-
-#include <QtCore>
-
-QT_BEGIN_NAMESPACE
-class QColor;
-class QIcon;
-class QString;
-QT_END_NAMESPACE
-
-QImage SingleColorImage(const QString& filename, const QColor&);
-QIcon SingleColorIcon(const QIcon&, const QColor&);
-QIcon SingleColorIcon(const QString& filename, const QColor&);
-QColor SingleColor();
-QIcon SingleColorIcon(const QString& filename);
-QIcon TextColorIcon(const QIcon&);
-QIcon TextColorIcon(const QString& filename);
-
-#endif // BITCOIN_QT_SCICON_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 3d57711568..449a7bc5e8 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -11,14 +11,15 @@
#include "coincontroldialog.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "sendcoinsentry.h"
#include "walletmodel.h"
#include "base58.h"
#include "coincontrol.h"
-#include "main.h"
+#include "main.h" // mempool and minRelayTxFee
#include "ui_interface.h"
+#include "txmempool.h"
#include "wallet/wallet.h"
#include <QMessageBox>
@@ -26,25 +27,26 @@
#include <QSettings>
#include <QTextDocument>
-SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
+SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
clientModel(0),
model(0),
fNewRecipientAllowed(true),
- fFeeMinimized(true)
+ fFeeMinimized(true),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->addButton->setIcon(QIcon());
- ui->clearButton->setIcon(QIcon());
- ui->sendButton->setIcon(QIcon());
-#else
- ui->addButton->setIcon(SingleColorIcon(":/icons/add"));
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->sendButton->setIcon(SingleColorIcon(":/icons/send"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->addButton->setIcon(QIcon());
+ ui->clearButton->setIcon(QIcon());
+ ui->sendButton->setIcon(QIcon());
+ } else {
+ ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send"));
+ }
GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
@@ -251,7 +253,7 @@ void SendCoinsDialog::on_sendButton_clicked()
// Format confirmation message
QStringList formatted;
- foreach(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
{
// generate bold amount string
QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
@@ -305,7 +307,7 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append("<hr />");
CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;
QStringList alternativeUnits;
- foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
if(u != model->getOptionsModel()->getDisplayUnit())
alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
@@ -363,7 +365,7 @@ void SendCoinsDialog::accept()
SendCoinsEntry *SendCoinsDialog::addEntry()
{
- SendCoinsEntry *entry = new SendCoinsEntry(this);
+ SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this);
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
@@ -540,7 +542,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
return;
}
- emit message(tr("Send Coins"), msgParams.first, msgParams.second);
+ Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second);
}
void SendCoinsDialog::minimizeFeeSection(bool fMinimize)
@@ -710,7 +712,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
// Coin Control: button inputs -> show actual coin control dialog
void SendCoinsDialog::coinControlButtonClicked()
{
- CoinControlDialog dlg;
+ CoinControlDialog dlg(platformStyle);
dlg.setModel(model);
dlg.exec();
coinControlUpdateLabels();
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index fc513bf2ba..391905ffcd 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -12,6 +12,7 @@
class ClientModel;
class OptionsModel;
+class PlatformStyle;
class SendCoinsEntry;
class SendCoinsRecipient;
@@ -31,7 +32,7 @@ class SendCoinsDialog : public QDialog
Q_OBJECT
public:
- explicit SendCoinsDialog(QWidget *parent = 0);
+ explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~SendCoinsDialog();
void setClientModel(ClientModel *clientModel);
@@ -45,7 +46,7 @@ public:
void pasteEntry(const SendCoinsRecipient &rv);
bool handlePaymentRequest(const SendCoinsRecipient &recipient);
-public slots:
+public Q_SLOTS:
void clear();
void reject();
void accept();
@@ -60,15 +61,16 @@ private:
WalletModel *model;
bool fNewRecipientAllowed;
bool fFeeMinimized;
+ const PlatformStyle *platformStyle;
// Process WalletModel::SendCoinsReturn and generate a pair consisting
- // of a message and message flags for use in emit message().
+ // of a message and message flags for use in Q_EMIT message().
// Additional parameter msgArg can be used via .arg(msgArg).
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString());
void minimizeFeeSection(bool fMinimize);
void updateFeeMinimizedLabel();
-private slots:
+private Q_SLOTS:
void on_sendButton_clicked();
void on_buttonChooseFee_clicked();
void on_buttonMinimizeFee_clicked();
@@ -93,7 +95,7 @@ private slots:
void updateSmartFeeLabel();
void updateGlobalFeeVariables();
-signals:
+Q_SIGNALS:
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
};
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 6eec33ffd4..44aa8ad1af 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -9,30 +9,30 @@
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "walletmodel.h"
#include <QApplication>
#include <QClipboard>
-SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
+SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) :
QStackedWidget(parent),
ui(new Ui::SendCoinsEntry),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
- ui->addressBookButton->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->pasteButton->setIcon(SingleColorIcon(":/icons/editpaste"));
- ui->deleteButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->deleteButton_is->setIcon(SingleColorIcon(":/icons/remove"));
- ui->deleteButton_s->setIcon(SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
+ ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->deleteButton_is->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->deleteButton_s->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
setCurrentWidget(ui->SendCoins);
-#ifdef Q_OS_MAC
- ui->payToLayout->setSpacing(4);
-#endif
+ if (platformStyle->getUseExtraSpacing())
+ ui->payToLayout->setSpacing(4);
#if QT_VERSION >= 0x040700
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif
@@ -65,7 +65,7 @@ void SendCoinsEntry::on_addressBookButton_clicked()
{
if(!model)
return;
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
dlg.setModel(model->getAddressTableModel());
if(dlg.exec())
{
@@ -114,7 +114,7 @@ void SendCoinsEntry::clear()
void SendCoinsEntry::deleteClicked()
{
- emit removeEntry(this);
+ Q_EMIT removeEntry(this);
}
bool SendCoinsEntry::validate()
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index c2d1185bdd..107ab70158 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -10,6 +10,7 @@
#include <QStackedWidget>
class WalletModel;
+class PlatformStyle;
namespace Ui {
class SendCoinsEntry;
@@ -25,7 +26,7 @@ class SendCoinsEntry : public QStackedWidget
Q_OBJECT
public:
- explicit SendCoinsEntry(QWidget *parent = 0);
+ explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = 0);
~SendCoinsEntry();
void setModel(WalletModel *model);
@@ -45,15 +46,15 @@ public:
void setFocus();
-public slots:
+public Q_SLOTS:
void clear();
-signals:
+Q_SIGNALS:
void removeEntry(SendCoinsEntry *entry);
void payAmountChanged();
void subtractFeeFromAmountChanged();
-private slots:
+private Q_SLOTS:
void deleteClicked();
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
@@ -64,6 +65,7 @@ private:
SendCoinsRecipient recipient;
Ui::SendCoinsEntry *ui;
WalletModel *model;
+ const PlatformStyle *platformStyle;
bool updateLabel(const QString &address);
};
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index ce166f3672..60e8e36ebe 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -7,7 +7,7 @@
#include "addressbookpage.h"
#include "guiutil.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "walletmodel.h"
#include "base58.h"
@@ -20,21 +20,22 @@
#include <QClipboard>
-SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
+SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SignVerifyMessageDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
- ui->addressBookButton_SM->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->pasteButton_SM->setIcon(SingleColorIcon(":/icons/editpaste"));
- ui->copySignatureButton_SM->setIcon(SingleColorIcon(":/icons/editcopy"));
- ui->signMessageButton_SM->setIcon(SingleColorIcon(":/icons/edit"));
- ui->clearButton_SM->setIcon(SingleColorIcon(":/icons/remove"));
- ui->addressBookButton_VM->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->verifyMessageButton_VM->setIcon(SingleColorIcon(":/icons/transaction_0"));
- ui->clearButton_VM->setIcon(SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
+ ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
+ ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0"));
+ ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
#if QT_VERSION >= 0x040700
ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
@@ -94,7 +95,7 @@ void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
{
if (model && model->getAddressTableModel())
{
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
dlg.setModel(model->getAddressTableModel());
if (dlg.exec())
{
@@ -148,12 +149,12 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
return;
}
- CDataStream ss(SER_GETHASH, 0);
+ CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << ui->messageIn_SM->document()->toPlainText().toStdString();
std::vector<unsigned char> vchSig;
- if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
+ if (!key.SignCompact(ss.GetHash(), vchSig))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
@@ -185,7 +186,7 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
{
if (model && model->getAddressTableModel())
{
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
dlg.setModel(model->getAddressTableModel());
if (dlg.exec())
{
@@ -223,12 +224,12 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- CDataStream ss(SER_GETHASH, 0);
+ CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << ui->messageIn_VM->document()->toPlainText().toStdString();
CPubKey pubkey;
- if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig))
+ if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
{
ui->signatureIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h
index 27807adc84..d651d5049b 100644
--- a/src/qt/signverifymessagedialog.h
+++ b/src/qt/signverifymessagedialog.h
@@ -7,6 +7,7 @@
#include <QDialog>
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -18,7 +19,7 @@ class SignVerifyMessageDialog : public QDialog
Q_OBJECT
public:
- explicit SignVerifyMessageDialog(QWidget *parent);
+ explicit SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent);
~SignVerifyMessageDialog();
void setModel(WalletModel *model);
@@ -34,8 +35,9 @@ protected:
private:
Ui::SignVerifyMessageDialog *ui;
WalletModel *model;
+ const PlatformStyle *platformStyle;
-private slots:
+private Q_SLOTS:
/* sign message */
void on_addressBookButton_SM_clicked();
void on_pasteButton_SM_clicked();
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 84e4556dd8..29d16d4eae 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -27,7 +27,7 @@ protected:
void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event);
-public slots:
+public Q_SLOTS:
/** Slot to call finish() method as it's not defined as slot */
void slotFinish(QWidget *mainWin);
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index e2ec439b2e..b28934cd31 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -195,7 +195,7 @@ void PaymentServerTests::paymentServerTests()
QVERIFY(r.paymentRequest.IsInitialized());
// Extract address and amount from the request
QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
- foreach (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest))
QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index c98bbf0833..71d61fcbe7 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -14,7 +14,7 @@ class PaymentServerTests : public QObject
{
Q_OBJECT
-private slots:
+private Q_SLOTS:
void paymentServerTests();
};
@@ -25,7 +25,7 @@ class RecipientCatcher : public QObject
{
Q_OBJECT
-public slots:
+public Q_SLOTS:
void getRecipient(SendCoinsRecipient r);
public:
diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h
index a0b7dc6c72..434169dcde 100644
--- a/src/qt/test/uritests.h
+++ b/src/qt/test/uritests.h
@@ -12,7 +12,7 @@ class URITests : public QObject
{
Q_OBJECT
-private slots:
+private Q_SLOTS:
void uriTests();
};
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 0b2eb9eaf2..9b67445bc0 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -139,10 +139,10 @@ void TrafficGraphWidget::updateRates()
}
float tmax = 0.0f;
- foreach(float f, vSamplesIn) {
+ Q_FOREACH(float f, vSamplesIn) {
if(f > tmax) tmax = f;
}
- foreach(float f, vSamplesOut) {
+ Q_FOREACH(float f, vSamplesOut) {
if(f > tmax) tmax = f;
}
fMax = tmax;
diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h
index 4c6b17fe7e..6336a8d144 100644
--- a/src/qt/trafficgraphwidget.h
+++ b/src/qt/trafficgraphwidget.h
@@ -27,7 +27,7 @@ public:
protected:
void paintEvent(QPaintEvent *);
-public slots:
+public Q_SLOTS:
void updateRates();
void setGraphRangeMins(int mins);
void clear();
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 5662b16657..af78a51d0f 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -21,8 +21,6 @@
#include <stdint.h>
#include <string>
-using namespace std;
-
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
AssertLockHeld(cs_main);
@@ -243,14 +241,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
- foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm)
+ Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
if (r.first == "Message")
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
//
// PaymentRequest info:
//
- foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm)
+ Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
{
if (r.first == "PaymentRequest")
{
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 34464b4075..98ad1a44b6 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -8,7 +8,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactiondesc.h"
#include "transactionrecord.h"
#include "walletmodel.h"
@@ -25,6 +25,8 @@
#include <QIcon>
#include <QList>
+#include <boost/foreach.hpp>
+
// Amount column is right-aligned it contains numbers
static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter, /* status */
@@ -142,7 +144,7 @@ public:
{
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
int insert_idx = lowerIndex;
- foreach(const TransactionRecord &rec, toInsert)
+ Q_FOREACH(const TransactionRecord &rec, toInsert)
{
cachedWallet.insert(insert_idx, rec);
insert_idx += 1;
@@ -220,12 +222,13 @@ public:
}
};
-TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *parent):
+TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent):
QAbstractTableModel(parent),
wallet(wallet),
walletModel(parent),
priv(new TransactionTablePriv(wallet, this)),
- fProcessingQueuedTransactions(false)
+ fProcessingQueuedTransactions(false),
+ platformStyle(platformStyle)
{
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
@@ -245,7 +248,7 @@ TransactionTableModel::~TransactionTableModel()
void TransactionTableModel::updateAmountColumnTitle()
{
columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
- emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+ Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
}
void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
@@ -262,8 +265,8 @@ void TransactionTableModel::updateConfirmations()
// Invalidate status (number of confirmations) and (possibly) description
// for all rows. Qt is smart enough to only actually request the data for the
// visible rows.
- emit dataChanged(index(0, Status), index(priv->size()-1, Status));
- emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
+ Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
+ Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
}
int TransactionTableModel::rowCount(const QModelIndex &parent) const
@@ -519,7 +522,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
case Qt::DecorationRole:
{
QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
- return TextColorIcon(icon);
+ return platformStyle->TextColorIcon(icon);
}
case Qt::DisplayRole:
switch(index.column())
@@ -650,7 +653,7 @@ void TransactionTableModel::updateDisplayUnit()
{
// emit dataChanged to update Amount column with the current unit
updateAmountColumnTitle();
- emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
+ Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
}
// queue notifications to show a non freezing progress dialog e.g. for rescan
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 30a15df9e6..2089f703a6 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -10,6 +10,7 @@
#include <QAbstractTableModel>
#include <QStringList>
+class PlatformStyle;
class TransactionRecord;
class TransactionTablePriv;
class WalletModel;
@@ -23,7 +24,7 @@ class TransactionTableModel : public QAbstractTableModel
Q_OBJECT
public:
- explicit TransactionTableModel(CWallet* wallet, WalletModel *parent = 0);
+ explicit TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent = 0);
~TransactionTableModel();
enum ColumnIndex {
@@ -82,6 +83,7 @@ private:
QStringList columns;
TransactionTablePriv *priv;
bool fProcessingQueuedTransactions;
+ const PlatformStyle *platformStyle;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
@@ -98,7 +100,7 @@ private:
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const;
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
-public slots:
+public Q_SLOTS:
/* New transaction, or transaction changed status */
void updateTransaction(const QString &hash, int status, bool showTransaction);
void updateConfirmations();
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 526940632e..54e5a82720 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -10,7 +10,7 @@
#include "editaddressdialog.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactiondescdialog.h"
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
@@ -35,7 +35,7 @@
#include <QUrl>
#include <QVBoxLayout>
-TransactionView::TransactionView(QWidget *parent) :
+TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
transactionView(0)
{
@@ -44,27 +44,28 @@ TransactionView::TransactionView(QWidget *parent) :
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);
-#ifdef Q_OS_MAC
- hlayout->setSpacing(5);
- hlayout->addSpacing(26);
-#else
- hlayout->setSpacing(0);
- hlayout->addSpacing(23);
-#endif
+
+ if (platformStyle->getUseExtraSpacing()) {
+ hlayout->setSpacing(5);
+ hlayout->addSpacing(26);
+ } else {
+ hlayout->setSpacing(0);
+ hlayout->addSpacing(23);
+ }
watchOnlyWidget = new QComboBox(this);
watchOnlyWidget->setFixedWidth(24);
watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All);
- watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
- watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
+ watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
+ watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
hlayout->addWidget(watchOnlyWidget);
dateWidget = new QComboBox(this);
-#ifdef Q_OS_MAC
- dateWidget->setFixedWidth(121);
-#else
- dateWidget->setFixedWidth(120);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ dateWidget->setFixedWidth(121);
+ } else {
+ dateWidget->setFixedWidth(120);
+ }
dateWidget->addItem(tr("All"), All);
dateWidget->addItem(tr("Today"), Today);
dateWidget->addItem(tr("This week"), ThisWeek);
@@ -75,11 +76,11 @@ TransactionView::TransactionView(QWidget *parent) :
hlayout->addWidget(dateWidget);
typeWidget = new QComboBox(this);
-#ifdef Q_OS_MAC
- typeWidget->setFixedWidth(121);
-#else
- typeWidget->setFixedWidth(120);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ typeWidget->setFixedWidth(121);
+ } else {
+ typeWidget->setFixedWidth(120);
+ }
typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
@@ -102,11 +103,11 @@ TransactionView::TransactionView(QWidget *parent) :
#if QT_VERSION >= 0x040700
amountWidget->setPlaceholderText(tr("Min amount"));
#endif
-#ifdef Q_OS_MAC
- amountWidget->setFixedWidth(97);
-#else
- amountWidget->setFixedWidth(100);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ amountWidget->setFixedWidth(97);
+ } else {
+ amountWidget->setFixedWidth(100);
+ }
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
@@ -121,11 +122,11 @@ TransactionView::TransactionView(QWidget *parent) :
vlayout->setSpacing(0);
int width = view->verticalScrollBar()->sizeHint().width();
// Cover scroll bar width with spacing
-#ifdef Q_OS_MAC
- hlayout->addSpacing(width+2);
-#else
- hlayout->addSpacing(width);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ hlayout->addSpacing(width+2);
+ } else {
+ hlayout->addSpacing(width);
+ }
// Always show scroll bar
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
view->setTabKeyNavigation(false);
@@ -341,11 +342,11 @@ void TransactionView::exportClicked()
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write()) {
- emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
+ Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
CClientUIInterface::MSG_ERROR);
}
else {
- emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
+ Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
CClientUIInterface::MSG_INFORMATION);
}
}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 092d919042..ac157fb98d 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -10,6 +10,7 @@
#include <QWidget>
#include <QKeyEvent>
+class PlatformStyle;
class TransactionFilterProxy;
class WalletModel;
@@ -32,7 +33,7 @@ class TransactionView : public QWidget
Q_OBJECT
public:
- explicit TransactionView(QWidget *parent = 0);
+ explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = 0);
void setModel(WalletModel *model);
@@ -83,7 +84,7 @@ private:
bool eventFilter(QObject *obj, QEvent *event);
-private slots:
+private Q_SLOTS:
void contextualMenu(const QPoint &);
void dateRangeChanged();
void showDetails();
@@ -95,13 +96,13 @@ private slots:
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
-signals:
+Q_SIGNALS:
void doubleClicked(const QModelIndex&);
/** Fired when a message should be reported to the user */
void message(const QString &title, const QString &message, unsigned int style);
-public slots:
+public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 386cf31d73..5e26f3e01b 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -84,7 +84,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QTextCharFormat bold;
bold.setFontWeight(QFont::Bold);
- foreach (const QString &line, coreOptions.split("\n")) {
+ Q_FOREACH (const QString &line, coreOptions.split("\n")) {
if (line.startsWith(" -"))
{
cursor.currentTable()->appendRows(1);
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 288b985f13..47282ae2d0 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -31,7 +31,7 @@ private:
Ui::HelpMessageDialog *ui;
QString text;
-private slots:
+private Q_SLOTS:
void on_okButton_accepted();
};
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 892947bf3a..ba8c28464d 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -12,9 +12,10 @@
#include <QHBoxLayout>
#include <QLabel>
-WalletFrame::WalletFrame(BitcoinGUI *_gui) :
+WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) :
QFrame(_gui),
- gui(_gui)
+ gui(_gui),
+ platformStyle(platformStyle)
{
// Leave HBox hook for adding a list view later
QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
@@ -42,7 +43,7 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0)
return false;
- WalletView *walletView = new WalletView(this);
+ WalletView *walletView = new WalletView(platformStyle, this);
walletView->setBitcoinGUI(gui);
walletView->setClientModel(clientModel);
walletView->setWalletModel(walletModel);
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index eea97defc9..9a56e97f9c 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -10,6 +10,7 @@
class BitcoinGUI;
class ClientModel;
+class PlatformStyle;
class SendCoinsRecipient;
class WalletModel;
class WalletView;
@@ -23,7 +24,7 @@ class WalletFrame : public QFrame
Q_OBJECT
public:
- explicit WalletFrame(BitcoinGUI *_gui = 0);
+ explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = 0);
~WalletFrame();
void setClientModel(ClientModel *clientModel);
@@ -45,9 +46,11 @@ private:
bool bOutOfSync;
+ const PlatformStyle *platformStyle;
+
WalletView *currentWalletView();
-public slots:
+public Q_SLOTS:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 9b8be76beb..f580853732 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -25,9 +25,9 @@
#include <QSet>
#include <QTimer>
-using namespace std;
+#include <boost/foreach.hpp>
-WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
+WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
@@ -39,7 +39,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
fForceCheckBalanceChanged = false;
addressTableModel = new AddressTableModel(wallet, this);
- transactionTableModel = new TransactionTableModel(wallet, this);
+ transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
// This timer will be fired repeatedly to update the balance
@@ -107,7 +107,7 @@ void WalletModel::updateStatus()
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
if(cachedEncryptionStatus != newEncryptionStatus)
- emit encryptionStatusChanged(newEncryptionStatus);
+ Q_EMIT encryptionStatusChanged(newEncryptionStatus);
}
void WalletModel::pollBalanceChanged()
@@ -159,7 +159,7 @@ void WalletModel::checkBalanceChanged()
cachedWatchOnlyBalance = newWatchOnlyBalance;
cachedWatchUnconfBalance = newWatchUnconfBalance;
cachedWatchImmatureBalance = newWatchImmatureBalance;
- emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
+ Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
}
}
@@ -180,7 +180,7 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label
void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
{
fHaveWatchOnly = fHaveWatchonly;
- emit notifyWatchonlyChanged(fHaveWatchonly);
+ Q_EMIT notifyWatchonlyChanged(fHaveWatchonly);
}
bool WalletModel::validateAddress(const QString &address)
@@ -205,7 +205,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
int nAddresses = 0;
// Pre-check input data for validity
- foreach(const SendCoinsRecipient &rcp, recipients)
+ Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
{
if (rcp.fSubtractFeeFromAmount)
fSubtractFeeFromAmount = true;
@@ -285,7 +285,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
- emit message(tr("Send Coins"), QString::fromStdString(strFailReason),
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
@@ -306,7 +306,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
LOCK2(cs_main, wallet->cs_wallet);
CWalletTx *newTx = transaction.getTransaction();
- foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
if (rcp.paymentRequest.IsInitialized())
{
@@ -337,7 +337,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
// Add addresses / update labels that we've sent to to the address book,
// and emit coinsSent signal for each recipient
- foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
// Don't touch the address book when we have a payment request
if (!rcp.paymentRequest.IsInitialized())
@@ -361,7 +361,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
}
}
}
- emit coinsSent(wallet, rcp, transaction_array);
+ Q_EMIT coinsSent(wallet, rcp, transaction_array);
}
checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
@@ -521,7 +521,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock()
if(was_locked)
{
// Request UI to unlock wallet
- emit requireUnlock();
+ Q_EMIT requireUnlock();
}
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
bool valid = getEncryptionStatus() != Locked;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index e263438880..c29682e4f6 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -17,6 +17,7 @@
class AddressTableModel;
class OptionsModel;
+class PlatformStyle;
class RecentRequestsTableModel;
class TransactionTableModel;
class WalletModelTransaction;
@@ -100,7 +101,7 @@ class WalletModel : public QObject
Q_OBJECT
public:
- explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
+ explicit WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
~WalletModel();
enum StatusCode // Returned by sendCoins
@@ -227,7 +228,7 @@ private:
void unsubscribeFromCoreSignals();
void checkBalanceChanged();
-signals:
+Q_SIGNALS:
// Signal that balance in wallet changed
void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
@@ -252,7 +253,7 @@ signals:
// Watch-only address added
void notifyWatchonlyChanged(bool fHaveWatchonly);
-public slots:
+public Q_SLOTS:
/* Wallet status might have changed */
void updateStatus();
/* New transaction, or transaction changed status */
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index 206bb7c774..6a9b2d5bd3 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -81,7 +81,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
CAmount WalletModelTransaction::getTotalTransactionAmount()
{
CAmount totalTransactionAmount = 0;
- foreach(const SendCoinsRecipient &rcp, recipients)
+ Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
{
totalTransactionAmount += rcp.amount;
}
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 956c8b8913..fa96f62e03 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -11,8 +11,8 @@
#include "guiutil.h"
#include "optionsmodel.h"
#include "overviewpage.h"
+#include "platformstyle.h"
#include "receivecoinsdialog.h"
-#include "scicon.h"
#include "sendcoinsdialog.h"
#include "signverifymessagedialog.h"
#include "transactiontablemodel.h"
@@ -29,31 +29,32 @@
#include <QPushButton>
#include <QVBoxLayout>
-WalletView::WalletView(QWidget *parent):
+WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent):
QStackedWidget(parent),
clientModel(0),
- walletModel(0)
+ walletModel(0),
+ platformStyle(platformStyle)
{
// Create tabs
- overviewPage = new OverviewPage();
+ overviewPage = new OverviewPage(platformStyle);
transactionsPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout();
QHBoxLayout *hbox_buttons = new QHBoxLayout();
- transactionView = new TransactionView(this);
+ transactionView = new TransactionView(platformStyle, this);
vbox->addWidget(transactionView);
QPushButton *exportButton = new QPushButton(tr("&Export"), this);
exportButton->setToolTip(tr("Export the data in the current tab to a file"));
-#ifndef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- exportButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
+ if (platformStyle->getImagesOnButtons()) {
+ exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
hbox_buttons->addStretch();
hbox_buttons->addWidget(exportButton);
vbox->addLayout(hbox_buttons);
transactionsPage->setLayout(vbox);
- receiveCoinsPage = new ReceiveCoinsDialog();
- sendCoinsPage = new SendCoinsDialog();
+ receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
+ sendCoinsPage = new SendCoinsDialog(platformStyle);
addWidget(overviewPage);
addWidget(transactionsPage);
@@ -153,7 +154,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int
QString address = ttm->data(index, TransactionTableModel::AddressRole).toString();
QString label = ttm->data(index, TransactionTableModel::LabelRole).toString();
- emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label);
+ Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label);
}
void WalletView::gotoOverviewPage()
@@ -182,7 +183,7 @@ void WalletView::gotoSendCoinsPage(QString addr)
void WalletView::gotoSignMessageTab(QString addr)
{
// calls show() in showTab_SM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
+ SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
signVerifyMessageDialog->setModel(walletModel);
signVerifyMessageDialog->showTab_SM(true);
@@ -194,7 +195,7 @@ void WalletView::gotoSignMessageTab(QString addr)
void WalletView::gotoVerifyMessageTab(QString addr)
{
// calls show() in showTab_VM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
+ SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
signVerifyMessageDialog->setModel(walletModel);
signVerifyMessageDialog->showTab_VM(true);
@@ -215,7 +216,7 @@ void WalletView::showOutOfSyncWarning(bool fShow)
void WalletView::updateEncryptionStatus()
{
- emit encryptionStatusChanged(walletModel->getEncryptionStatus());
+ Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus());
}
void WalletView::encryptWallet(bool status)
@@ -239,11 +240,11 @@ void WalletView::backupWallet()
return;
if (!walletModel->backupWallet(filename)) {
- emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
+ Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
CClientUIInterface::MSG_ERROR);
}
else {
- emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
+ Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
CClientUIInterface::MSG_INFORMATION);
}
}
@@ -272,7 +273,7 @@ void WalletView::usedSendingAddresses()
{
if(!walletModel)
return;
- AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
+ AddressBookPage *dlg = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->setModel(walletModel->getAddressTableModel());
dlg->show();
@@ -282,7 +283,7 @@ void WalletView::usedReceivingAddresses()
{
if(!walletModel)
return;
- AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
+ AddressBookPage *dlg = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->setModel(walletModel->getAddressTableModel());
dlg->show();
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 1840e21e9c..f97cf1ee80 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -12,6 +12,7 @@
class BitcoinGUI;
class ClientModel;
class OverviewPage;
+class PlatformStyle;
class ReceiveCoinsDialog;
class SendCoinsDialog;
class SendCoinsRecipient;
@@ -34,7 +35,7 @@ class WalletView : public QStackedWidget
Q_OBJECT
public:
- explicit WalletView(QWidget *parent);
+ explicit WalletView(const PlatformStyle *platformStyle, QWidget *parent);
~WalletView();
void setBitcoinGUI(BitcoinGUI *gui);
@@ -64,8 +65,9 @@ private:
TransactionView *transactionView;
QProgressDialog *progressDialog;
+ const PlatformStyle *platformStyle;
-public slots:
+public Q_SLOTS:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
@@ -105,7 +107,7 @@ public slots:
/** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress);
-signals:
+Q_SIGNALS:
/** Signal that we want to show the main window */
void showNormalIfMinimized();
/** Fired when a message should be reported to the user */
diff --git a/src/rest.cpp b/src/rest.cpp
index 1fce7dfc9c..0dd238b683 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chain.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "main.h"
@@ -20,7 +21,7 @@
using namespace std;
-static const int MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
+static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
enum RetFormat {
RF_UNDEF,
@@ -65,6 +66,7 @@ public:
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
+extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);
static RestErr RESTERR(enum HTTPStatusCode status, string message)
{
@@ -134,14 +136,14 @@ static bool rest_headers(AcceptedConnection* conn,
if (!ParseHashStr(hashStr, hash))
throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
- std::vector<CBlockHeader> headers;
+ std::vector<const CBlockIndex *> headers;
headers.reserve(count);
{
LOCK(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL;
while (pindex != NULL && chainActive.Contains(pindex)) {
- headers.push_back(pindex->GetBlockHeader());
+ headers.push_back(pindex);
if (headers.size() == (unsigned long)count)
break;
pindex = chainActive.Next(pindex);
@@ -149,8 +151,8 @@ static bool rest_headers(AcceptedConnection* conn,
}
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
- BOOST_FOREACH(const CBlockHeader &header, headers) {
- ssHeader << header;
+ BOOST_FOREACH(const CBlockIndex *pindex, headers) {
+ ssHeader << pindex->GetBlockHeader();
}
switch (rf) {
@@ -166,6 +168,16 @@ static bool rest_headers(AcceptedConnection* conn,
return true;
}
+ case RF_JSON: {
+ UniValue jsonHeaders(UniValue::VARR);
+ BOOST_FOREACH(const CBlockIndex *pindex, headers) {
+ jsonHeaders.push_back(blockheaderToJSON(pindex));
+ }
+ string strJSON = jsonHeaders.write() + "\n";
+ conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ return true;
+ }
+
default: {
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 85229e9857..80d49490d2 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -3,13 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "amount.h"
+#include "chain.h"
+#include "chainparams.h"
#include "checkpoints.h"
+#include "coins.h"
#include "consensus/validation.h"
#include "main.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
+#include "streams.h"
#include "sync.h"
+#include "txmempool.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <stdint.h>
@@ -51,6 +58,31 @@ double GetDifficulty(const CBlockIndex* blockindex)
return dDiff;
}
+UniValue blockheaderToJSON(const CBlockIndex* blockindex)
+{
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
+ int confirmations = -1;
+ // Only report confirmations if the block is on the main chain
+ if (chainActive.Contains(blockindex))
+ confirmations = chainActive.Height() - blockindex->nHeight + 1;
+ result.push_back(Pair("confirmations", confirmations));
+ result.push_back(Pair("height", blockindex->nHeight));
+ result.push_back(Pair("version", blockindex->nVersion));
+ result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
+ result.push_back(Pair("time", (int64_t)blockindex->nTime));
+ result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce));
+ result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
+ result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
+ result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
+
+ if (blockindex->pprev)
+ result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
+ CBlockIndex *pnext = chainActive.Next(blockindex);
+ if (pnext)
+ result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
+ return result;
+}
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
@@ -92,7 +124,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
return result;
}
-
UniValue getblockcount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -162,7 +193,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
- " \"fee\" : n, (numeric) transaction fee in bitcoins\n"
+ " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
@@ -255,6 +286,62 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
+UniValue getblockheader(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "getblockheader \"hash\" ( verbose )\n"
+ "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
+ "If verbose is true, returns an Object with information about blockheader <hash>.\n"
+ "\nArguments:\n"
+ "1. \"hash\" (string, required) The block hash\n"
+ "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
+ "\nResult (for verbose = true):\n"
+ "{\n"
+ " \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
+ " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
+ " \"height\" : n, (numeric) The block height or index\n"
+ " \"version\" : n, (numeric) The block version\n"
+ " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
+ " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"nonce\" : n, (numeric) The nonce\n"
+ " \"bits\" : \"1d00ffff\", (string) The bits\n"
+ " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
+ " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
+ " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
+ "}\n"
+ "\nResult (for verbose=false):\n"
+ "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ );
+
+ LOCK(cs_main);
+
+ std::string strHash = params[0].get_str();
+ uint256 hash(uint256S(strHash));
+
+ bool fVerbose = true;
+ if (params.size() > 1)
+ fVerbose = params[1].get_bool();
+
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ CBlockIndex* pblockindex = mapBlockIndex[hash];
+
+ if (!fVerbose)
+ {
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ ssBlock << pblockindex->GetBlockHeader();
+ std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
+ return strHex;
+ }
+
+ return blockheaderToJSON(pblockindex);
+}
+
UniValue getblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
@@ -375,7 +462,7 @@ UniValue gettxout(const UniValue& params, bool fHelp)
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
- " \"value\" : x.xxx, (numeric) The transaction value in btc\n"
+ " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"code\", (string) \n"
" \"hex\" : \"hex\", (string) \n"
@@ -469,6 +556,36 @@ UniValue verifychain(const UniValue& params, bool fHelp)
return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
}
+/** Implementation of IsSuperMajority with better feedback */
+static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
+{
+ int nFound = 0;
+ CBlockIndex* pstart = pindex;
+ for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
+ {
+ if (pstart->nVersion >= minVersion)
+ ++nFound;
+ pstart = pstart->pprev;
+ }
+
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("status", nFound >= nRequired));
+ rv.push_back(Pair("found", nFound));
+ rv.push_back(Pair("required", nRequired));
+ rv.push_back(Pair("window", consensusParams.nMajorityWindow));
+ return rv;
+}
+
+static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
+{
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("id", name));
+ rv.push_back(Pair("version", version));
+ rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
+ rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
+ return rv;
+}
+
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -484,6 +601,21 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
+ " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
+ " \"pruneheight\": xxxxxx, (numeric) heighest block available\n"
+ " \"softforks\": [ (array) status of softforks in progress\n"
+ " {\n"
+ " \"id\": \"xxxx\", (string) name of softfork\n"
+ " \"version\": xx, (numeric) block version\n"
+ " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
+ " \"status\": xx, (boolean) true if threshold reached\n"
+ " \"found\": xx, (numeric) number of blocks with the new version found\n"
+ " \"required\": xx, (numeric) number of blocks required to trigger\n"
+ " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
+ " },\n"
+ " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
+ " }, ...\n"
+ " ]\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -501,6 +633,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
+
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ CBlockIndex* tip = chainActive.Tip();
+ UniValue softforks(UniValue::VARR);
+ softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
+ softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
+ obj.push_back(Pair("softforks", softforks));
+
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();
@@ -627,6 +767,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
"{\n"
" \"size\": xxxxx (numeric) Current tx count\n"
" \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
+ " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
@@ -636,6 +777,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
+ ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));
return ret;
}
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4c6b47e4a0..b41e960e8a 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -71,6 +71,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 1 },
{ "listunspent", 2 },
{ "getblock", 1 },
+ { "getblockheader", 1 },
{ "gettransaction", 1 },
{ "getrawtransaction", 1 },
{ "createrawtransaction", 0 },
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index f332814611..b7d4ff58fc 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h"
+#include "chain.h"
#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
@@ -14,15 +15,15 @@
#include "net.h"
#include "pow.h"
#include "rpcserver.h"
+#include "txmempool.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
#include <stdint.h>
#include <boost/assign/list_of.hpp>
+#include <boost/shared_ptr.hpp>
#include "univalue/univalue.h"
@@ -92,7 +93,6 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
-#ifdef ENABLE_WALLET
UniValue getgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -127,8 +127,6 @@ UniValue generate(const UniValue& params, bool fHelp)
+ HelpExampleCli("generate", "11")
);
- if (pwalletMain == NULL)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (!Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest");
@@ -136,7 +134,13 @@ UniValue generate(const UniValue& params, bool fHelp)
int nHeightEnd = 0;
int nHeight = 0;
int nGenerate = params[0].get_int();
- CReserveKey reservekey(pwalletMain);
+
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
+ //throw an error if no script was provided
+ if (!coinbaseScript->reserveScript.size())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked
LOCK(cs_main);
@@ -148,9 +152,9 @@ UniValue generate(const UniValue& params, bool fHelp)
UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd)
{
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
@@ -166,11 +170,13 @@ UniValue generate(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
+
+ //mark script as important because it was used at least for one coinbase output
+ coinbaseScript->KeepScript();
}
return blockHashes;
}
-
UniValue setgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
@@ -193,8 +199,6 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
+ HelpExampleRpc("setgenerate", "true, 1")
);
- if (pwalletMain == NULL)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network");
@@ -212,12 +216,10 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
mapArgs["-gen"] = (fGenerate ? "1" : "0");
mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
- GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
+ GenerateBitcoins(fGenerate, nGenProcLimit, Params());
return NullUniValue;
}
-#endif
-
UniValue getmininginfo(const UniValue& params, bool fHelp)
{
@@ -257,9 +259,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
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)));
-#endif
return obj;
}
@@ -669,16 +669,15 @@ UniValue estimatefee(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatefee nblocks\n"
- "\nEstimates the approximate fee per kilobyte\n"
- "needed for a transaction to begin confirmation\n"
- "within nblocks blocks.\n"
+ "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
+ "confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
- "n : (numeric) estimated fee-per-kilobyte\n"
+ "n (numeric) estimated fee-per-kilobyte\n"
"\n"
- "-1.0 is returned if not enough transactions and\n"
- "blocks have been observed to make an estimate.\n"
+ "A negative value is returned if not enough transactions and blocks\n"
+ "have been observed to make an estimate.\n"
"\nExample:\n"
+ HelpExampleCli("estimatefee", "6")
);
@@ -701,16 +700,15 @@ UniValue estimatepriority(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
- "\nEstimates the approximate priority\n"
- "a zero-fee transaction needs to begin confirmation\n"
- "within nblocks blocks.\n"
+ "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
+ "confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
- "n : (numeric) estimated priority\n"
+ "n (numeric) estimated priority\n"
"\n"
- "-1.0 is returned if not enough transactions and\n"
- "blocks have been observed to make an estimate.\n"
+ "A negative value is returned if not enough transactions and blocks\n"
+ "have been observed to make an estimate.\n"
"\nExample:\n"
+ HelpExampleCli("estimatepriority", "6")
);
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index cab57d7027..6d10d1ce15 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -12,6 +12,7 @@
#include "rpcserver.h"
#include "timedata.h"
#include "util.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
@@ -59,8 +60,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc/kb\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
+ " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 1572b16687..56ec59171d 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -4,6 +4,7 @@
#include "rpcserver.h"
+#include "chainparams.h"
#include "clientversion.h"
#include "main.h"
#include "net.h"
@@ -12,6 +13,7 @@
#include "sync.h"
#include "timedata.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "version.h"
#include <boost/foreach.hpp>
@@ -421,7 +423,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ],\n"
- " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
+ " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"
@@ -441,8 +443,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
- obj.push_back(Pair("subversion",
- FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
+ obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
@@ -515,7 +516,7 @@ UniValue setban(const UniValue& params, bool fHelp)
if (params.size() == 4 && params[3].isTrue())
absolute = true;
- isSubnet ? CNode::Ban(subNet, banTime, absolute) : CNode::Ban(netAddr, banTime, absolute);
+ isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
//disconnect possible nodes
while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
@@ -527,6 +528,7 @@ UniValue setban(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
}
+ DumpBanlist(); //store banlist to disk
return NullUniValue;
}
@@ -541,15 +543,19 @@ UniValue listbanned(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listbanned", "")
);
- std::map<CSubNet, int64_t> banMap;
+ banmap_t banMap;
CNode::GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
- for (std::map<CSubNet, int64_t>::iterator it = banMap.begin(); it != banMap.end(); it++)
+ for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
{
+ CBanEntry banEntry = (*it).second;
UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", (*it).first.ToString()));
- rec.push_back(Pair("banned_untill", (*it).second));
+ rec.push_back(Pair("banned_until", banEntry.nBanUntil));
+ rec.push_back(Pair("ban_created", banEntry.nCreateTime));
+ rec.push_back(Pair("ban_reason", banEntry.banReasonToString()));
+
bannedAddresses.push_back(rec);
}
@@ -568,6 +574,7 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
);
CNode::ClearBanned();
+ DumpBanlist(); //store banlist to disk
return NullUniValue;
}
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 89dec2977e..2e5c913734 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -6,6 +6,7 @@
#include "rpcprotocol.h"
#include "clientversion.h"
+#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -13,6 +14,7 @@
#include "version.h"
#include <stdint.h>
+#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
@@ -287,3 +289,68 @@ UniValue JSONRPCError(int code, const string& message)
error.push_back(Pair("message", message));
return error;
}
+
+/** Username used when cookie authentication is in use (arbitrary, only for
+ * recognizability in debugging/logging purposes)
+ */
+static const std::string COOKIEAUTH_USER = "__cookie__";
+/** Default name for auth cookie file */
+static const std::string COOKIEAUTH_FILE = ".cookie";
+
+boost::filesystem::path GetAuthCookieFile()
+{
+ boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ if (!path.is_complete()) path = GetDataDir() / path;
+ return path;
+}
+
+bool GenerateAuthCookie(std::string *cookie_out)
+{
+ unsigned char rand_pwd[32];
+ GetRandBytes(rand_pwd, 32);
+ std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
+
+ /** the umask determines what permissions are used to create this file -
+ * these are set to 077 in init.cpp unless overridden with -sysperms.
+ */
+ std::ofstream file;
+ boost::filesystem::path filepath = GetAuthCookieFile();
+ file.open(filepath.string().c_str());
+ if (!file.is_open()) {
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
+ return false;
+ }
+ file << cookie;
+ file.close();
+ LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
+
+ if (cookie_out)
+ *cookie_out = cookie;
+ return true;
+}
+
+bool GetAuthCookie(std::string *cookie_out)
+{
+ std::ifstream file;
+ std::string cookie;
+ boost::filesystem::path filepath = GetAuthCookieFile();
+ file.open(filepath.string().c_str());
+ if (!file.is_open())
+ return false;
+ std::getline(file, cookie);
+ file.close();
+
+ if (cookie_out)
+ *cookie_out = cookie;
+ return true;
+}
+
+void DeleteAuthCookie()
+{
+ try {
+ boost::filesystem::remove(GetAuthCookieFile());
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
+ }
+}
+
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index ccd2439c9f..2360ec2c60 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -14,6 +14,7 @@
#include <boost/iostreams/stream.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
+#include <boost/filesystem.hpp>
#include "univalue/univalue.h"
@@ -165,4 +166,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
+/** Get name of RPC authentication cookie file */
+boost::filesystem::path GetAuthCookieFile();
+/** Generate a new RPC authentication cookie and write it to disk */
+bool GenerateAuthCookie(std::string *cookie_out);
+/** Read the RPC authentication cookie from disk */
+bool GetAuthCookie(std::string *cookie_out);
+/** Delete RPC authentication cookie from disk */
+void DeleteAuthCookie();
+
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 20394fc2c1..a3246b41fb 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -4,6 +4,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
+#include "chain.h"
+#include "coins.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
@@ -11,13 +13,16 @@
#include "main.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
+#include "txmempool.h"
#include "uint256.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif
@@ -144,7 +149,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
- " \"value\" : x.xxx, (numeric) The value in btc\n"
+ " \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -330,7 +335,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
" ]\n"
"2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
" {\n"
- " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n"
+ " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the " + CURRENCY_UNIT + " amount\n"
" ,...\n"
" }\n"
@@ -417,7 +422,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
- " \"value\" : x.xxx, (numeric) The value in btc\n"
+ " \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 2f28971589..68091010f7 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -11,7 +11,6 @@
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
-#include "utilmoneystr.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -121,10 +120,10 @@ void RPCTypeCheckObj(const UniValue& o,
CAmount AmountFromValue(const UniValue& value)
{
- if (!value.isReal() && !value.isNum())
- throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
+ if (!value.isNum() && !value.isStr())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
CAmount amount;
- if (!ParseMoney(value.getValStr(), amount))
+ if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
if (!MoneyRange(amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
@@ -133,7 +132,12 @@ CAmount AmountFromValue(const UniValue& value)
UniValue ValueFromAmount(const CAmount& amount)
{
- return UniValue(UniValue::VREAL, FormatMoney(amount));
+ bool sign = amount < 0;
+ int64_t n_abs = (sign ? -amount : amount);
+ int64_t quotient = n_abs / COIN;
+ int64_t remainder = n_abs % COIN;
+ return UniValue(UniValue::VNUM,
+ strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
uint256 ParseHashV(const UniValue& v, string strName)
@@ -289,6 +293,7 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "getblockcount", &getblockcount, true },
{ "blockchain", "getblock", &getblock, true },
{ "blockchain", "getblockhash", &getblockhash, true },
+ { "blockchain", "getblockheader", &getblockheader, true },
{ "blockchain", "getchaintips", &getchaintips, true },
{ "blockchain", "getdifficulty", &getdifficulty, true },
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true },
@@ -306,12 +311,10 @@ static const CRPCCommand vRPCCommands[] =
{ "mining", "prioritisetransaction", &prioritisetransaction, true },
{ "mining", "submitblock", &submitblock, true },
-#ifdef ENABLE_WALLET
/* Coin generation */
{ "generating", "getgenerate", &getgenerate, true },
{ "generating", "setgenerate", &setgenerate, true },
{ "generating", "generate", &generate, true },
-#endif
/* Raw transactions */
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true },
@@ -598,28 +601,18 @@ void StartRPCThreads()
strAllowed += subnet.ToString() + " ";
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
- strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
- if (((mapArgs["-rpcpassword"] == "") ||
- (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
+ if (mapArgs["-rpcpassword"] == "")
{
- unsigned char rand_pwd[32];
- GetRandBytes(rand_pwd, 32);
- uiInterface.ThreadSafeMessageBox(strprintf(
- _("To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file:\n"
- "%s\n"
- "It is recommended you use the following random password:\n"
- "rpcuser=bitcoinrpc\n"
- "rpcpassword=%s\n"
- "(you do not need to remember this password)\n"
- "The username and password MUST NOT be the same.\n"
- "If the file does not exist, create it with owner-readable-only file permissions.\n"
- "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"),
- GetConfigFile().string(),
- EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
- "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
- StartShutdown();
- return;
+ LogPrintf("No rpcpassword set - using random cookie authentication\n");
+ if (!GenerateAuthCookie(&strRPCUserColonPass)) {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
+ "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return;
+ }
+ } else {
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
assert(rpc_io_service == NULL);
@@ -759,17 +752,19 @@ void StopRPCThreads()
{
acceptor->cancel(ec);
if (ec)
- LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message());
+ LogPrintf("%s: Warning: %s when cancelling acceptor\n", __func__, ec.message());
}
rpc_acceptors.clear();
BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers)
{
timer.second->cancel(ec);
if (ec)
- LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message());
+ LogPrintf("%s: Warning: %s when cancelling timer\n", __func__, ec.message());
}
deadlineTimers.clear();
+ DeleteAuthCookie();
+
rpc_io_service->stop();
g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)
@@ -932,13 +927,6 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
if (!valRequest.read(strRequest))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
- // Return immediately if in warmup
- {
- LOCK(cs_rpcWarmup);
- if (fRPCInWarmup)
- throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
- }
-
string strReply;
// singleton request
@@ -1010,6 +998,13 @@ void ServiceConnection(AcceptedConnection *conn)
UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
{
+ // Return immediately if in warmup
+ {
+ LOCK(cs_rpcWarmup);
+ if (fRPCInWarmup)
+ throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
+ }
+
// Find method
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 45af10c2a8..89d3980223 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -234,6 +234,7 @@ extern UniValue settxfee(const UniValue& params, bool fHelp);
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
extern UniValue getblockhash(const UniValue& params, bool fHelp);
+extern UniValue getblockheader(const UniValue& params, bool fHelp);
extern UniValue getblock(const UniValue& params, bool fHelp);
extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
extern UniValue gettxout(const UniValue& params, bool fHelp);
diff --git a/src/script/script.h b/src/script/script.h
index c09899aabd..e39ca57f4f 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -609,4 +609,13 @@ public:
}
};
+class CReserveScript
+{
+public:
+ CScript reserveScript;
+ virtual void KeepScript() {}
+ CReserveScript() {}
+ virtual ~CReserveScript() {}
+};
+
#endif // BITCOIN_SCRIPT_SCRIPT_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 4543ca303f..8b43183b6d 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -5,9 +5,10 @@
#include "script/sign.h"
-#include "primitives/transaction.h"
#include "key.h"
#include "keystore.h"
+#include "policy/policy.h"
+#include "primitives/transaction.h"
#include "script/standard.h"
#include "uint256.h"
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index ce50e3aad8..66657127ab 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -180,26 +180,6 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
return -1;
}
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
-{
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
-
- if (whichType == TX_MULTISIG)
- {
- unsigned char m = vSolutions.front()[0];
- unsigned char n = vSolutions.back()[0];
- // Support up to x-of-3 multisig txns as standard
- if (n < 1 || n > 3)
- return false;
- if (m < 1 || m > n)
- return false;
- }
-
- return whichType != TX_NONSTANDARD;
-}
-
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
vector<valtype> vSolutions;
diff --git a/src/script/standard.h b/src/script/standard.h
index 3b401dfe4f..46ae5f9f10 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -39,23 +39,6 @@ extern unsigned nMaxDatacarrierBytes;
*/
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
-/**
- * Standard script verification flags that standard transactions will comply
- * with. However scripts violating these flags may still be present in valid
- * blocks and we must accept those blocks.
- */
-static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
- SCRIPT_VERIFY_DERSIG |
- SCRIPT_VERIFY_STRICTENC |
- SCRIPT_VERIFY_MINIMALDATA |
- SCRIPT_VERIFY_NULLDUMMY |
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
- SCRIPT_VERIFY_CLEANSTACK |
- SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
-
-/** For convenience, standard but not mandatory verify flags. */
-static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
-
enum txnouttype
{
TX_NONSTANDARD,
@@ -86,7 +69,6 @@ const char* GetTxnOutputType(txnouttype t);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
diff --git a/src/sync.cpp b/src/sync.cpp
index a422939964..1837e8d53d 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -33,20 +33,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
//
struct CLockLocation {
- CLockLocation(const char* pszName, const char* pszFile, int nLine)
+ CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
{
mutexName = pszName;
sourceFile = pszFile;
sourceLine = nLine;
+ fTry = fTryIn;
}
std::string ToString() const
{
- return mutexName + " " + sourceFile + ":" + itostr(sourceLine);
+ return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
std::string MutexName() const { return mutexName; }
+ bool fTry;
private:
std::string mutexName;
std::string sourceFile;
@@ -62,23 +64,52 @@ static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
+ // We attempt to not assert on probably-not deadlocks by assuming that
+ // a try lock will immediately have otherwise bailed if it had
+ // failed to get the lock
+ // We do this by, for the locks which triggered the potential deadlock,
+ // in either lockorder, checking that the second of the two which is locked
+ // is only a TRY_LOCK, ignoring locks if they are reentrant.
+ bool firstLocked = false;
+ bool secondLocked = false;
+ bool onlyMaybeDeadlock = false;
+
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
LogPrintf("Previous lock order was:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ firstLocked = false;
+ secondLocked = false;
LogPrintf("Current lock order is:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ assert(onlyMaybeDeadlock);
}
static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
@@ -101,10 +132,8 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
lockorders[p1] = (*lockstack);
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
- if (lockorders.count(p2)) {
+ if (lockorders.count(p2))
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
- break;
- }
}
}
dd_mutex.unlock();
@@ -119,7 +148,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}
void LeaveCritical()
diff --git a/src/sync.h b/src/sync.h
index 78b9043477..705647e4a5 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -101,7 +101,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
/** Wrapper around boost::unique_lock<Mutex> */
template <typename Mutex>
-class CMutexLock
+class SCOPED_LOCKABLE CMutexLock
{
private:
boost::unique_lock<Mutex> lock;
@@ -129,7 +129,7 @@ private:
}
public:
- CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
+ CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -137,7 +137,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
+ CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
@@ -148,7 +148,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- ~CMutexLock()
+ ~CMutexLock() UNLOCK_FUNCTION()
{
if (lock.owns_lock())
LeaveCritical();
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index bf25548755..da296a0461 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -2,12 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
// Unit tests for denial-of-service detection/prevention code
-//
-
-
+#include "chainparams.h"
#include "keystore.h"
#include "main.h"
#include "net.h"
diff --git a/src/test/README.md b/src/test/README.md
index 7efce6f052..e36112bd4f 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -18,4 +18,16 @@ uint256_tests.cpp.
For further reading, I found the following website to be helpful in
explaining how the boost unit test framework works:
-[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). \ No newline at end of file
+[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).
+
+test_bitcoin has some built-in command-line arguments; for
+example, to run just the getarg_tests verbosely:
+
+ test_bitcoin --log_level=all --run_test=getarg_tests
+
+... or to run just the doubledash test:
+
+ test_bitcoin --run_test=getarg_tests/doubledash
+
+Run test_bitcoin --help for the full list.
+
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 38dcc6023c..b8d5606cc3 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -2,17 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
// Unit tests for alert system
-//
#include "alert.h"
#include "chain.h"
#include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
-
-#include "main.h"
+#include "main.h" // For PartitionCheck
#include "serialize.h"
#include "streams.h"
#include "util.h"
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 0d815c27fd..69084213a2 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -88,12 +88,23 @@ void RunTest(const TestVector &test) {
unsigned char data[74];
key.Encode(data);
pubkey.Encode(data);
+
// Test private key
CBitcoinExtKey b58key; b58key.SetKey(key);
BOOST_CHECK(b58key.ToString() == derive.prv);
+
+ CBitcoinExtKey b58keyDecodeCheck(derive.prv);
+ CExtKey checkKey = b58keyDecodeCheck.GetKey();
+ assert(checkKey == key); //ensure a base58 decoded key also matches
+
// Test public key
CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);
BOOST_CHECK(b58pubkey.ToString() == derive.pub);
+
+ CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub);
+ CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();
+ assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches
+
// Derive new keys
CExtKey keyNew;
BOOST_CHECK(key.Derive(keyNew, derive.nChild));
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 1bda8a7ea1..6b30d6aa8a 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -469,7 +469,7 @@ static std::vector<unsigned char> RandomData()
BOOST_AUTO_TEST_CASE(rolling_bloom)
{
// last-100-entry, 1% false positive:
- CRollingBloomFilter rb1(100, 0.01, 0);
+ CRollingBloomFilter rb1(100, 0.01);
// Overfill:
static const int DATASIZE=399;
@@ -500,7 +500,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
BOOST_CHECK(nHits < 175);
BOOST_CHECK(rb1.contains(data[DATASIZE-1]));
- rb1.clear();
+ rb1.reset();
BOOST_CHECK(!rb1.contains(data[DATASIZE-1]));
// Now roll through data, make sure last 100 entries
@@ -527,7 +527,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
BOOST_CHECK(nHits < 100);
// last-1000-entry, 0.01% false positive:
- CRollingBloomFilter rb2(1000, 0.001, 0);
+ CRollingBloomFilter rb2(1000, 0.001);
for (int i = 0; i < DATASIZE; i++) {
rb2.insert(data[i]);
}
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 51530c4de5..f7e2470617 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -4,7 +4,8 @@
#include "clientversion.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "main.h" // For CheckBlock
+#include "primitives/block.h"
#include "test/test_bitcoin.h"
#include "utiltime.h"
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 34b311b804..13d848311a 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -70,9 +70,9 @@ public:
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins);
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
- ret += memusage::DynamicUsage(it->second.coins);
+ ret += it->second.coins.DynamicMemoryUsage();
}
- BOOST_CHECK_EQUAL(memusage::DynamicUsage(*this), ret);
+ BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
}
};
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
index 6090421cb6..afd35af503 100644
--- a/src/test/data/bitcoin-util-test.json
+++ b/src/test/data/bitcoin-util-test.json
@@ -52,7 +52,7 @@
["-create",
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
- "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]",
+ "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
"sign=ALL",
"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
"output_cmp": "txcreatesign.hex"
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 9def4042da..20bdbd08a5 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -137,6 +137,8 @@
["Argument missing"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blockheight nLockTime=0"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
@@ -145,10 +147,14 @@
["Argument negative with by-blocktime nLockTime=500,000,000"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Input locked"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
@@ -158,6 +164,8 @@
["Argument/tx height/time mismatch, both versions"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
diff --git a/src/test/data/txcreatesign.hex b/src/test/data/txcreatesign.hex
index 56ce28a865..a46fcc88cb 100644
--- a/src/test/data/txcreatesign.hex
+++ b/src/test/data/txcreatesign.hex
@@ -1 +1 @@
-01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
+01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index a0c5592a95..eb61a2884d 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -60,18 +60,18 @@ BOOST_AUTO_TEST_CASE(boolarg)
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
- ResetArgs("-foo -nofoo"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
-
- ResetArgs("-foo=1 -nofoo=1"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ ResetArgs("-foo -nofoo"); // -nofoo should win
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
- ResetArgs("-foo=0 -nofoo=0"); // -foo should win
+ ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
+ ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
+ BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
BOOST_CHECK(GetBoolArg("-foo", false));
@@ -150,9 +150,9 @@ BOOST_AUTO_TEST_CASE(boolargno)
BOOST_CHECK(GetBoolArg("-foo", true));
BOOST_CHECK(GetBoolArg("-foo", false));
- ResetArgs("-foo --nofoo");
- BOOST_CHECK(GetBoolArg("-foo", true));
- BOOST_CHECK(GetBoolArg("-foo", false));
+ ResetArgs("-foo --nofoo"); // --nofoo should win
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
BOOST_CHECK(GetBoolArg("-foo", true));
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 0996e13c48..2439689d7f 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
#include "txmempool.h"
#include "util.h"
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 212be0d2d6..ad79a558c2 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,12 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chainparams.h"
+#include "coins.h"
#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
#include "pubkey.h"
+#include "script/standard.h"
+#include "txmempool.h"
#include "uint256.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 6b189a6b55..b65c299adc 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -4,7 +4,7 @@
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/interpreter.h"
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 0f5e1615c6..7154476c7c 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -143,6 +143,17 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid());
BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid());
BOOST_CHECK(!CSubNet("fuzzy").IsValid());
+
+ //CNetAddr constructor test
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).IsValid());
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.1")));
+ BOOST_CHECK(!CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.2")));
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).ToString() == "127.0.0.1/255.255.255.255");
+
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).IsValid());
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:8")));
+ BOOST_CHECK(!CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:9")));
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index a436749287..b6eb39bc38 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -2,8 +2,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "chain.h"
+#include "chainparams.h"
#include "pow.h"
+#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index c38df0ecf3..7946b02855 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -120,6 +120,29 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
}
static UniValue ValueFromString(const std::string &str)
@@ -142,6 +165,24 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
+
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN);
+
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); //should fail
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); //should fail
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present
+
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); //overflow error signless
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error
}
BOOST_AUTO_TEST_CASE(json_parse_errors)
@@ -151,6 +192,9 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
// Valid, with leading or trailing whitespace
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
+
+ BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON
+ BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1);
// Invalid, initial garbage
BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
@@ -199,7 +243,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
- UniValue banned_until = find_value(o1, "banned_untill");
+ UniValue banned_until = find_value(o1, "banned_until");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0");
BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
@@ -210,7 +254,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
- banned_until = find_value(o1, "banned_untill");
+ banned_until = find_value(o1, "banned_until");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0");
int64_t now = GetTime();
BOOST_CHECK(banned_until.get_int64() > now);
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index c8cfe28729..16c9a4a868 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -5,6 +5,7 @@
#include "key.h"
#include "keystore.h"
#include "main.h"
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 3733425699..37c046935f 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -8,11 +8,11 @@
#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
#if defined(HAVE_CONSENSUS_LIB)
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index a0797d5f3f..4b96461562 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -4,13 +4,16 @@
#include "consensus/validation.h"
#include "data/sighash.json.h"
-#include "main.h"
+#include "hash.h"
+#include "main.h" // For CheckTransaction
#include "random.h"
#include "script/interpreter.h"
#include "script/script.h"
#include "serialize.h"
+#include "streams.h"
#include "test/test_bitcoin.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "version.h"
#include <iostream>
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 86a4bc6727..a904e3862f 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "chain.h"
#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index c727303ea1..8d81275a6f 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -6,8 +6,13 @@
#include "test_bitcoin.h"
+#include "chainparams.h"
+#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "key.h"
#include "main.h"
+#include "miner.h"
+#include "pubkey.h"
#include "random.h"
#include "txdb.h"
#include "ui_interface.h"
@@ -27,20 +32,22 @@ CWallet* pwalletMain;
extern bool fPrintToConsole;
extern void noui_connect();
-BasicTestingSetup::BasicTestingSetup()
+BasicTestingSetup::BasicTestingSetup(CBaseChainParams::Network network)
{
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(network);
+ noui_connect();
}
+
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
}
-TestingSetup::TestingSetup()
+TestingSetup::TestingSetup(CBaseChainParams::Network network) : BasicTestingSetup(network)
{
#ifdef ENABLE_WALLET
bitdb.MakeMock();
@@ -86,6 +93,51 @@ TestingSetup::~TestingSetup()
boost::filesystem::remove_all(pathTemp);
}
+TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
+{
+ // Generate a 100-block chain:
+ coinbaseKey.MakeNewKey(true);
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ for (int i = 0; i < COINBASE_MATURITY; i++)
+ {
+ std::vector<CMutableTransaction> noTxns;
+ CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
+ coinbaseTxns.push_back(b.vtx[0]);
+ }
+}
+
+//
+// Create a new block with just given transactions, coinbase paying to
+// scriptPubKey, and try to add it to the current chain.
+//
+CBlock
+TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
+{
+ CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey);
+ CBlock& block = pblocktemplate->block;
+
+ // Replace mempool-selected txns with just coinbase plus passed-in txns:
+ block.vtx.resize(1);
+ BOOST_FOREACH(const CMutableTransaction& tx, txns)
+ block.vtx.push_back(tx);
+ // IncrementExtraNonce creates a valid coinbase and merkleRoot
+ unsigned int extraNonce = 0;
+ IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+
+ while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce;
+
+ CValidationState state;
+ ProcessNewBlock(state, NULL, &block, true, NULL);
+
+ CBlock result = block;
+ delete pblocktemplate;
+ return result;
+}
+
+TestChain100Setup::~TestChain100Setup()
+{
+}
+
void Shutdown(void* parg)
{
exit(0);
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 2f75332d40..b9314d0611 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -1,6 +1,8 @@
#ifndef BITCOIN_TEST_TEST_BITCOIN_H
#define BITCOIN_TEST_TEST_BITCOIN_H
+#include "chainparamsbase.h"
+#include "key.h"
#include "txdb.h"
#include <boost/filesystem.hpp>
@@ -10,7 +12,7 @@
* This just configures logging and chain parameters.
*/
struct BasicTestingSetup {
- BasicTestingSetup();
+ BasicTestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -23,8 +25,30 @@ struct TestingSetup: public BasicTestingSetup {
boost::filesystem::path pathTemp;
boost::thread_group threadGroup;
- TestingSetup();
+ TestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
~TestingSetup();
};
+class CBlock;
+struct CMutableTransaction;
+class CScript;
+
+//
+// Testing fixture that pre-creates a
+// 100-block REGTEST-mode block chain
+//
+struct TestChain100Setup : public TestingSetup {
+ TestChain100Setup();
+
+ // Create a new block with just given transactions, coinbase paying to
+ // scriptPubKey, and try to add it to the current chain.
+ CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
+ const CScript& scriptPubKey);
+
+ ~TestChain100Setup();
+
+ std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions
+ CKey coinbaseKey; // private/public key needed to spend coinbase transactions
+};
+
#endif
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 9ce7aae966..e70ebddc2f 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -11,9 +11,11 @@
#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "main.h" // For CheckTransaction
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
+#include "utilstrencodings.h"
#include <map>
#include <string>
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
new file mode 100644
index 0000000000..edad18644e
--- /dev/null
+++ b/src/test/txvalidationcache_tests.cpp
@@ -0,0 +1,86 @@
+// Copyright (c) 2011-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 "consensus/validation.h"
+#include "key.h"
+#include "main.h"
+#include "miner.h"
+#include "pubkey.h"
+#include "txmempool.h"
+#include "random.h"
+#include "script/standard.h"
+#include "test/test_bitcoin.h"
+#include "utiltime.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
+
+static bool
+ToMemPool(CMutableTransaction& tx)
+{
+ LOCK(cs_main);
+
+ CValidationState state;
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, false);
+}
+
+BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
+{
+ // Make sure skipping validation of transctions that were
+ // validated going into the memory pool does not allow
+ // double-spends in blocks to pass validation when they should not.
+
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+
+ // Create a double-spend of mature coinbase txn:
+ std::vector<CMutableTransaction> spends;
+ spends.resize(2);
+ for (int i = 0; i < 2; i++)
+ {
+ spends[i].vin.resize(1);
+ spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spends[i].vin[0].prevout.n = 0;
+ spends[i].vout.resize(1);
+ spends[i].vout[0].nValue = 11*CENT;
+ spends[i].vout[0].scriptPubKey = scriptPubKey;
+
+ // Sign:
+ std::vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL);
+ BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
+ vchSig.push_back((unsigned char)SIGHASH_ALL);
+ spends[i].vin[0].scriptSig << vchSig;
+ }
+
+ CBlock block;
+
+ // Test 1: block with both of those transactions should be rejected.
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+
+ // Test 2: ... and should be rejected if spend1 is in the memory pool
+ BOOST_CHECK(ToMemPool(spends[0]));
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ mempool.clear();
+
+ // Test 3: ... and should be rejected if spend2 is in the memory pool
+ BOOST_CHECK(ToMemPool(spends[1]));
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ mempool.clear();
+
+ // Final sanity test: first spend in mempool, second in block, that's OK:
+ std::vector<CMutableTransaction> oneSpend;
+ oneSpend.push_back(spends[0]);
+ BOOST_CHECK(ToMemPool(spends[1]));
+ block = CreateAndProcessBlock(oneSpend, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
+ // spends[1] should have been removed from the mempool when the
+ // block with spends[0] is accepted:
+ BOOST_CHECK_EQUAL(mempool.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 16bc8d30f6..67cb9b9623 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
double vd = -7.21;
UniValue v7(vd);
- BOOST_CHECK(v7.isReal());
+ BOOST_CHECK(v7.isNum());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
string vs("yawn");
@@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
BOOST_CHECK(v.setFloat(-1.01));
- BOOST_CHECK(v.isReal());
+ BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
BOOST_CHECK(v.setInt((int)1023));
@@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
- objTypes["temperature"] = UniValue::VREAL;
+ objTypes["temperature"] = UniValue::VNUM;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 5cb5894251..e956cc5b90 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -418,4 +418,70 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
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_CASE(test_ParseFixedPoint)
+{
+ int64_t amount = 0;
+ BOOST_CHECK(ParseFixedPoint("0", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 0LL);
+ BOOST_CHECK(ParseFixedPoint("1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000LL);
+ BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 0LL);
+ BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -10000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 110000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 110000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1100000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 11000000LL);
+ BOOST_CHECK(ParseFixedPoint("1000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000000LL);
+ BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -100000000000LL);
+ BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1LL);
+ BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1LL);
+ BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -1LL);
+ BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000000000001LL);
+ BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 999999999999999999LL);
+ BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -999999999999999999LL);
+
+ BOOST_CHECK(!ParseFixedPoint("", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 935b784676..21ecd65238 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,6 +5,7 @@
#include "txdb.h"
+#include "chain.h"
#include "chainparams.h"
#include "hash.h"
#include "main.h"
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 1c16e2092e..c921dae45d 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -18,7 +18,7 @@
using namespace std;
CTxMemPoolEntry::CTxMemPoolEntry():
- nFee(0), nTxSize(0), nModSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false)
+ nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false)
{
nHeight = MEMPOOL_HEIGHT;
}
@@ -31,6 +31,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
{
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
nModSize = tx.CalculateModifiedSize(nTxSize);
+ nUsageSize = RecursiveDynamicUsage(tx);
}
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
@@ -101,6 +102,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
+ cachedInnerUsage += entry.DynamicMemoryUsage();
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
return true;
@@ -146,6 +148,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
removed.push_back(tx);
totalTxSize -= mapTx[hash].GetTxSize();
+ cachedInnerUsage -= mapTx[hash].DynamicMemoryUsage();
mapTx.erase(hash);
nTransactionsUpdated++;
minerPolicyEstimator->removeTx(hash);
@@ -166,7 +169,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in
continue;
const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash);
if (fSanityCheck) assert(coins);
- if (!coins || (coins->IsCoinBase() && nMemPoolHeight - coins->nHeight < COINBASE_MATURITY)) {
+ if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
transactionsToRemove.push_back(tx);
break;
}
@@ -226,6 +229,7 @@ void CTxMemPool::clear()
mapTx.clear();
mapNextTx.clear();
totalTxSize = 0;
+ cachedInnerUsage = 0;
++nTransactionsUpdated;
}
@@ -237,6 +241,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
uint64_t checkTotal = 0;
+ uint64_t innerUsage = 0;
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
@@ -245,6 +250,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0;
checkTotal += it->second.GetTxSize();
+ innerUsage += it->second.DynamicMemoryUsage();
const CTransaction& tx = it->second.GetTx();
bool fDependsWait = false;
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
@@ -299,6 +305,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
}
assert(totalTxSize == checkTotal);
+ assert(innerUsage == cachedInnerUsage);
}
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
@@ -341,7 +348,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
minerPolicyEstimator->Write(fileout);
}
catch (const std::exception&) {
- LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)");
+ LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n");
return false;
}
return true;
@@ -360,7 +367,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
minerPolicyEstimator->Read(filein);
}
catch (const std::exception&) {
- LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)");
+ LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
return false;
}
return true;
@@ -419,3 +426,8 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
return mempool.exists(txid) || base->HaveCoins(txid);
}
+
+size_t CTxMemPool::DynamicMemoryUsage() const {
+ LOCK(cs);
+ return memusage::DynamicUsage(mapTx) + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage;
+}
diff --git a/src/txmempool.h b/src/txmempool.h
index 7271a5f603..ea36ce1ad5 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -40,6 +40,7 @@ private:
CAmount nFee; //! Cached to avoid expensive parent-transaction lookups
size_t nTxSize; //! ... and avoid recomputing tx size
size_t nModSize; //! ... and modified size for priority
+ size_t nUsageSize; //! ... and total memory usage
int64_t nTime; //! Local time when entering the mempool
double dPriority; //! Priority when entering the mempool
unsigned int nHeight; //! Chain height when entering the mempool
@@ -58,6 +59,7 @@ public:
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return nHeight; }
bool WasClearAtEntry() const { return hadNoDependencies; }
+ size_t DynamicMemoryUsage() const { return nUsageSize; }
};
class CBlockPolicyEstimator;
@@ -73,6 +75,7 @@ public:
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); }
+ size_t DynamicMemoryUsage() const { return 0; }
};
/**
@@ -93,6 +96,7 @@ private:
CBlockPolicyEstimator* minerPolicyEstimator;
uint64_t totalTxSize; //! sum of all mempool tx' byte sizes
+ uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves)
public:
mutable CCriticalSection cs;
@@ -139,6 +143,7 @@ public:
LOCK(cs);
return mapTx.size();
}
+
uint64_t GetTotalTxSize()
{
LOCK(cs);
@@ -162,6 +167,8 @@ public:
/** Write/Read estimates to disk */
bool WriteFeeEstimates(CAutoFile& fileout) const;
bool ReadFeeEstimates(CAutoFile& filein);
+
+ size_t DynamicMemoryUsage() const;
};
/**
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index 6920c44c96..1d49a2cfc9 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -86,7 +86,7 @@ bool UniValue::setFloat(double val)
oss << std::setprecision(16) << val;
bool ret = setNumStr(oss.str());
- typ = VREAL;
+ typ = VNUM;
return ret;
}
@@ -210,7 +210,6 @@ const char *uvTypeName(UniValue::VType t)
case UniValue::VARR: return "array";
case UniValue::VSTR: return "string";
case UniValue::VNUM: return "number";
- case UniValue::VREAL: return "number";
}
// not reached
@@ -280,7 +279,7 @@ int64_t UniValue::get_int64() const
double UniValue::get_real() const
{
- if (typ != VREAL && typ != VNUM)
+ if (typ != VNUM)
throw std::runtime_error("JSON value is not a number as expected");
double retval;
if (!ParseDouble(getValStr(), &retval))
diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h
index 54239741e2..4742b56f3d 100644
--- a/src/univalue/univalue.h
+++ b/src/univalue/univalue.h
@@ -16,7 +16,7 @@
class UniValue {
public:
- enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, };
+ enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
UniValue() { typ = VNULL; }
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
@@ -78,7 +78,6 @@ public:
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
- bool isReal() const { return (typ == VREAL); }
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index d360c253b0..bce3997af7 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -61,13 +61,6 @@ string UniValue::write(unsigned int prettyIndent,
case VSTR:
s += "\"" + json_escape(val) + "\"";
break;
- case VREAL:
- {
- std::stringstream ss;
- ss << std::showpoint << std::fixed << std::setprecision(8) << get_real();
- s += ss.str();
- }
- break;
case VNUM:
s += val;
break;
diff --git a/src/util.cpp b/src/util.cpp
index da5821e530..a7ec740de8 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -83,6 +83,7 @@
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
+#include <openssl/conf.h>
// Work around clang compilation problem in Boost 1.46:
// /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
@@ -113,7 +114,7 @@ CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
static CCriticalSection** ppmutexOpenSSL;
-void locking_callback(int mode, int i, const char* file, int line)
+void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
{
if (mode & CRYPTO_LOCK) {
ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
@@ -134,6 +135,13 @@ public:
ppmutexOpenSSL[i] = new CCriticalSection();
CRYPTO_set_locking_callback(locking_callback);
+ // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
+ // We don't use them so we don't require the config. However some of our libs may call functions
+ // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
+ // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
+ // that the config appears to have been loaded and there are no modules/engines available.
+ OPENSSL_no_config();
+
#ifdef WIN32
// Seed OpenSSL PRNG with current contents of the screen
RAND_screen();
@@ -167,23 +175,51 @@ instance_of_cinit;
*/
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
+
/**
- * We use boost::call_once() to make sure these are initialized
- * in a thread-safe manner the first time called:
+ * We use boost::call_once() to make sure mutexDebugLog and
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
+ *
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
+ * are leaked on exit. This is ugly, but will be cleaned up by
+ * the OS/libc. When the shutdown sequence is fully audited and
+ * tested, explicit destruction of these objects can be implemented.
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
+static list<string> *vMsgsBeforeOpenLog;
+
+static int FileWriteStr(const std::string &str, FILE *fp)
+{
+ return fwrite(str.data(), 1, str.size(), fp);
+}
static void DebugPrintInit()
{
- assert(fileout == NULL);
assert(mutexDebugLog == NULL);
+ mutexDebugLog = new boost::mutex();
+ vMsgsBeforeOpenLog = new list<string>;
+}
+
+void OpenDebugLog()
+{
+ boost::call_once(&DebugPrintInit, debugPrintInitFlag);
+ boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
+ assert(fileout == NULL);
+ assert(vMsgsBeforeOpenLog);
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
fileout = fopen(pathDebug.string().c_str(), "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
- mutexDebugLog = new boost::mutex();
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
+
+ delete vMsgsBeforeOpenLog;
+ vMsgsBeforeOpenLog = NULL;
}
bool LogAcceptCategory(const char* category)
@@ -215,59 +251,85 @@ bool LogAcceptCategory(const char* category)
return true;
}
+/**
+ * fStartedNewLine is a state variable held by the calling context that will
+ * suppress printing of the timestamp when multiple calls are made that don't
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
+ */
+static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine)
+{
+ string strStamped;
+
+ if (!fLogTimestamps)
+ return str;
+
+ if (*fStartedNewLine)
+ strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str;
+ else
+ strStamped = str;
+
+ if (!str.empty() && str[str.size()-1] == '\n')
+ *fStartedNewLine = true;
+ else
+ *fStartedNewLine = false;
+
+ return strStamped;
+}
+
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written
+ static bool fStartedNewLine = true;
if (fPrintToConsole)
{
// print to console
ret = fwrite(str.data(), 1, str.size(), stdout);
fflush(stdout);
}
- else if (fPrintToDebugLog && AreBaseParamsConfigured())
+ else if (fPrintToDebugLog)
{
- static bool fStartedNewLine = true;
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
-
- if (fileout == NULL)
- return ret;
-
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
- setbuf(fileout, NULL); // unbuffered
- }
+ string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
- // Debug print useful for profiling
- if (fLogTimestamps && fStartedNewLine)
- ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
- if (!str.empty() && str[str.size()-1] == '\n')
- fStartedNewLine = true;
+ // buffer if we haven't opened the log yet
+ if (fileout == NULL) {
+ assert(vMsgsBeforeOpenLog);
+ ret = strTimestamped.length();
+ vMsgsBeforeOpenLog->push_back(strTimestamped);
+ }
else
- fStartedNewLine = false;
-
- ret = fwrite(str.data(), 1, str.size(), fileout);
+ {
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
+ setbuf(fileout, NULL); // unbuffered
+ }
+
+ ret = FileWriteStr(strTimestamped, fileout);
+ }
}
-
return ret;
}
-static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
+/** Interpret string as boolean, for argument parsing */
+static bool InterpretBool(const std::string& strValue)
+{
+ if (strValue.empty())
+ return true;
+ return (atoi(strValue) != 0);
+}
+
+/** Turn -noX into -X=0 */
+static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
{
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- if (name.find("-no") == 0)
+ if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
{
- std::string positive("-");
- positive.append(name.begin()+3, name.end());
- if (mapSettingsRet.count(positive) == 0)
- {
- bool value = !GetBoolArg(name, false);
- mapSettingsRet[positive] = (value ? "1" : "0");
- }
+ strKey = "-" + strKey.substr(3);
+ strValue = InterpretBool(strValue) ? "0" : "1";
}
}
@@ -299,17 +361,11 @@ void ParseParameters(int argc, const char* const argv[])
// If both --foo and -foo are set, the last takes effect.
if (str.length() > 1 && str[1] == '-')
str = str.substr(1);
+ InterpretNegativeSetting(str, strValue);
mapArgs[str] = strValue;
mapMultiArgs[str].push_back(strValue);
}
-
- // New 0.6 features:
- BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
- {
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- InterpretNegativeSetting(entry.first, mapArgs);
- }
}
std::string GetArg(const std::string& strArg, const std::string& strDefault)
@@ -329,11 +385,7 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault)
bool GetBoolArg(const std::string& strArg, bool fDefault)
{
if (mapArgs.count(strArg))
- {
- if (mapArgs[strArg].empty())
- return true;
- return (atoi(mapArgs[strArg]) != 0);
- }
+ return InterpretBool(mapArgs[strArg]);
return fDefault;
}
@@ -484,13 +536,11 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
string strKey = string("-") + it->string_key;
+ string strValue = it->value[0];
+ InterpretNegativeSetting(strKey, strValue);
if (mapSettingsRet.count(strKey) == 0)
- {
- mapSettingsRet[strKey] = it->value[0];
- // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
- InterpretNegativeSetting(strKey, mapSettingsRet);
- }
- mapMultiSettingsRet[strKey].push_back(it->value[0]);
+ mapSettingsRet[strKey] = strValue;
+ mapMultiSettingsRet[strKey].push_back(strValue);
}
// If datadir is changed in .conf file:
ClearDatadirCache();
@@ -756,3 +806,13 @@ void SetThreadPriority(int nPriority)
#endif // PRIO_THREAD
#endif // WIN32
}
+
+int GetNumCores()
+{
+#if BOOST_VERSION >= 105600
+ return boost::thread::physical_concurrency();
+#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores
+ return boost::thread::hardware_concurrency();
+#endif
+}
+
diff --git a/src/util.h b/src/util.h
index 6ec81698ea..afc9a378bb 100644
--- a/src/util.h
+++ b/src/util.h
@@ -125,6 +125,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
boost::filesystem::path GetTempPath();
+void OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
@@ -199,6 +200,13 @@ std::string HelpMessageGroup(const std::string& message);
*/
std::string HelpMessageOpt(const std::string& option, const std::string& message);
+/**
+ * Return the number of physical cores available on the current system.
+ * @note This does not count virtual cores, such as those provided by HyperThreading
+ * when boost is newer than 1.56.
+ */
+int GetNumCores();
+
void SetThreadPriority(int nPriority);
void RenameThread(const char* name);
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 7d1de7d6a8..1f7a2cae2c 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -464,11 +464,12 @@ bool ParseDouble(const std::string& str, double *out)
return false;
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
return false;
- char *endp = NULL;
- errno = 0; // strtod will not set errno if valid
- double n = strtod(str.c_str(), &endp);
- if(out) *out = n;
- return endp && *endp == 0 && !errno;
+ std::istringstream text(str);
+ text.imbue(std::locale::classic());
+ double result;
+ text >> result;
+ if(out) *out = result;
+ return text.eof() && !text.fail();
}
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
@@ -538,3 +539,123 @@ int atoi(const std::string& str)
{
return atoi(str.c_str());
}
+
+/** Upper bound for mantissa.
+ * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
+ * Larger integers cannot consist of arbitrary combinations of 0-9:
+ *
+ * 999999999999999999 1^18-1
+ * 9223372036854775807 (1<<63)-1 (max int64_t)
+ * 9999999999999999999 1^19-1 (would overflow)
+ */
+static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
+
+/** Helper function for ParseFixedPoint */
+static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
+{
+ if(ch == '0')
+ ++mantissa_tzeros;
+ else {
+ for (int i=0; i<=mantissa_tzeros; ++i) {
+ if (mantissa > (UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ mantissa *= 10;
+ }
+ mantissa += ch - '0';
+ mantissa_tzeros = 0;
+ }
+ return true;
+}
+
+bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
+{
+ int64_t mantissa = 0;
+ int64_t exponent = 0;
+ int mantissa_tzeros = 0;
+ bool mantissa_sign = false;
+ bool exponent_sign = false;
+ int ptr = 0;
+ int end = val.size();
+ int point_ofs = 0;
+
+ if (ptr < end && val[ptr] == '-') {
+ mantissa_sign = true;
+ ++ptr;
+ }
+ if (ptr < end)
+ {
+ if (val[ptr] == '0') {
+ /* pass single 0 */
+ ++ptr;
+ } else if (val[ptr] >= '1' && val[ptr] <= '9') {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
+ return false; /* overflow */
+ ++ptr;
+ }
+ } else return false; /* missing expected digit */
+ } else return false; /* empty string or loose '-' */
+ if (ptr < end && val[ptr] == '.')
+ {
+ ++ptr;
+ if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9')
+ {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
+ return false; /* overflow */
+ ++ptr;
+ ++point_ofs;
+ }
+ } else return false; /* missing expected digit */
+ }
+ if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
+ {
+ ++ptr;
+ if (ptr < end && val[ptr] == '+')
+ ++ptr;
+ else if (ptr < end && val[ptr] == '-') {
+ exponent_sign = true;
+ ++ptr;
+ }
+ if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (exponent > (UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ exponent = exponent * 10 + val[ptr] - '0';
+ ++ptr;
+ }
+ } else return false; /* missing expected digit */
+ }
+ if (ptr != end)
+ return false; /* trailing garbage */
+
+ /* finalize exponent */
+ if (exponent_sign)
+ exponent = -exponent;
+ exponent = exponent - point_ofs + mantissa_tzeros;
+
+ /* finalize mantissa */
+ if (mantissa_sign)
+ mantissa = -mantissa;
+
+ /* convert to one 64-bit fixed-point value */
+ exponent += decimals;
+ if (exponent < 0)
+ return false; /* cannot represent values smaller than 10^-decimals */
+ if (exponent >= 18)
+ return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
+
+ for (int i=0; i < exponent; ++i) {
+ if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ mantissa *= 10;
+ }
+ if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
+ return false; /* overflow */
+
+ if (amount_out)
+ *amount_out = mantissa;
+
+ return true;
+}
+
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 58329b51bb..dcd56751f2 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -109,4 +109,11 @@ bool TimingResistantEqual(const T& a, const T& b)
return accumulator == 0;
}
+/** Parse number as fixed point according to JSON number syntax.
+ * See http://json.org/number.gif
+ * @returns true on success, false on error.
+ * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
+ */
+bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 0532da5f37..d365f03008 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -19,9 +19,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
+ g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
+ g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
+ g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
@@ -31,6 +35,8 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
}
void UnregisterAllValidationInterfaces() {
+ g_signals.BlockFound.disconnect_all_slots();
+ g_signals.ScriptForMining.disconnect_all_slots();
g_signals.BlockChecked.disconnect_all_slots();
g_signals.Broadcast.disconnect_all_slots();
g_signals.Inventory.disconnect_all_slots();
diff --git a/src/validationinterface.h b/src/validationinterface.h
index a911d1efeb..fb0ce0bdaa 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -7,9 +7,11 @@
#define BITCOIN_VALIDATIONINTERFACE_H
#include <boost/signals2/signal.hpp>
+#include <boost/shared_ptr.hpp>
class CBlock;
struct CBlockLocator;
+class CReserveScript;
class CTransaction;
class CValidationInterface;
class CValidationState;
@@ -34,6 +36,8 @@ protected:
virtual void Inventory(const uint256 &hash) {}
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
+ virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
+ virtual void ResetRequestCount(const uint256 &hash) {};
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
@@ -52,6 +56,10 @@ struct CMainSignals {
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
/** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
+ /** Notifies listeners that a key for mining is required (coinbase) */
+ boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
+ /** Notifies listeners that a block has been successfully mined */
+ boost::signals2::signal<void (const uint256 &)> BlockFound;
};
CMainSignals& GetMainSignals();
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index c7f7e21679..0b0fb562e0 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -186,7 +186,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
}
if (keyPass && keyFail)
{
- LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
+ LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
assert(false);
}
if (keyFail || !keyPass)
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 5f800474a0..dbe36a2be1 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
+#include "chain.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
@@ -21,6 +22,8 @@
#include "univalue/univalue.h"
+#include <boost/foreach.hpp>
+
using namespace std;
void EnsureWalletIsUnlocked();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 8d88933878..198b5baf60 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -5,6 +5,7 @@
#include "amount.h"
#include "base58.h"
+#include "chain.h"
#include "core_io.h"
#include "init.h"
#include "main.h"
@@ -389,7 +390,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
+ HelpRequiringPassphrase() +
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
- "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
+ "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
"4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
@@ -451,7 +452,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
" [\n"
" [\n"
" \"bitcoinaddress\", (string) The bitcoin address\n"
- " amount, (numeric) The amount in btc\n"
+ " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"account\" (string, optional) The account (DEPRECATED)\n"
" ]\n"
" ,...\n"
@@ -476,7 +477,6 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- LOCK(pwalletMain->cs_wallet);
if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
}
@@ -556,7 +556,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
"1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received at this address.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
"\nExamples:\n"
"\nThe amount from transactions with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
@@ -614,7 +614,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
"1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
"\nAmount received by the default account with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbyaccount", "\"\"") +
@@ -707,7 +707,7 @@ UniValue getbalance(const UniValue& params, bool fHelp)
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
"\nThe total amount in the wallet\n"
+ HelpExampleCli("getbalance", "") +
@@ -793,14 +793,15 @@ UniValue movecmd(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
"2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
- "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
- "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
+ "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
+ "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
+ "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
"\nResult:\n"
"true|false (boolean) true if successfull.\n"
"\nExamples:\n"
- "\nMove 0.01 btc from the default account to the account named tabby\n"
+ "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
+ HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
- "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
+ "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
+ HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
@@ -867,7 +868,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
- "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
+ "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
@@ -877,7 +878,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
- "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
+ "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
+ HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
"\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
+ HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
@@ -932,7 +933,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
"1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
" {\n"
- " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
+ " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
" ,...\n"
" }\n"
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
@@ -1233,7 +1234,7 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
" \"address\" : \"receivingaddress\", (string) The receiving address\n"
" \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
- " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
+ " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
" \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
" }\n"
" ,...\n"
@@ -1405,11 +1406,11 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" transaction between accounts, and not associated with an address,\n"
" transaction id or block. 'send' and 'receive' transactions are \n"
" associated with an address, transaction id and block details\n"
- " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
+ " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
" 'move' category for moves outbound. It is positive for the 'receive' category,\n"
" and for the 'move' category for inbound funds.\n"
" \"vout\" : n, (numeric) the vout value\n"
- " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions.\n"
@@ -1600,10 +1601,10 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
- " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
+ " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
" outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
" \"vout\" : n, (numeric) the vout value\n"
- " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
@@ -1686,7 +1687,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
"2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
"\nResult:\n"
"{\n"
- " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
+ " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"blockhash\" : \"hash\", (string) The block hash\n"
" \"blockindex\" : xx, (numeric) The block index\n"
@@ -1699,7 +1700,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
" \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
- " \"amount\" : x.xxx (numeric) The amount in btc\n"
+ " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"vout\" : n, (numeric) the vout value\n"
" }\n"
" ,...\n"
@@ -2165,7 +2166,7 @@ UniValue settxfee(const UniValue& params, bool fHelp)
"settxfee amount\n"
"\nSet the transaction fee per kB.\n"
"\nArguments:\n"
- "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
+ "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
"\nResult\n"
"true|false (boolean) Returns true if successful\n"
"\nExamples:\n"
@@ -2194,14 +2195,14 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total confirmed bitcoin balance of the wallet\n"
- " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed bitcoin balance of the wallet\n"
- " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
+ " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
+ " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
+ " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in btc/kb\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getwalletinfo", "")
@@ -2278,7 +2279,7 @@ UniValue listunspent(const UniValue& params, bool fHelp)
" \"address\" : \"address\", (string) the bitcoin address\n"
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
- " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
+ " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n (numeric) The number of confirmations\n"
" }\n"
" ,...\n"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index eee57900b5..dcc2983139 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -7,14 +7,21 @@
#include "base58.h"
#include "checkpoints.h"
+#include "chain.h"
#include "coincontrol.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "key.h"
+#include "keystore.h"
#include "main.h"
#include "net.h"
+#include "policy/policy.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
#include "timedata.h"
+#include "txmempool.h"
#include "util.h"
#include "utilmoneystr.h"
@@ -419,6 +426,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
// fTimeReceivedIsTxTime not copied on purpose
@@ -1330,6 +1338,15 @@ bool CWalletTx::IsTrusted() const
return true;
}
+bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
+{
+ CMutableTransaction tx1 = *this;
+ CMutableTransaction tx2 = tx;
+ for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript();
+ for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript();
+ return CTransaction(tx1) == CTransaction(tx2);
+}
+
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
{
std::vector<uint256> result;
@@ -2092,7 +2109,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (!wtxNew.AcceptToMemoryPool(false))
{
// This must not fail. The transaction has already been signed and recorded.
- LogPrintf("CommitTransaction(): Error: Transaction not valid");
+ LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
}
wtxNew.RelayWalletTransaction();
@@ -2583,6 +2600,17 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
}
}
+void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
+{
+ boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
+ CPubKey pubkey;
+ if (!rKey->GetReservedKey(pubkey))
+ return;
+
+ script = rKey;
+ script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
+}
+
void CWallet::LockCoin(COutPoint& output)
{
AssertLockHeld(cs_wallet); // setLockedCoins
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b6a8e8671f..ae007e4673 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,10 +7,7 @@
#define BITCOIN_WALLET_WALLET_H
#include "amount.h"
-#include "key.h"
-#include "keystore.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
+#include "streams.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "utilstrencodings.h"
@@ -28,6 +25,8 @@
#include <utility>
#include <vector>
+#include <boost/shared_ptr.hpp>
+
/**
* Settings
*/
@@ -376,6 +375,9 @@ public:
return (GetDebit(filter) > 0);
}
+ // True if only scriptSigs are different
+ bool IsEquivalentTo(const CWalletTx& tx) const;
+
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);
@@ -680,6 +682,13 @@ public:
}
}
+ void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
+ void ResetRequestCount(const uint256 &hash)
+ {
+ LOCK(cs_wallet);
+ mapRequestCount[hash] = 0;
+ };
+
unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // setKeyPool
@@ -735,7 +744,7 @@ public:
};
/** A key allocated from the key pool. */
-class CReserveKey
+class CReserveKey : public CReserveScript
{
protected:
CWallet* pwallet;
@@ -756,6 +765,7 @@ public:
void ReturnKey();
bool GetReservedKey(CPubKey &pubkey);
void KeepKey();
+ void KeepScript() { KeepKey(); }
};
diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h
index 5b9b0e0841..7846565f8d 100644
--- a/src/wallet/wallet_ismine.h
+++ b/src/wallet/wallet_ismine.h
@@ -6,9 +6,10 @@
#ifndef BITCOIN_WALLET_WALLET_ISMINE_H
#define BITCOIN_WALLET_WALLET_ISMINE_H
-#include "key.h"
#include "script/standard.h"
+#include <stdint.h>
+
class CKeyStore;
class CScript;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index f777926e72..c1eb184581 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -7,7 +7,7 @@
#include "base58.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "main.h" // For CheckTransaction
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index bc1a104b5b..270f826aed 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -9,7 +9,6 @@
#include "amount.h"
#include "wallet/db.h"
#include "key.h"
-#include "keystore.h"
#include <list>
#include <stdint.h>