diff options
Diffstat (limited to 'src')
147 files changed, 3607 insertions, 2899 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e3eaacdb4..03fac5bf9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,6 +105,7 @@ BITCOIN_CORE_H = \ merkleblock.h \ miner.h \ net.h \ + netaddress.h \ netbase.h \ noui.h \ policy/fees.h \ @@ -289,6 +290,7 @@ libbitcoin_common_a_SOURCES = \ core_write.cpp \ key.cpp \ keystore.cpp \ + netaddress.cpp \ netbase.cpp \ protocol.cpp \ scheduler.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 36a21dd06..7730aba37 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -8,6 +8,7 @@ QT_TS = \ qt/locale/bitcoin_ar.ts \ qt/locale/bitcoin_be_BY.ts \ qt/locale/bitcoin_bg.ts \ + qt/locale/bitcoin_bg_BG.ts \ qt/locale/bitcoin_ca_ES.ts \ qt/locale/bitcoin_ca.ts \ qt/locale/[email protected] \ @@ -231,6 +232,7 @@ RES_ICONS = \ qt/res/icons/about.png \ qt/res/icons/about_qt.png \ qt/res/icons/bitcoin.ico \ + qt/res/icons/bitcoin_testnet.ico \ qt/res/icons/bitcoin.png \ qt/res/icons/chevron.png \ qt/res/icons/clock1.png \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c8918eb53..27e769474 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -38,7 +38,6 @@ BITCOIN_TESTS =\ test/arith_uint256_tests.cpp \ test/scriptnum10.h \ test/addrman_tests.cpp \ - test/alert_tests.cpp \ test/amount_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ diff --git a/src/addrman.h b/src/addrman.h index 1caf54075..9bab39049 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -6,7 +6,7 @@ #ifndef BITCOIN_ADDRMAN_H #define BITCOIN_ADDRMAN_H -#include "netbase.h" +#include "netaddress.h" #include "protocol.h" #include "random.h" #include "sync.h" diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 86bef1e10..ea6e3aada 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -71,11 +71,10 @@ public: CMainParams() { strNetworkID = "main"; consensus.nSubsidyHalvingInterval = 210000; - consensus.nMajorityEnforceBlockUpgrade = 750; - consensus.nMajorityRejectBlockOutdated = 950; - consensus.nMajorityWindow = 1000; consensus.BIP34Height = 227931; consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); + consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 + consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -167,11 +166,10 @@ public: CTestNetParams() { strNetworkID = "test"; consensus.nSubsidyHalvingInterval = 210000; - consensus.nMajorityEnforceBlockUpgrade = 51; - consensus.nMajorityRejectBlockOutdated = 75; - consensus.nMajorityWindow = 100; consensus.BIP34Height = 21111; consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); + consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 + consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -247,11 +245,10 @@ public: CRegTestParams() { strNetworkID = "regtest"; consensus.nSubsidyHalvingInterval = 150; - consensus.nMajorityEnforceBlockUpgrade = 750; - consensus.nMajorityRejectBlockOutdated = 950; - consensus.nMajorityWindow = 1000; - consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest + consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests) consensus.BIP34Hash = uint256(); + consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) + consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests) consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -303,6 +300,12 @@ public: 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> >(); } + + void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) + { + consensus.vDeployments[d].nStartTime = nStartTime; + consensus.vDeployments[d].nTimeout = nTimeout; + } }; static CRegTestParams regTestParams; @@ -330,4 +333,9 @@ void SelectParams(const std::string& network) SelectBaseParams(network); pCurrentParams = &Params(network); } + +void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) +{ + regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout); +} diff --git a/src/chainparams.h b/src/chainparams.h index 638893e9a..0c3820b7c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -112,4 +112,9 @@ CChainParams& Params(const std::string& chain); */ void SelectParams(const std::string& chain); +/** + * Allows modifying the BIP9 regtest parameters. + */ +void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout); + #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/clientversion.h b/src/clientversion.h index 47263d534..53ad46034 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -15,7 +15,7 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 -#define CLIENT_VERSION_MINOR 12 +#define CLIENT_VERSION_MINOR 13 #define CLIENT_VERSION_REVISION 99 #define CLIENT_VERSION_BUILD 0 diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 81f40593b..690856586 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -10,8 +10,8 @@ /** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000; -/** The maximum allowed cost for a block, see BIP 141 (network rule) */ -static const unsigned int MAX_BLOCK_COST = 4000000; +/** The maximum allowed weight for a block, see BIP 141 (network rule) */ +static const unsigned int MAX_BLOCK_WEIGHT = 4000000; /** The maximum allowed size for a block excluding witness data, in bytes (network rule) */ static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000; /** The maximum allowed number of signature check operations in a block (network rule) */ diff --git a/src/consensus/params.h b/src/consensus/params.h index 822ec87d6..5b2f49184 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -39,13 +39,13 @@ struct BIP9Deployment { struct Params { uint256 hashGenesisBlock; int nSubsidyHalvingInterval; - /** Used to check majorities for block version upgrade */ - int nMajorityEnforceBlockUpgrade; - int nMajorityRejectBlockOutdated; - int nMajorityWindow; /** Block height and hash at which BIP34 becomes active */ int BIP34Height; uint256 BIP34Hash; + /** Block height at which BIP65 becomes active */ + int BIP65Height; + /** Block height at which BIP66 becomes active */ + int BIP66Height; /** * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period, * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. diff --git a/src/core_memusage.h b/src/core_memusage.h index dd86f805f..b8e0f08bb 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -33,13 +33,13 @@ static inline size_t RecursiveDynamicUsage(const CScriptWitness& scriptWit) { return mem; } -static inline size_t RecursiveDynamicUsage(const CTxinWitness& txinwit) { +static inline size_t RecursiveDynamicUsage(const CTxInWitness& txinwit) { return RecursiveDynamicUsage(txinwit.scriptWitness); } static inline size_t RecursiveDynamicUsage(const CTxWitness& txwit) { size_t mem = memusage::DynamicUsage(txwit.vtxinwit); - for (std::vector<CTxinWitness>::const_iterator it = txwit.vtxinwit.begin(); it != txwit.vtxinwit.end(); it++) { + for (std::vector<CTxInWitness>::const_iterator it = txwit.vtxinwit.begin(); it != txwit.vtxinwit.end(); it++) { mem += RecursiveDynamicUsage(*it); } return mem; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index a0779d3ab..47bdb31b5 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -52,9 +52,9 @@ private: public: /** - * @param[in] parent CDBWrapper that this batch is to be submitted to + * @param[in] _parent CDBWrapper that this batch is to be submitted to */ - CDBBatch(const CDBWrapper &parent) : parent(parent) { }; + CDBBatch(const CDBWrapper &_parent) : parent(_parent) { }; template <typename K, typename V> void Write(const K& key, const V& value) @@ -94,11 +94,11 @@ private: public: /** - * @param[in] parent Parent CDBWrapper instance. - * @param[in] piterIn The original leveldb iterator. + * @param[in] _parent Parent CDBWrapper instance. + * @param[in] _piter The original leveldb iterator. */ - CDBIterator(const CDBWrapper &parent, leveldb::Iterator *piterIn) : - parent(parent), piter(piterIn) { }; + CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) : + parent(_parent), piter(_piter) { }; ~CDBIterator(); bool Valid(); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 812940eaf..f921305fc 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <signal.h> +#include <future> #include <event2/event.h> #include <event2/http.h> @@ -34,9 +35,6 @@ #endif #endif -#include <boost/algorithm/string/case_conv.hpp> // for to_lower() -#include <boost/foreach.hpp> - /** Maximum size of http request (request line + headers) */ static const size_t MAX_HEADERS_SIZE = 8192; @@ -68,8 +66,8 @@ class WorkQueue { private: /** Mutex protects entire object */ - CWaitableCriticalSection cs; - CConditionVariable cond; + std::mutex cs; + std::condition_variable cond; std::deque<std::unique_ptr<WorkItem>> queue; bool running; size_t maxDepth; @@ -82,12 +80,12 @@ private: WorkQueue &wq; ThreadCounter(WorkQueue &w): wq(w) { - boost::lock_guard<boost::mutex> lock(wq.cs); + std::lock_guard<std::mutex> lock(wq.cs); wq.numThreads += 1; } ~ThreadCounter() { - boost::lock_guard<boost::mutex> lock(wq.cs); + std::lock_guard<std::mutex> lock(wq.cs); wq.numThreads -= 1; wq.cond.notify_all(); } @@ -108,7 +106,7 @@ public: /** Enqueue a work item */ bool Enqueue(WorkItem* item) { - boost::unique_lock<boost::mutex> lock(cs); + std::unique_lock<std::mutex> lock(cs); if (queue.size() >= maxDepth) { return false; } @@ -123,7 +121,7 @@ public: while (running) { std::unique_ptr<WorkItem> i; { - boost::unique_lock<boost::mutex> lock(cs); + std::unique_lock<std::mutex> lock(cs); while (running && queue.empty()) cond.wait(lock); if (!running) @@ -137,14 +135,14 @@ public: /** Interrupt and exit loops */ void Interrupt() { - boost::unique_lock<boost::mutex> lock(cs); + std::unique_lock<std::mutex> lock(cs); running = false; cond.notify_all(); } /** Wait for worker threads to exit */ void WaitExit() { - boost::unique_lock<boost::mutex> lock(cs); + std::unique_lock<std::mutex> lock(cs); while (numThreads > 0) cond.wait(lock); } @@ -152,7 +150,7 @@ public: /** Return current depth of queue */ size_t Depth() { - boost::unique_lock<boost::mutex> lock(cs); + std::unique_lock<std::mutex> lock(cs); return queue.size(); } }; @@ -189,7 +187,7 @@ static bool ClientAllowed(const CNetAddr& netaddr) { if (!netaddr.IsValid()) return false; - BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets) + for(const CSubNet& subnet : rpc_allow_subnets) if (subnet.Match(netaddr)) return true; return false; @@ -199,12 +197,17 @@ static bool ClientAllowed(const CNetAddr& netaddr) static bool InitHTTPAllowList() { rpc_allow_subnets.clear(); - rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet - rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost + CNetAddr localv4; + CNetAddr localv6; + LookupHost("127.0.0.1", localv4, false); + LookupHost("::1", localv6, false); + rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet + rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost if (mapMultiArgs.count("-rpcallowip")) { const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"]; - BOOST_FOREACH (std::string strAllow, vAllow) { - CSubNet subnet(strAllow); + for (std::string strAllow : vAllow) { + CSubNet subnet; + LookupSubNet(strAllow.c_str(), subnet); if (!subnet.IsValid()) { uiInterface.ThreadSafeMessageBox( strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow), @@ -215,7 +218,7 @@ static bool InitHTTPAllowList() } } std::string strAllowed; - BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets) + for (const CSubNet& subnet : rpc_allow_subnets) strAllowed += subnet.ToString() + " "; LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed); return true; @@ -302,13 +305,14 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) } /** Event dispatcher thread */ -static void ThreadHTTP(struct event_base* base, struct evhttp* http) +static bool ThreadHTTP(struct event_base* base, struct evhttp* http) { RenameThread("bitcoin-http"); LogPrint("http", "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() LogPrint("http", "Exited http event loop\n"); + return event_base_got_break(base) == 0; } /** Bind HTTP server to specified addresses */ @@ -437,17 +441,22 @@ bool InitHTTPServer() return true; } -boost::thread threadHTTP; +std::thread threadHTTP; +std::future<bool> threadResult; bool StartHTTPServer() { LogPrint("http", "Starting HTTP server\n"); int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); - threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP); + threadResult = task.get_future(); + threadHTTP = std::thread(std::move(task), eventBase, eventHTTP); - for (int i = 0; i < rpcThreads; i++) - boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + for (int i = 0; i < rpcThreads; i++) { + std::thread rpc_worker(HTTPWorkQueueRun, workQueue); + rpc_worker.detach(); + } return true; } @@ -456,7 +465,7 @@ void InterruptHTTPServer() LogPrint("http", "Interrupting HTTP server\n"); if (eventHTTP) { // Unlisten sockets - BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) { + for (evhttp_bound_socket *socket : boundSockets) { evhttp_del_accept_socket(eventHTTP, socket); } // Reject requests on current connections @@ -482,15 +491,11 @@ void StopHTTPServer() // master that appears to be solved, so in the future that solution // could be used again (if desirable). // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990) -#if BOOST_VERSION >= 105000 - if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) { -#else - if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) { -#endif + if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) { LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); event_base_loopbreak(eventBase); - threadHTTP.join(); } + threadHTTP.join(); } if (eventHTTP) { evhttp_free(eventHTTP); @@ -517,7 +522,7 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data) delete self; } -HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler): +HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler): deleteWhenTriggered(deleteWhenTriggered), handler(handler) { ev = event_new(base, -1, 0, httpevent_callback_fn, this); @@ -599,7 +604,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); HTTPEvent* ev = new HTTPEvent(eventBase, true, - boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); + std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); ev->trigger(0); replySent = true; req = 0; // transferred back to main thread @@ -614,7 +619,7 @@ CService HTTPRequest::GetPeer() const char* address = ""; uint16_t port = 0; evhttp_connection_get_peer(con, (char**)&address, &port); - peer = CService(address, port); + peer = LookupNumeric(address, port); } return peer; } diff --git a/src/httpserver.h b/src/httpserver.h index 20a119cc5..0e30e666a 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,9 +7,7 @@ #include <string> #include <stdint.h> -#include <boost/thread.hpp> -#include <boost/scoped_ptr.hpp> -#include <boost/function.hpp> +#include <functional> static const int DEFAULT_HTTP_THREADS=4; static const int DEFAULT_HTTP_WORKQUEUE=16; @@ -35,7 +33,7 @@ void InterruptHTTPServer(); void StopHTTPServer(); /** Handler for requests to a certain HTTP path */ -typedef boost::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler; +typedef std::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler; /** Register handler for prefix. * If multiple handlers match a prefix, the first-registered one will * be invoked. @@ -132,7 +130,7 @@ public: * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called) * handler is the handler to call when the event is triggered. */ - HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler); + HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler); ~HTTPEvent(); /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after @@ -141,7 +139,7 @@ public: void trigger(struct timeval* tv); bool deleteWhenTriggered; - boost::function<void(void)> handler; + std::function<void(void)> handler; private: struct event* ev; }; diff --git a/src/indirectmap.h b/src/indirectmap.h index 28e1e8ded..76da4a6bd 100644 --- a/src/indirectmap.h +++ b/src/indirectmap.h @@ -1,3 +1,7 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_INDIRECTMAP_H #define BITCOIN_INDIRECTMAP_H diff --git a/src/init.cpp b/src/init.cpp index ea4ccaddf..5ef8af8b3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -21,6 +21,7 @@ #include "key.h" #include "main.h" #include "miner.h" +#include "netbase.h" #include "net.h" #include "policy/policy.h" #include "rpc/server.h" @@ -410,6 +411,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); + strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)"); } string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) @@ -446,14 +448,13 @@ std::string HelpMessage(HelpMessageMode mode) 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("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); strUsage += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockmaxcost=<n>", strprintf(_("Set maximum block cost (default: %d)"), DEFAULT_BLOCK_MAX_COST)); - strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), DEFAULT_BLOCK_MIN_SIZE)); + strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); if (showDebug) @@ -482,7 +483,7 @@ std::string LicenseInfo() { const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>"; const std::string URL_WEBSITE = "<https://bitcoincore.org>"; - // todo: remove urls from translations on next change + return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" + "\n" + strprintf(_("Please contribute if you find %s useful. " @@ -494,9 +495,9 @@ std::string LicenseInfo() "\n" + "\n" + _("This is experimental software.") + "\n" + - _("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.") + "\n" + + strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" + "\n" + - _("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.") + + strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard."), "<https://www.openssl.org>") + "\n"; } @@ -511,6 +512,21 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex boost::thread t(runCommand, strCmd); // thread runs free } +static bool fHaveGenesis = false; +static boost::mutex cs_GenesisWait; +static CConditionVariable condvar_GenesisWait; + +static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) +{ + if (pBlockIndex != NULL) { + { + boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait); + fHaveGenesis = true; + } + condvar_GenesisWait.notify_all(); + } +} + struct CImportingNow { CImportingNow() { @@ -877,6 +893,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-whitelistalwaysrelay", false)) InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); + if (mapArgs.count("-blockminsize")) + InitWarning("Unsupported argument -blockminsize ignored."); + // Checkmempool and checkblockindex default to true in regtest mode int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { @@ -973,6 +992,41 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); } + if (!mapMultiArgs["-bip9params"].empty()) { + // Allow overriding BIP9 parameters for testing + if (!Params().MineBlocksOnDemand()) { + return InitError("BIP9 parameters may only be overridden on regtest."); + } + const vector<string>& deployments = mapMultiArgs["-bip9params"]; + for (auto i : deployments) { + std::vector<std::string> vDeploymentParams; + boost::split(vDeploymentParams, i, boost::is_any_of(":")); + if (vDeploymentParams.size() != 3) { + return InitError("BIP9 parameters malformed, expecting deployment:start:end"); + } + int64_t nStartTime, nTimeout; + if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { + return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); + } + if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { + return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); + } + bool found = false; + for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) + { + if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) { + UpdateRegtestBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout); + found = true; + LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout); + break; + } + } + if (!found) { + return InitError(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); + } + } + } + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Initialize elliptic curve code @@ -1013,7 +1067,6 @@ 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); - std::ostringstream strErrors; LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); if (nScriptCheckThreads) { @@ -1081,7 +1134,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-whitelist")) { BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) { - CSubNet subnet(net); + CSubNet subnet; + LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); CNode::AddWhitelistedRange(subnet); @@ -1094,7 +1148,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string proxyArg = GetArg("-proxy", ""); SetLimited(NET_TOR); if (proxyArg != "" && proxyArg != "0") { - proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize); + CService resolved(LookupNumeric(proxyArg.c_str(), 9050)); + proxyType addrProxy = proxyType(resolved, proxyRandomize); if (!addrProxy.IsValid()) return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg)); @@ -1113,7 +1168,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (onionArg == "0") { // Handle -noonion/-onion=0 SetLimited(NET_TOR); // set onions as unreachable } else { - proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize); + CService resolved(LookupNumeric(onionArg.c_str(), 9050)); + proxyType addrOnion = proxyType(resolved, proxyRandomize); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg)); SetProxy(NET_TOR, addrOnion); @@ -1216,10 +1272,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache int64_t nBlockTreeDBCache = nTotalCache / 8; - if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", DEFAULT_TXINDEX)) - nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB + nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache + nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache nTotalCache -= nCoinDBCache; nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache LogPrintf("Cache configuration:\n"); @@ -1284,7 +1340,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } - if (!fReindex) { + if (!fReindex && chainActive.Tip() != NULL) { uiInterface.InitMessage(_("Rewinding blocks...")); if (!RewindBlockIndex(chainparams)) { strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain"); @@ -1401,6 +1457,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 10: import blocks + if (!CheckDiskSpace()) + return false; + + // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. + // No locking, as this happens before any background thread is started. + if (chainActive.Tip() == NULL) { + uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait); + } else { + fHaveGenesis = true; + } + if (mapArgs.count("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); @@ -1410,29 +1477,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"]) vImportFiles.push_back(strFile); } + threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); // Wait for genesis block to be processed - bool fHaveGenesis = false; - while (!fHaveGenesis && !fRequestShutdown) { - { - LOCK(cs_main); - fHaveGenesis = (chainActive.Tip() != NULL); - } - - if (!fHaveGenesis) { - MilliSleep(10); + { + boost::unique_lock<boost::mutex> lock(cs_GenesisWait); + while (!fHaveGenesis) { + condvar_GenesisWait.wait(lock); } + uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait); } // ********************************************************* Step 11: start node - if (!CheckDiskSpace()) - return false; - - if (!strErrors.str().empty()) - return InitError(strErrors.str()); - //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); @@ -1447,12 +1505,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); - // Monitor the chain, and alert if we get blocks much quicker or slower than expected - int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; - CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); - scheduler.scheduleEvery(f, nPowTargetSpacing); - // ********************************************************* Step 12: finished SetRPCWarmupFinished(); @@ -15,7 +15,7 @@ #include <vector> -/** +/** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; @@ -45,6 +45,8 @@ private: //! The actual byte data unsigned char vch[32]; + static_assert(sizeof(vch) == 32, "vch must be 32 bytes in length to not break serialization"); + //! Check whether the 32-byte array pointed to be vch is valid keydata. bool static Check(const unsigned char* vch); @@ -70,20 +72,19 @@ public: friend bool operator==(const CKey& a, const CKey& b) { - return a.fCompressed == b.fCompressed && a.size() == b.size() && - memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; + return a.fCompressed == b.fCompressed && + a.size() == b.size() && + memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; } //! Initialize using begin and end iterators to byte data. template <typename T> void Set(const T pbegin, const T pend, bool fCompressedIn) { - if (pend - pbegin != 32) { + if (pend - pbegin != sizeof(vch)) { fValid = false; - return; - } - if (Check(&pbegin[0])) { - memcpy(vch, (unsigned char*)&pbegin[0], 32); + } else if (Check(&pbegin[0])) { + memcpy(vch, (unsigned char*)&pbegin[0], sizeof(vch)); fValid = true; fCompressed = fCompressedIn; } else { @@ -92,7 +93,7 @@ public: } //! Simple read-only vector-like interface. - unsigned int size() const { return (fValid ? 32 : 0); } + unsigned int size() const { return (fValid ? sizeof(vch) : 0); } const unsigned char* begin() const { return vch; } const unsigned char* end() const { return vch + size(); } @@ -110,7 +111,7 @@ public: /** * Convert the private key to a CPrivKey (serialized OpenSSL private key data). - * This is expensive. + * This is expensive. */ CPrivKey GetPrivKey() const; @@ -146,9 +147,6 @@ public: //! Load private key and check that public key matches. bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck); - - //! Check whether an element of a signature (r or s) is valid. - static bool CheckSignatureElement(const unsigned char* vch, int len, bool half); }; struct CExtKey { @@ -160,8 +158,11 @@ struct CExtKey { friend bool operator==(const CExtKey& a, const CExtKey& b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - a.chaincode == b.chaincode && a.key == b.key; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.key == b.key; } void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; diff --git a/src/limitedmap.h b/src/limitedmap.h index 4d9bb4fa2..7841d7f4a 100644 --- a/src/limitedmap.h +++ b/src/limitedmap.h @@ -66,8 +66,11 @@ public: } void update(const_iterator itIn, const mapped_type& v) { - // TODO: When we switch to C++11, use map.erase(itIn, itIn) to get the non-const iterator. - iterator itTarget = map.find(itIn->first); + // Using map::erase() with empty range instead of map::find() to get a non-const iterator, + // since it is a constant time operation in C++11. For more details, see + // https://stackoverflow.com/questions/765148/how-to-remove-constness-of-const-iterator + iterator itTarget = map.erase(itIn, itIn); + if (itTarget == map.end()) return; std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second); diff --git a/src/main.cpp b/src/main.cpp index 6cdd55e39..db457f6f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,7 +74,6 @@ bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG; bool fRequireStandard = true; -unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; size_t nCoinCacheUsage = 5000 * 300; @@ -107,11 +106,6 @@ map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); map<COutPoint, set<map<uint256, COrphanTx>::iterator, IteratorComparator>> 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 - * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. - */ -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); static void CheckBlockIndex(const Consensus::Params& consensusParams); /** Constant stuff for coinbase transactions we create: */ @@ -276,6 +270,8 @@ struct CNodeState { CBlockIndex *pindexLastCommonBlock; //! The best header we have sent our peer. CBlockIndex *pindexBestHeaderSent; + //! Length of current-streak of unconnecting headers announcements + int nUnconnectingHeaders; //! Whether we've started headers synchronization with this peer. bool fSyncStarted; //! Since when we're stalling block download progress (in microseconds), or 0. @@ -304,6 +300,7 @@ struct CNodeState { hashLastUnknownBlock.SetNull(); pindexLastCommonBlock = NULL; pindexBestHeaderSent = NULL; + nUnconnectingHeaders = 0; fSyncStarted = false; nStallingSince = 0; nDownloadingSince = 0; @@ -691,8 +688,8 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c // have been mined or received. // 100 orphans, each of which is at most 99,999 bytes big is // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case): - unsigned int sz = GetTransactionCost(tx); - if (sz >= MAX_STANDARD_TX_COST) + unsigned int sz = GetTransactionWeight(tx); + if (sz >= MAX_STANDARD_TX_WEIGHT) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); return false; @@ -785,7 +782,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + for (const auto& txin : tx.vin) { if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) return false; } @@ -999,11 +996,11 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + for (const auto& txin : tx.vin) { nSigOps += txin.scriptSig.GetSigOpCount(false); } - BOOST_FOREACH(const CTxOut& txout, tx.vout) + for (const auto& txout : tx.vout) { nSigOps += txout.scriptPubKey.GetSigOpCount(false); } @@ -1061,7 +1058,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) // Check for negative or overflow output values CAmount nValueOut = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) + for (const auto& txout : tx.vout) { if (txout.nValue < 0) return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); @@ -1074,7 +1071,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) // Check for duplicate inputs set<COutPoint> vInOutPoints; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + for (const auto& txin : tx.vin) { if (vInOutPoints.count(txin.prevout)) return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); @@ -1088,7 +1085,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) } else { - BOOST_FOREACH(const CTxIn& txin, tx.vin) + for (const auto& txin : tx.vin) if (txin.prevout.IsNull()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1132,11 +1129,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C if (tx.IsCoinBase()) return state.DoS(100, false, REJECT_INVALID, "coinbase"); - // Rather not work on nonstandard transactions (unless -testnet/-regtest) - string reason; - if (fRequireStandard && !IsStandardTx(tx, reason)) - return state.DoS(0, false, REJECT_NONSTANDARD, reason); - // Don't relay version 2 transactions until CSV is active, and we can be // sure that such transactions will be mined (unless we're on // -testnet/-regtest). @@ -1146,10 +1138,16 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } // Reject transactions with witness before segregated witness activates (override with -prematurewitness) - if (!GetBoolArg("-prematurewitness",false) && !tx.wit.IsNull() && !IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus())) { + bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()); + if (!GetBoolArg("-prematurewitness",false) && !tx.wit.IsNull() && !witnessEnabled) { return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true); } + // Rather not work on nonstandard transactions (unless -testnet/-regtest) + string reason; + if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled)) + return state.DoS(0, false, REJECT_NONSTANDARD, reason); + // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. @@ -1293,7 +1291,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. - if ((nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) || (nBytesPerSigOp && nSigOpsCost > nSize * WITNESS_SCALE_FACTOR / nBytesPerSigOp)) + if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, strprintf("%d", nSigOpsCost)); @@ -1543,7 +1541,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } } - SyncWithWallets(tx, NULL, NULL); + SyncWithWallets(tx, NULL); return true; } @@ -2240,68 +2238,6 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } -// -// Called periodically asynchronously; alerts if it smells like -// we're being fed a bad chain (blocks being generated much -// too slowly or too quickly). -// -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, - int64_t nPowTargetSpacing) -{ - if (bestHeader == NULL || initialDownloadCheck()) return; - - static int64_t lastAlertTime = 0; - int64_t now = GetAdjustedTime(); - if (lastAlertTime > now-60*60*24) return; // Alert at most once per day - - const int SPAN_HOURS=4; - const int SPAN_SECONDS=SPAN_HOURS*60*60; - int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; - - boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED); - - std::string strWarning; - int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; - - LOCK(cs); - const CBlockIndex* i = bestHeader; - int nBlocks = 0; - while (i->GetBlockTime() >= startTime) { - ++nBlocks; - i = i->pprev; - if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed - } - - // How likely is it to find that many by chance? - double p = boost::math::pdf(poisson, nBlocks); - - LogPrint("partitioncheck", "%s: Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); - LogPrint("partitioncheck", "%s: likelihood: %g\n", __func__, p); - - // Aim for one false-positive about every fifty years of normal running: - const int FIFTY_YEARS = 50*365*24*60*60; - double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); - - if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) - { - // Many fewer blocks than expected: alert! - strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"), - nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); - } - else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED) - { - // Many more blocks than expected: alert! - strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"), - nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); - } - if (!strWarning.empty()) - { - strMiscWarning = strWarning; - AlertNotify(strWarning); - lastAlertTime = now; - } -} - // Protected by cs_main VersionBitsCache versionbitscache; @@ -2431,15 +2367,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; - // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, - // when 75% of the network has upgraded: - if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + // Start enforcing the DERSIG (BIP66) rule + if (pindex->nHeight >= chainparams.GetConsensus().BIP66Height) { flags |= SCRIPT_VERIFY_DERSIG; } - // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 - // blocks, when 75% of the network has upgraded: - if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule + if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height) { flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } @@ -2836,7 +2770,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, pindexDelete->pprev, NULL); + SyncWithWallets(tx, pindexDelete->pprev); } return true; } @@ -2851,7 +2785,7 @@ static int64_t nTimePostConnect = 0; * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ -bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock) +bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::list<CTransaction> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int> > &txChanged) { assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. @@ -2887,20 +2821,13 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, return false; int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); - // Remove conflicting transactions from the mempool. - list<CTransaction> txConflicted; + // Remove conflicting transactions from the mempool.; mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); // Update chainActive & related variables. UpdateTip(pindexNew, chainparams); - // Tell wallet about transactions that went from mempool - // to conflicted: - BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, pindexNew, NULL); - } - // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pindexNew, pblock); - } + + for(unsigned int i=0; i < pblock->vtx.size(); i++) + txChanged.push_back(std::make_tuple(pblock->vtx[i], pindexNew, i)); int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); @@ -2982,7 +2909,7 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound) +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::list<CTransaction>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int> >& txChanged) { AssertLockHeld(cs_main); const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -3015,7 +2942,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c // Connect new blocks. BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL, txConflicted, txChanged)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -3090,6 +3017,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, break; const CBlockIndex *pindexFork; + std::list<CTransaction> txConflicted; + std::vector<std::tuple<CTransaction,CBlockIndex*,int> > txChanged; bool fInitialDownload; int nNewHeight; { @@ -3104,7 +3033,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, return true; bool fInvalidFound = false; - if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound)) + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound, txConflicted, txChanged)) return false; if (fInvalidFound) { @@ -3119,6 +3048,17 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, // When we reach this point, we switched to a new tip (stored in pindexNewTip). // Notifications/callbacks that can run without cs_main + + // throw all transactions though the signal-interface + // while _not_ holding the cs_main lock + BOOST_FOREACH(const CTransaction &tx, txConflicted) + { + SyncWithWallets(tx, pindexNewTip); + } + // ... and about transactions that got confirmed: + for(unsigned int i = 0; i < txChanged.size(); i++) + SyncWithWallets(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i])); + // Always notify the UI if a new block tip was connected if (pindexFork != pindexNewTip) { uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); @@ -3463,13 +3403,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase"); // Check transactions - BOOST_FOREACH(const CTransaction& tx, block.vtx) + for (const auto& tx : block.vtx) if (!CheckTransaction(tx, state)) return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage())); unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, block.vtx) + for (const auto& tx : block.vtx) { nSigOps += GetLegacySigOpCount(tx); } @@ -3561,8 +3501,9 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc return commitment; } -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex * const pindexPrev, int64_t nAdjustedTime) +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) { + const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); @@ -3576,18 +3517,19 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future"); // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded: - for (int32_t version = 2; version < 5; ++version) // check for version 2, 3 and 4 upgrades - if (block.nVersion < version && IsSuperMajority(version, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", version - 1), - strprintf("rejected nVersion=0x%08x block", version - 1)); + // check for version 2, 3 and 4 upgrades + if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || + (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || + (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) + return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), + strprintf("rejected nVersion=0x%08x block", block.nVersion)); return true; } -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; - const Consensus::Params& consensusParams = Params().GetConsensus(); // Start enforcing BIP113 (Median Time Past) using versionbits logic. int nLockTimeFlags = 0; @@ -3600,15 +3542,14 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn : block.GetBlockTime(); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) { + for (const auto& tx : block.vtx) { if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); } } - // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)) + // Enforce rule that the coinbase starts with serialized block height + if (nHeight >= consensusParams.BIP34Height) { CScript expect = CScript() << nHeight; if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || @@ -3626,7 +3567,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are // multiple, the last one is used. bool fHaveWitness = false; - if (IsWitnessEnabled(pindexPrev, consensusParams)) { + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) { int commitpos = GetWitnessCommitmentIndex(block); if (commitpos != -1) { bool malleated = false; @@ -3635,11 +3576,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn // already does not permit it, it is impossible to trigger in the // witness tree. if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) { - return state.DoS(100, error("%s : invalid witness nonce size", __func__), REJECT_INVALID, "bad-witness-nonce-size", true); + return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__)); } CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) { - return state.DoS(100, error("%s : witness merkle commitment mismatch", __func__), REJECT_INVALID, "bad-witness-merkle-match", true); + return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__)); } fHaveWitness = true; } @@ -3649,19 +3590,19 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn if (!fHaveWitness) { for (size_t i = 0; i < block.vtx.size(); i++) { if (!block.vtx[i].wit.IsNull()) { - return state.DoS(100, error("%s : unexpected witness data found", __func__), REJECT_INVALID, "unexpected-witness", true); + return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__)); } } } // After the coinbase witness nonce and commitment are verified, - // we can check if the block cost passes (before we've checked the - // coinbase witness, it would be possible for the cost to be too + // we can check if the block weight passes (before we've checked the + // coinbase witness, it would be possible for the weight to be too // large by filling up the coinbase witness, which doesn't change // the block hash, so we couldn't mark the block as permanently // failed). - if (GetBlockCost(block) > MAX_BLOCK_COST) { - return state.DoS(100, error("ContextualCheckBlock(): cost limit failed"), REJECT_INVALID, "bad-blk-cost"); + if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) { + return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__)); } return true; @@ -3748,7 +3689,8 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha } if (fNewBlock) *fNewBlock = true; - if ((!CheckBlock(block, state, chainparams.GetConsensus(), GetAdjustedTime())) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if (!CheckBlock(block, state, chainparams.GetConsensus(), GetAdjustedTime()) || + !ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) { if (state.IsInvalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); @@ -3781,19 +3723,6 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha return true; } -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) -{ - unsigned int nFound = 0; - for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) - { - if (pstart->nVersion >= minVersion) - ++nFound; - pstart = pstart->pprev; - } - return (nFound >= nRequired); -} - - bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) { { @@ -3839,7 +3768,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot)) return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); - if (!ContextualCheckBlock(block, state, pindexPrev)) + if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev)) return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state)); if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) return false; @@ -4159,7 +4088,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nGoodTransactions = 0; CValidationState state; int reportDone = 0; - LogPrintf("[0%]..."); + LogPrintf("[0%%]..."); for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); @@ -4390,8 +4319,6 @@ bool InitBlockIndex(const CChainParams& chainparams) CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, chainparams, &block)) - return error("LoadBlockIndex(): genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); } catch (const std::runtime_error& e) { @@ -5402,7 +5329,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, BlockMap::iterator it = mapBlockIndex.find(req.blockhash); if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) { - Misbehaving(pfrom->GetId(), 100); LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id); return true; } @@ -5686,8 +5612,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); pfrom->PushMessage(NetMsgType::GETDATA, vInv); - return true; } + return true; } // If we're not close to tip yet, give up and let parallel block fetch work its magic @@ -5835,12 +5761,34 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } - // If we already know the last header in the message, then it contains - // no new information for us. In this case, we do not request - // more headers later. This prevents multiple chains of redundant - // getheader requests from running in parallel if triggered by incoming - // blocks while the node is still in initial headers sync. - const bool hasNewHeaders = (mapBlockIndex.count(headers.back().GetHash()) == 0); + CNodeState *nodestate = State(pfrom->GetId()); + + // If this looks like it could be a block announcement (nCount < + // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that + // don't connect: + // - Send a getheaders message in response to try to connect the chain. + // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that + // don't connect before giving DoS points + // - Once a headers message is received that is valid and does connect, + // nUnconnectingHeaders gets reset back to 0. + if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { + nodestate->nUnconnectingHeaders++; + pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()); + LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", + headers[0].GetHash().ToString(), + headers[0].hashPrevBlock.ToString(), + pindexBestHeader->nHeight, + pfrom->id, nodestate->nUnconnectingHeaders); + // Set hashLastUnknownBlock for this peer, so that if we + // eventually get the headers - even from a different peer - + // we can use this peer to download. + UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); + + if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) { + Misbehaving(pfrom->GetId(), 20); + } + return true; + } CBlockIndex *pindexLast = NULL; BOOST_FOREACH(const CBlockHeader& header, headers) { @@ -5859,10 +5807,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } + if (nodestate->nUnconnectingHeaders > 0) { + LogPrint("net", "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->id, nodestate->nUnconnectingHeaders); + } + nodestate->nUnconnectingHeaders = 0; + assert(pindexLast); UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); - if (nCount == MAX_HEADERS_RESULTS && hasNewHeaders) { + if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. @@ -5871,7 +5824,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); - CNodeState *nodestate = State(pfrom->GetId()); // If this set of headers is valid and ends in a block with at least as // much work as our tip, download as much as possible. if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { @@ -6179,6 +6131,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } + else if (strCommand == NetMsgType::NOTFOUND) { + // We do not care about the NOTFOUND message, but logging an Unknown Command + // message would be undesirable as we transmit it ourselves. + } + else { // Ignore unknown commands for extensibility LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); @@ -6538,7 +6495,7 @@ bool SendMessages(CNode* pto) CBlock block; assert(ReadBlockFromDisk(block, pBestIndex, consensusParams)); CBlockHeaderAndShortTxIDs cmpctblock(block); - pto->PushMessage(NetMsgType::CMPCTBLOCK, cmpctblock); + pto->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); state.pindexBestHeaderSent = pBestIndex; } else if (state.fPreferHeaders) { if (vHeaders.size() > 1) { diff --git a/src/main.h b/src/main.h index 2ffe5770d..d4d70c018 100644 --- a/src/main.h +++ b/src/main.h @@ -124,7 +124,6 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; /** Default for -permitbaremultisig */ static const bool DEFAULT_PERMIT_BAREMULTISIG = true; -static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; static const bool DEFAULT_CHECKPOINTS_ENABLED = true; static const bool DEFAULT_TXINDEX = false; static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; @@ -138,6 +137,9 @@ static const bool DEFAULT_FEEFILTER = true; /** Maximum number of headers to announce when relaying blocks with headers message.*/ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; +/** Maximum number of unconnecting headers announcements before DoS score */ +static const int MAX_UNCONNECTING_HEADERS = 10; + static const bool DEFAULT_PEERBLOOMFILTERS = true; struct BlockHasher @@ -152,7 +154,7 @@ typedef boost::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; -extern uint64_t nLastBlockCost; +extern uint64_t nLastBlockWeight; extern const std::string strMessageMagic; extern CWaitableCriticalSection csBestBlock; extern CConditionVariable cvBlockChange; @@ -162,7 +164,6 @@ extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; extern bool fRequireStandard; -extern unsigned int nBytesPerSigOp; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; @@ -247,8 +248,6 @@ bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); -/** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core. @@ -353,9 +352,22 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); +/** Transaction validation functions */ + /** Context-independent validity checks */ bool CheckTransaction(const CTransaction& tx, CValidationState& state); +namespace Consensus { + +/** + * Check whether all inputs of this transaction are valid (no double spends and amounts) + * This does not modify the UTXO set. This does not check scripts and sigs. + * Preconditions: tx.IsCoinBase() is false. + */ +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight); + +} // namespace Consensus + /** * Check if transaction is final and can be included in a block with the * specified height and time. Consensus critical. @@ -446,8 +458,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P /** Context-dependent validity checks. * By "context", we mean only the previous block headers, but not the UTXO * set; UTXO-related validity checks are done in ConnectBlock(). */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex* pindexPrev, int64_t nAdjustedTime); -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime); +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() diff --git a/src/miner.cpp b/src/miner.cpp index cfc2dae56..957585884 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -45,7 +45,7 @@ using namespace std; uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; -uint64_t nLastBlockCost = 0; +uint64_t nLastBlockWeight = 0; class ScoreCompare { @@ -77,35 +77,31 @@ BlockAssembler::BlockAssembler(const CChainParams& _chainparams) : chainparams(_chainparams) { // Block resource limits - // If neither -blockmaxsize or -blockmaxcost is given, limit to DEFAULT_BLOCK_MAX_* + // If neither -blockmaxsize or -blockmaxweight is given, limit to DEFAULT_BLOCK_MAX_* // If only one is given, only restrict the specified resource. // If both are given, restrict both. - nBlockMaxCost = DEFAULT_BLOCK_MAX_COST; + nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE; - bool fCostSet = false; - if (mapArgs.count("-blockmaxcost")) { - nBlockMaxCost = GetArg("-blockmaxcost", DEFAULT_BLOCK_MAX_COST); + bool fWeightSet = false; + if (mapArgs.count("-blockmaxweight")) { + nBlockMaxWeight = GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE; - fCostSet = true; + fWeightSet = true; } if (mapArgs.count("-blockmaxsize")) { nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - if (!fCostSet) { - nBlockMaxCost = nBlockMaxSize * WITNESS_SCALE_FACTOR; + if (!fWeightSet) { + nBlockMaxWeight = nBlockMaxSize * WITNESS_SCALE_FACTOR; } } - // Limit cost to between 4K and MAX_BLOCK_COST-4K for sanity: - nBlockMaxCost = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_COST-4000), nBlockMaxCost)); + + // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity: + nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_WEIGHT-4000), nBlockMaxWeight)); // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize)); - // Minimum block size you want to create; block will be filled with free transactions - // until there are no more or the block reaches this size: - nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); - nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - - // Whether we need to account for byte usage (in addition to cost usage) - fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000) || (nBlockMinSize > 0); + // Whether we need to account for byte usage (in addition to weight usage) + fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000); } void BlockAssembler::resetBlock() @@ -114,7 +110,7 @@ void BlockAssembler::resetBlock() // Reserve space for coinbase tx nBlockSize = 1000; - nBlockCost = 4000; + nBlockWeight = 4000; nBlockSigOpsCost = 400; fIncludeWitness = false; @@ -167,17 +163,11 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()); addPriorityTxs(); - if (fNeedSizeAccounting) { - // addPackageTxs (the CPFP-based algorithm) cannot deal with size based - // accounting, so fall back to the old algorithm. - addScoreTxs(); - } else { - addPackageTxs(); - } + addPackageTxs(); nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - nLastBlockCost = nBlockCost; + nLastBlockWeight = nBlockWeight; LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost); // Create coinbase transaction. @@ -197,7 +187,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; - pblocktemplate->vTxSigOpsCost[0] = GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { @@ -233,38 +223,51 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet) bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) { - // TODO: switch to cost-based accounting for packages instead of vsize-based accounting. - if (nBlockCost + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxCost) + // TODO: switch to weight-based accounting for packages instead of vsize-based accounting. + if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight) return false; if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST) return false; return true; } -// Block size and sigops have already been tested. Check that all transactions -// are final. -bool BlockAssembler::TestPackageFinality(const CTxMemPool::setEntries& package) +// Perform transaction-level checks before adding to block: +// - transaction finality (locktime) +// - premature witness (in case segwit transactions are added to mempool before +// segwit activation) +// - serialized size (in case -blockmaxsize is in use) +bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) { + uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting BOOST_FOREACH (const CTxMemPool::txiter it, package) { if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff)) return false; + if (!fIncludeWitness && !it->GetTx().wit.IsNull()) + return false; + if (fNeedSizeAccounting) { + uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); + if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) { + return false; + } + nPotentialBlockSize += nTxSize; + } } return true; } bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter) { - if (nBlockCost + iter->GetTxCost() >= nBlockMaxCost) { + if (nBlockWeight + iter->GetTxWeight() >= nBlockMaxWeight) { // If the block is so close to full that no more txs will fit // or if we've tried more than 50 times to fill remaining space // then flag that the block is finished - if (nBlockCost > nBlockMaxCost - 400 || lastFewTxs > 50) { + if (nBlockWeight > nBlockMaxWeight - 400 || lastFewTxs > 50) { blockFinished = true; return false; } - // Once we're within 4000 cost of a full block, only look at 50 more txs + // Once we're within 4000 weight of a full block, only look at 50 more txs // to try to fill the remaining space. - if (nBlockCost > nBlockMaxCost - 4000) { + if (nBlockWeight > nBlockMaxWeight - 4000) { lastFewTxs++; } return false; @@ -312,7 +315,7 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) if (fNeedSizeAccounting) { nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION); } - nBlockCost += iter->GetTxCost(); + nBlockWeight += iter->GetTxWeight(); ++nBlockTx; nBlockSigOpsCost += iter->GetSigOpCost(); nFees += iter->GetFee(); @@ -330,66 +333,6 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) } } -void BlockAssembler::addScoreTxs() -{ - std::priority_queue<CTxMemPool::txiter, std::vector<CTxMemPool::txiter>, ScoreCompare> clearedTxs; - CTxMemPool::setEntries waitSet; - CTxMemPool::indexed_transaction_set::index<mining_score>::type::iterator mi = mempool.mapTx.get<mining_score>().begin(); - CTxMemPool::txiter iter; - while (!blockFinished && (mi != mempool.mapTx.get<mining_score>().end() || !clearedTxs.empty())) - { - // If no txs that were previously postponed are available to try - // again, then try the next highest score tx - if (clearedTxs.empty()) { - iter = mempool.mapTx.project<0>(mi); - mi++; - } - // If a previously postponed tx is available to try again, then it - // has higher score than all untried so far txs - else { - iter = clearedTxs.top(); - clearedTxs.pop(); - } - - // If tx already in block, skip (added by addPriorityTxs) - if (inBlock.count(iter)) { - continue; - } - - // cannot accept witness transactions into a non-witness block - if (!fIncludeWitness && !iter->GetTx().wit.IsNull()) - continue; - - // If tx is dependent on other mempool txs which haven't yet been included - // then put it in the waitSet - if (isStillDependent(iter)) { - waitSet.insert(iter); - continue; - } - - // If the fee rate is below the min fee rate for mining, then we're done - // adding txs based on score (fee rate) - if (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(iter->GetTxSize()) && nBlockSize >= nBlockMinSize) { - return; - } - - // If this tx fits in the block add it, otherwise keep looping - if (TestForBlock(iter)) { - AddToBlock(iter); - - // This tx was successfully added, so - // add transactions that depend on this one to the priority queue to try again - BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) - { - if (waitSet.count(child)) { - clearedTxs.push(child); - waitSet.erase(child); - } - } - } - } -} - void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx) { @@ -539,7 +482,7 @@ void BlockAssembler::addPackageTxs() ancestors.insert(iter); // Test if all tx's are Final - if (!TestPackageFinality(ancestors)) { + if (!TestPackageTransactions(ancestors)) { if (fUsingModified) { mapModifiedTx.get<ancestor_score>().erase(modit); failedTx.insert(iter); @@ -573,6 +516,7 @@ void BlockAssembler::addPriorityTxs() return; } + bool fSizeAccounting = fNeedSizeAccounting; fNeedSizeAccounting = true; // This vector will be sorted into a priority queue: @@ -624,7 +568,7 @@ void BlockAssembler::addPriorityTxs() // If now that this txs is added we've surpassed our desired priority size // or have dropped below the AllowFreeThreshold, then we're done adding priority txs if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) { - return; + break; } // This tx was successfully added, so @@ -640,6 +584,7 @@ void BlockAssembler::addPriorityTxs() } } } + fNeedSizeAccounting = fSizeAccounting; } void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce) diff --git a/src/miner.h b/src/miner.h index b303a8fa3..11753f5e4 100644 --- a/src/miner.h +++ b/src/miner.h @@ -141,11 +141,11 @@ private: // Configuration parameters for the block size bool fIncludeWitness; - unsigned int nBlockMaxCost, nBlockMaxSize, nBlockMinSize; + unsigned int nBlockMaxWeight, nBlockMaxSize; bool fNeedSizeAccounting; // Information on the current status of the block - uint64_t nBlockCost; + uint64_t nBlockWeight; uint64_t nBlockSize; uint64_t nBlockTx; uint64_t nBlockSigOpsCost; @@ -157,7 +157,7 @@ private: int64_t nLockTimeCutoff; const CChainParams& chainparams; - // Variables used for addScoreTxs and addPriorityTxs + // Variables used for addPriorityTxs int lastFewTxs; bool blockFinished; @@ -174,14 +174,12 @@ private: void AddToBlock(CTxMemPool::txiter iter); // Methods for how to add transactions to a block. - /** Add transactions based on modified feerate */ - void addScoreTxs(); /** Add transactions based on tx "priority" */ void addPriorityTxs(); /** Add transactions based on feerate including unconfirmed ancestors */ void addPackageTxs(); - // helper function for addScoreTxs and addPriorityTxs + // helper function for addPriorityTxs /** Test if tx will still "fit" in the block */ bool TestForBlock(CTxMemPool::txiter iter); /** Test if tx still has unconfirmed parents not yet in block */ @@ -192,8 +190,11 @@ private: void onlyUnconfirmed(CTxMemPool::setEntries& testSet); /** Test if a new package would "fit" in the block */ bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost); - /** Test if a set of transactions are all final */ - bool TestPackageFinality(const CTxMemPool::setEntries& package); + /** Perform checks on each transaction in a package: + * locktime, premature-witness, serialized size (if necessary) + * These checks should always succeed, and they're here + * only as an extra check in case of suboptimal node configuration */ + bool TestPackageTransactions(const CTxMemPool::setEntries& package); /** Return true if given transaction from mapTx has already been evaluated, * or if the transaction's cached data in mapTx is incorrect. */ bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx); diff --git a/src/net.cpp b/src/net.cpp index 4cbc43e4d..a0773b2e0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -17,6 +17,7 @@ #include "crypto/sha256.h" #include "hash.h" #include "primitives/transaction.h" +#include "netbase.h" #include "scheduler.h" #include "ui_interface.h" #include "utilstrencodings.h" @@ -175,7 +176,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn // one by discovery. CAddress GetLocalAddress(const CNetAddr *paddrPeer) { - CAddress ret(CService("0.0.0.0",GetListenPort()), NODE_NONE); + CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE); CService addr; if (GetLocal(addr, paddrPeer)) { @@ -494,7 +495,7 @@ void CNode::PushVersion() int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices)); + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) @@ -982,11 +983,11 @@ static bool AttemptToEvictConnection() { uint64_t naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapAddrCounts; + std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes; BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { - mapAddrCounts[node.nKeyedNetGroup].push_back(node); - int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected; - size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size(); + mapNetGroupNodes[node.nKeyedNetGroup].push_back(node); + int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected; + size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; @@ -996,7 +997,7 @@ static bool AttemptToEvictConnection() { } // Reduce to the network group with the most connections - vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); + vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]); // Disconnect from the network group with the most connections NodeId evicted = vEvictionCandidates.front().id; @@ -1396,8 +1397,11 @@ void ThreadMapPort() { if(externalIPAddress[0]) { - LogPrintf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); - AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); + CNetAddr resolved; + if(LookupHost(externalIPAddress, resolved, false)) { + LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str()); + AddLocal(resolved, LOCAL_UPNP); + } } else LogPrintf("UPnP: GetExternalIPAddress failed.\n"); @@ -1623,7 +1627,9 @@ void ThreadOpenConnections() static bool done = false; if (!done) { LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); - addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); + CNetAddr local; + LookupHost("127.0.0.1", local, false); + addrman.Add(convertSeed6(Params().FixedSeeds()), local); done = true; } } @@ -1722,7 +1728,7 @@ std::vector<AddedNodeInfo> GetAddedNodeInfo() } BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - CService service(strAddNode, Params().GetDefaultPort()); + CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort())); if (service.IsValid()) { // strAddNode is an IP:port auto it = mapConnected.find(service); @@ -1760,7 +1766,7 @@ void ThreadOpenAddedConnections() CSemaphoreGrant grant(*semOutbound); // If strAddedNode is an IP/port, decode it immediately, so // OpenNetworkConnection can detect existing connections to that IP/port. - CService service(info.strAddedNode, Params().GetDefaultPort()); + CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); MilliSleep(500); } @@ -2050,6 +2056,8 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) DumpBanlist(); } + uiInterface.InitMessage(_("Starting network threads...")); + fAddressesInitialized = true; if (semOutbound == NULL) { @@ -2058,8 +2066,11 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) semOutbound = new CSemaphore(nMaxOutbound); } - if (pnodeLocalHost == NULL) - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); + if (pnodeLocalHost == NULL) { + CNetAddr local; + LookupHost("127.0.0.1", local, false); + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + } Discover(threadGroup); @@ -10,7 +10,7 @@ #include "bloom.h" #include "compat.h" #include "limitedmap.h" -#include "netbase.h" +#include "netaddress.h" #include "protocol.h" #include "random.h" #include "streams.h" diff --git a/src/netaddress.cpp b/src/netaddress.cpp new file mode 100644 index 000000000..7000ce3f0 --- /dev/null +++ b/src/netaddress.cpp @@ -0,0 +1,716 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifdef HAVE_CONFIG_H +#include "config/bitcoin-config.h" +#endif + +#include "netaddress.h" +#include "hash.h" +#include "utilstrencodings.h" +#include "tinyformat.h" + +static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; +static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; + +void CNetAddr::Init() +{ + memset(ip, 0, sizeof(ip)); + scopeId = 0; +} + +void CNetAddr::SetIP(const CNetAddr& ipIn) +{ + memcpy(ip, ipIn.ip, sizeof(ip)); +} + +void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) +{ + switch(network) + { + case NET_IPV4: + memcpy(ip, pchIPv4, 12); + memcpy(ip+12, ip_in, 4); + break; + case NET_IPV6: + memcpy(ip, ip_in, 16); + break; + default: + assert(!"invalid network"); + } +} + +bool CNetAddr::SetSpecial(const std::string &strName) +{ + if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") { + std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); + if (vchAddr.size() != 16-sizeof(pchOnionCat)) + return false; + memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); + for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++) + ip[i + sizeof(pchOnionCat)] = vchAddr[i]; + return true; + } + return false; +} + +CNetAddr::CNetAddr() +{ + Init(); +} + +CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) +{ + SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr); +} + +CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope) +{ + SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); + scopeId = scope; +} + +unsigned int CNetAddr::GetByte(int n) const +{ + return ip[15-n]; +} + +bool CNetAddr::IsIPv4() const +{ + return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); +} + +bool CNetAddr::IsIPv6() const +{ + return (!IsIPv4() && !IsTor()); +} + +bool CNetAddr::IsRFC1918() const +{ + return IsIPv4() && ( + GetByte(3) == 10 || + (GetByte(3) == 192 && GetByte(2) == 168) || + (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); +} + +bool CNetAddr::IsRFC2544() const +{ + return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19); +} + +bool CNetAddr::IsRFC3927() const +{ + return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); +} + +bool CNetAddr::IsRFC6598() const +{ + return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127; +} + +bool CNetAddr::IsRFC5737() const +{ + return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) || + (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) || + (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113)); +} + +bool CNetAddr::IsRFC3849() const +{ + return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; +} + +bool CNetAddr::IsRFC3964() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x02); +} + +bool CNetAddr::IsRFC6052() const +{ + static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); +} + +bool CNetAddr::IsRFC4380() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); +} + +bool CNetAddr::IsRFC4862() const +{ + static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); +} + +bool CNetAddr::IsRFC4193() const +{ + return ((GetByte(15) & 0xFE) == 0xFC); +} + +bool CNetAddr::IsRFC6145() const +{ + static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0}; + return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); +} + +bool CNetAddr::IsRFC4843() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); +} + +bool CNetAddr::IsTor() const +{ + return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); +} + +bool CNetAddr::IsLocal() const +{ + // IPv4 loopback + if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) + return true; + + // IPv6 loopback (::1/128) + static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + if (memcmp(ip, pchLocal, 16) == 0) + return true; + + return false; +} + +bool CNetAddr::IsMulticast() const +{ + return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) + || (GetByte(15) == 0xFF); +} + +bool CNetAddr::IsValid() const +{ + // Cleanup 3-byte shifted addresses caused by garbage in size field + // of addr messages from versions before 0.2.9 checksum. + // Two consecutive addr messages look like this: + // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26... + // so if the first length field is garbled, it reads the second batch + // of addr misaligned by 3 bytes. + if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0) + return false; + + // unspecified IPv6 address (::/128) + unsigned char ipNone[16] = {}; + if (memcmp(ip, ipNone, 16) == 0) + return false; + + // documentation IPv6 address + if (IsRFC3849()) + return false; + + if (IsIPv4()) + { + // INADDR_NONE + uint32_t ipNone = INADDR_NONE; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + + // 0 + ipNone = 0; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + } + + return true; +} + +bool CNetAddr::IsRoutable() const +{ + return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal()); +} + +enum Network CNetAddr::GetNetwork() const +{ + if (!IsRoutable()) + return NET_UNROUTABLE; + + if (IsIPv4()) + return NET_IPV4; + + if (IsTor()) + return NET_TOR; + + return NET_IPV6; +} + +std::string CNetAddr::ToStringIP() const +{ + if (IsTor()) + return EncodeBase32(&ip[6], 10) + ".onion"; + CService serv(*this, 0); + struct sockaddr_storage sockaddr; + socklen_t socklen = sizeof(sockaddr); + if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) { + char name[1025] = ""; + if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) + return std::string(name); + } + if (IsIPv4()) + return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); + else + return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", + GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12), + GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8), + GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4), + GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0)); +} + +std::string CNetAddr::ToString() const +{ + return ToStringIP(); +} + +bool operator==(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) == 0); +} + +bool operator!=(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) != 0); +} + +bool operator<(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) < 0); +} + +bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const +{ + if (!IsIPv4()) + return false; + memcpy(pipv4Addr, ip+12, 4); + return true; +} + +bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const +{ + memcpy(pipv6Addr, ip, 16); + return true; +} + +// get canonical identifier of an address' group +// no two connections will be attempted to addresses with the same group +std::vector<unsigned char> CNetAddr::GetGroup() const +{ + std::vector<unsigned char> vchRet; + int nClass = NET_IPV6; + int nStartByte = 0; + int nBits = 16; + + // all local addresses belong to the same group + if (IsLocal()) + { + nClass = 255; + nBits = 0; + } + + // all unroutable addresses belong to the same group + if (!IsRoutable()) + { + nClass = NET_UNROUTABLE; + nBits = 0; + } + // for IPv4 addresses, '1' + the 16 higher-order bits of the IP + // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix + else if (IsIPv4() || IsRFC6145() || IsRFC6052()) + { + nClass = NET_IPV4; + nStartByte = 12; + } + // for 6to4 tunnelled addresses, use the encapsulated IPv4 address + else if (IsRFC3964()) + { + nClass = NET_IPV4; + nStartByte = 2; + } + // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address + else if (IsRFC4380()) + { + vchRet.push_back(NET_IPV4); + vchRet.push_back(GetByte(3) ^ 0xFF); + vchRet.push_back(GetByte(2) ^ 0xFF); + return vchRet; + } + else if (IsTor()) + { + nClass = NET_TOR; + nStartByte = 6; + nBits = 4; + } + // for he.net, use /36 groups + else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70) + nBits = 36; + // for the rest of the IPv6 network, use /32 groups + else + nBits = 32; + + vchRet.push_back(nClass); + while (nBits >= 8) + { + vchRet.push_back(GetByte(15 - nStartByte)); + nStartByte++; + nBits -= 8; + } + if (nBits > 0) + vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1)); + + return vchRet; +} + +uint64_t CNetAddr::GetHash() const +{ + uint256 hash = Hash(&ip[0], &ip[16]); + uint64_t nRet; + memcpy(&nRet, &hash, sizeof(nRet)); + return nRet; +} + +// private extensions to enum Network, only returned by GetExtNetwork, +// and only used in GetReachabilityFrom +static const int NET_UNKNOWN = NET_MAX + 0; +static const int NET_TEREDO = NET_MAX + 1; +int static GetExtNetwork(const CNetAddr *addr) +{ + if (addr == NULL) + return NET_UNKNOWN; + if (addr->IsRFC4380()) + return NET_TEREDO; + return addr->GetNetwork(); +} + +/** Calculates a metric for how reachable (*this) is from a given partner */ +int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const +{ + enum Reachability { + REACH_UNREACHABLE, + REACH_DEFAULT, + REACH_TEREDO, + REACH_IPV6_WEAK, + REACH_IPV4, + REACH_IPV6_STRONG, + REACH_PRIVATE + }; + + if (!IsRoutable()) + return REACH_UNREACHABLE; + + int ourNet = GetExtNetwork(this); + int theirNet = GetExtNetwork(paddrPartner); + bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); + + switch(theirNet) { + case NET_IPV4: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_IPV4: return REACH_IPV4; + } + case NET_IPV6: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV4: return REACH_IPV4; + case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled + } + case NET_TOR: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well + case NET_TOR: return REACH_PRIVATE; + } + case NET_TEREDO: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV6: return REACH_IPV6_WEAK; + case NET_IPV4: return REACH_IPV4; + } + case NET_UNKNOWN: + case NET_UNROUTABLE: + default: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV6: return REACH_IPV6_WEAK; + case NET_IPV4: return REACH_IPV4; + case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address + } + } +} + +void CService::Init() +{ + port = 0; +} + +CService::CService() +{ + Init(); +} + +CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn) +{ +} + +CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) +{ +} + +CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) +{ +} + +CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) +{ + assert(addr.sin_family == AF_INET); +} + +CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port)) +{ + assert(addr.sin6_family == AF_INET6); +} + +bool CService::SetSockAddr(const struct sockaddr *paddr) +{ + switch (paddr->sa_family) { + case AF_INET: + *this = CService(*(const struct sockaddr_in*)paddr); + return true; + case AF_INET6: + *this = CService(*(const struct sockaddr_in6*)paddr); + return true; + default: + return false; + } +} + +unsigned short CService::GetPort() const +{ + return port; +} + +bool operator==(const CService& a, const CService& b) +{ + return (CNetAddr)a == (CNetAddr)b && a.port == b.port; +} + +bool operator!=(const CService& a, const CService& b) +{ + return (CNetAddr)a != (CNetAddr)b || a.port != b.port; +} + +bool operator<(const CService& a, const CService& b) +{ + return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); +} + +bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const +{ + if (IsIPv4()) { + if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) + return false; + *addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr; + memset(paddrin, 0, *addrlen); + if (!GetInAddr(&paddrin->sin_addr)) + return false; + paddrin->sin_family = AF_INET; + paddrin->sin_port = htons(port); + return true; + } + if (IsIPv6()) { + if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) + return false; + *addrlen = sizeof(struct sockaddr_in6); + struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr; + memset(paddrin6, 0, *addrlen); + if (!GetIn6Addr(&paddrin6->sin6_addr)) + return false; + paddrin6->sin6_scope_id = scopeId; + paddrin6->sin6_family = AF_INET6; + paddrin6->sin6_port = htons(port); + return true; + } + return false; +} + +std::vector<unsigned char> CService::GetKey() const +{ + std::vector<unsigned char> vKey; + vKey.resize(18); + memcpy(&vKey[0], ip, 16); + vKey[16] = port / 0x100; + vKey[17] = port & 0x0FF; + return vKey; +} + +std::string CService::ToStringPort() const +{ + return strprintf("%u", port); +} + +std::string CService::ToStringIPPort() const +{ + if (IsIPv4() || IsTor()) { + return ToStringIP() + ":" + ToStringPort(); + } else { + return "[" + ToStringIP() + "]:" + ToStringPort(); + } +} + +std::string CService::ToString() const +{ + return ToStringIPPort(); +} + +void CService::SetPort(unsigned short portIn) +{ + port = portIn; +} + +CSubNet::CSubNet(): + valid(false) +{ + memset(netmask, 0, sizeof(netmask)); +} + +CSubNet::CSubNet(const CNetAddr &addr, int32_t mask) +{ + valid = true; + network = addr; + // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address + memset(netmask, 255, sizeof(netmask)); + + // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n + const int astartofs = network.IsIPv4() ? 12 : 0; + + int32_t n = mask; + if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address + { + n += astartofs*8; + // Clear bits [n..127] + for (; n < 128; ++n) + netmask[n>>3] &= ~(1<<(7-(n&7))); + } else + valid = false; + + // Normalize network according to netmask + for(int x=0; x<16; ++x) + network.ip[x] &= netmask[x]; +} + +CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) +{ + valid = true; + network = addr; + // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address + memset(netmask, 255, sizeof(netmask)); + + // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n + const int astartofs = network.IsIPv4() ? 12 : 0; + + for(int x=astartofs; x<16; ++x) + netmask[x] = mask.ip[x]; + + // Normalize network according to netmask + for(int x=0; x<16; ++x) + 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()) + return false; + for(int x=0; x<16; ++x) + if ((addr.ip[x] & netmask[x]) != network.ip[x]) + return false; + return true; +} + +static inline int NetmaskBits(uint8_t x) +{ + switch(x) { + case 0x00: return 0; break; + case 0x80: return 1; break; + case 0xc0: return 2; break; + case 0xe0: return 3; break; + case 0xf0: return 4; break; + case 0xf8: return 5; break; + case 0xfc: return 6; break; + case 0xfe: return 7; break; + case 0xff: return 8; break; + default: return -1; break; + } +} + +std::string CSubNet::ToString() const +{ + /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */ + int cidr = 0; + bool valid_cidr = true; + int n = network.IsIPv4() ? 12 : 0; + for (; n < 16 && netmask[n] == 0xff; ++n) + cidr += 8; + if (n < 16) { + int bits = NetmaskBits(netmask[n]); + if (bits < 0) + valid_cidr = false; + else + cidr += bits; + ++n; + } + for (; n < 16 && valid_cidr; ++n) + if (netmask[n] != 0x00) + valid_cidr = false; + + /* Format output */ + std::string strNetmask; + if (valid_cidr) { + strNetmask = strprintf("%u", cidr); + } else { + if (network.IsIPv4()) + strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]); + else + strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x", + netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3], + netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7], + netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11], + netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]); + } + + return network.ToString() + "/" + strNetmask; +} + +bool CSubNet::IsValid() const +{ + return valid; +} + +bool operator==(const CSubNet& a, const CSubNet& b) +{ + return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16); +} + +bool operator!=(const CSubNet& a, const CSubNet& b) +{ + return !(a==b); +} + +bool operator<(const CSubNet& a, const CSubNet& b) +{ + return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0)); +} diff --git a/src/netaddress.h b/src/netaddress.h new file mode 100644 index 000000000..9330fe332 --- /dev/null +++ b/src/netaddress.h @@ -0,0 +1,171 @@ +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NETADDRESS_H +#define BITCOIN_NETADDRESS_H + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "compat.h" +#include "serialize.h" + +#include <stdint.h> +#include <string> +#include <vector> + +enum Network +{ + NET_UNROUTABLE = 0, + NET_IPV4, + NET_IPV6, + NET_TOR, + + NET_MAX, +}; + +/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ +class CNetAddr +{ + protected: + unsigned char ip[16]; // in network byte order + uint32_t scopeId; // for scoped/link-local ipv6 addresses + + public: + CNetAddr(); + CNetAddr(const struct in_addr& ipv4Addr); + void Init(); + void SetIP(const CNetAddr& ip); + + /** + * Set raw IPv4 or IPv6 address (in network byte order) + * @note Only NET_IPV4 and NET_IPV6 are allowed for network. + */ + void SetRaw(Network network, const uint8_t *data); + + bool SetSpecial(const std::string &strName); // for Tor addresses + bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) + bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) + bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) + bool IsRFC2544() const; // IPv4 inter-network communcations (192.18.0.0/15) + bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10) + bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24) + bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) + bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) + bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) + bool IsRFC4193() const; // IPv6 unique local (FC00::/7) + bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) + bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) + bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) + bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) + bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) + bool IsTor() const; + bool IsLocal() const; + bool IsRoutable() const; + bool IsValid() const; + bool IsMulticast() const; + enum Network GetNetwork() const; + std::string ToString() const; + std::string ToStringIP() const; + unsigned int GetByte(int n) const; + uint64_t GetHash() const; + bool GetInAddr(struct in_addr* pipv4Addr) const; + std::vector<unsigned char> GetGroup() const; + int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; + + CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0); + bool GetIn6Addr(struct in6_addr* pipv6Addr) const; + + friend bool operator==(const CNetAddr& a, const CNetAddr& b); + friend bool operator!=(const CNetAddr& a, const CNetAddr& b); + friend bool operator<(const CNetAddr& a, const CNetAddr& b); + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(FLATDATA(ip)); + } + + friend class CSubNet; +}; + +class CSubNet +{ + protected: + /// Network (base) address + CNetAddr network; + /// Netmask, in network byte order + uint8_t netmask[16]; + /// Is this value valid? (only used to signal parse errors) + bool valid; + + public: + CSubNet(); + CSubNet(const CNetAddr &addr, int32_t mask); + CSubNet(const CNetAddr &addr, const CNetAddr &mask); + + //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; + bool IsValid() const; + + 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 */ +class CService : public CNetAddr +{ + protected: + unsigned short port; // host order + + public: + CService(); + CService(const CNetAddr& ip, unsigned short port); + CService(const struct in_addr& ipv4Addr, unsigned short port); + CService(const struct sockaddr_in& addr); + void Init(); + void SetPort(unsigned short portIn); + unsigned short GetPort() const; + bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; + bool SetSockAddr(const struct sockaddr* paddr); + friend bool operator==(const CService& a, const CService& b); + friend bool operator!=(const CService& a, const CService& b); + friend bool operator<(const CService& a, const CService& b); + std::vector<unsigned char> GetKey() const; + std::string ToString() const; + std::string ToStringPort() const; + std::string ToStringIPPort() const; + + CService(const struct in6_addr& ipv6Addr, unsigned short port); + CService(const struct sockaddr_in6& addr); + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(FLATDATA(ip)); + unsigned short portN = htons(port); + READWRITE(FLATDATA(portN)); + if (ser_action.ForRead()) + port = ntohs(portN); + } +}; + +#endif // BITCOIN_NETADDRESS_H diff --git a/src/netbase.cpp b/src/netbase.cpp index e2a516986..4f243ec6f 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -42,8 +42,6 @@ static CCriticalSection cs_proxyInfos; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = DEFAULT_NAME_LOOKUP; -static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; - // Need ample time for negotiation for very slow proxies such as Tor (milliseconds) static const int SOCKS5_RECV_TIMEOUT = 20 * 1000; @@ -195,6 +193,16 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nM return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup); } +bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup) +{ + std::vector<CNetAddr> vIP; + LookupHost(pszName, vIP, 1, fAllowLookup); + if(vIP.empty()) + return false; + addr = vIP.front(); + return true; +} + bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) { if (pszName[0] == 0) @@ -223,9 +231,14 @@ bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLoo return true; } -bool LookupNumeric(const char *pszName, CService& addr, int portDefault) +CService LookupNumeric(const char *pszName, int portDefault) { - return Lookup(pszName, addr, portDefault, false); + CService addr; + // "1.2:345" will fail to resolve the ip, but will still set the port. + // If the ip fails to resolve, re-init the result. + if(!Lookup(pszName, addr, portDefault, false)) + addr = CService(); + return addr; } struct timeval MillisToTimeval(int64_t nTimeout) @@ -629,777 +642,48 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest } } - addr = CService("0.0.0.0:0"); + addr = CService(); if (!HaveNameProxy()) return false; return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed); } -void CNetAddr::Init() -{ - memset(ip, 0, sizeof(ip)); - scopeId = 0; -} - -void CNetAddr::SetIP(const CNetAddr& ipIn) -{ - memcpy(ip, ipIn.ip, sizeof(ip)); -} - -void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) -{ - switch(network) - { - case NET_IPV4: - memcpy(ip, pchIPv4, 12); - memcpy(ip+12, ip_in, 4); - break; - case NET_IPV6: - memcpy(ip, ip_in, 16); - break; - default: - assert(!"invalid network"); - } -} - -static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; - -bool CNetAddr::SetSpecial(const std::string &strName) -{ - if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") { - std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); - if (vchAddr.size() != 16-sizeof(pchOnionCat)) - return false; - memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); - for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++) - ip[i + sizeof(pchOnionCat)] = vchAddr[i]; - return true; - } - return false; -} - -CNetAddr::CNetAddr() -{ - Init(); -} - -CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) -{ - SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr); -} - -CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope) -{ - SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); - scopeId = scope; -} - -CNetAddr::CNetAddr(const char *pszIp) -{ - Init(); - std::vector<CNetAddr> vIP; - if (LookupHost(pszIp, vIP, 1, false)) - *this = vIP[0]; -} - -CNetAddr::CNetAddr(const std::string &strIp) -{ - Init(); - std::vector<CNetAddr> vIP; - if (LookupHost(strIp.c_str(), vIP, 1, false)) - *this = vIP[0]; -} - -unsigned int CNetAddr::GetByte(int n) const -{ - return ip[15-n]; -} - -bool CNetAddr::IsIPv4() const -{ - return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); -} - -bool CNetAddr::IsIPv6() const -{ - return (!IsIPv4() && !IsTor()); -} - -bool CNetAddr::IsRFC1918() const -{ - return IsIPv4() && ( - GetByte(3) == 10 || - (GetByte(3) == 192 && GetByte(2) == 168) || - (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); -} - -bool CNetAddr::IsRFC2544() const -{ - return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19); -} - -bool CNetAddr::IsRFC3927() const -{ - return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); -} - -bool CNetAddr::IsRFC6598() const -{ - return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127; -} - -bool CNetAddr::IsRFC5737() const -{ - return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) || - (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) || - (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113)); -} - -bool CNetAddr::IsRFC3849() const -{ - return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; -} - -bool CNetAddr::IsRFC3964() const -{ - return (GetByte(15) == 0x20 && GetByte(14) == 0x02); -} - -bool CNetAddr::IsRFC6052() const -{ - static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0}; - return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); -} - -bool CNetAddr::IsRFC4380() const -{ - return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); -} - -bool CNetAddr::IsRFC4862() const -{ - static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0}; - return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); -} - -bool CNetAddr::IsRFC4193() const -{ - return ((GetByte(15) & 0xFE) == 0xFC); -} - -bool CNetAddr::IsRFC6145() const -{ - static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0}; - return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); -} - -bool CNetAddr::IsRFC4843() const -{ - return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); -} - -bool CNetAddr::IsTor() const -{ - return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); -} - -bool CNetAddr::IsLocal() const -{ - // IPv4 loopback - if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) - return true; - - // IPv6 loopback (::1/128) - static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; - if (memcmp(ip, pchLocal, 16) == 0) - return true; - - return false; -} - -bool CNetAddr::IsMulticast() const -{ - return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) - || (GetByte(15) == 0xFF); -} - -bool CNetAddr::IsValid() const -{ - // Cleanup 3-byte shifted addresses caused by garbage in size field - // of addr messages from versions before 0.2.9 checksum. - // Two consecutive addr messages look like this: - // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26... - // so if the first length field is garbled, it reads the second batch - // of addr misaligned by 3 bytes. - if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0) - return false; - - // unspecified IPv6 address (::/128) - unsigned char ipNone[16] = {}; - if (memcmp(ip, ipNone, 16) == 0) - return false; - - // documentation IPv6 address - if (IsRFC3849()) - return false; - - if (IsIPv4()) - { - // INADDR_NONE - uint32_t ipNone = INADDR_NONE; - if (memcmp(ip+12, &ipNone, 4) == 0) - return false; - - // 0 - ipNone = 0; - if (memcmp(ip+12, &ipNone, 4) == 0) - return false; - } - - return true; -} - -bool CNetAddr::IsRoutable() const -{ - return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal()); -} - -enum Network CNetAddr::GetNetwork() const -{ - if (!IsRoutable()) - return NET_UNROUTABLE; - - if (IsIPv4()) - return NET_IPV4; - - if (IsTor()) - return NET_TOR; - - return NET_IPV6; -} - -std::string CNetAddr::ToStringIP() const -{ - if (IsTor()) - return EncodeBase32(&ip[6], 10) + ".onion"; - CService serv(*this, 0); - struct sockaddr_storage sockaddr; - socklen_t socklen = sizeof(sockaddr); - if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) { - char name[1025] = ""; - if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) - return std::string(name); - } - if (IsIPv4()) - return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); - else - return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", - GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12), - GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8), - GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4), - GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0)); -} - -std::string CNetAddr::ToString() const -{ - return ToStringIP(); -} - -bool operator==(const CNetAddr& a, const CNetAddr& b) -{ - return (memcmp(a.ip, b.ip, 16) == 0); -} - -bool operator!=(const CNetAddr& a, const CNetAddr& b) -{ - return (memcmp(a.ip, b.ip, 16) != 0); -} - -bool operator<(const CNetAddr& a, const CNetAddr& b) -{ - return (memcmp(a.ip, b.ip, 16) < 0); -} - -bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const -{ - if (!IsIPv4()) - return false; - memcpy(pipv4Addr, ip+12, 4); - return true; -} - -bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const -{ - memcpy(pipv6Addr, ip, 16); - return true; -} - -// get canonical identifier of an address' group -// no two connections will be attempted to addresses with the same group -std::vector<unsigned char> CNetAddr::GetGroup() const -{ - std::vector<unsigned char> vchRet; - int nClass = NET_IPV6; - int nStartByte = 0; - int nBits = 16; - - // all local addresses belong to the same group - if (IsLocal()) - { - nClass = 255; - nBits = 0; - } - - // all unroutable addresses belong to the same group - if (!IsRoutable()) - { - nClass = NET_UNROUTABLE; - nBits = 0; - } - // for IPv4 addresses, '1' + the 16 higher-order bits of the IP - // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix - else if (IsIPv4() || IsRFC6145() || IsRFC6052()) - { - nClass = NET_IPV4; - nStartByte = 12; - } - // for 6to4 tunnelled addresses, use the encapsulated IPv4 address - else if (IsRFC3964()) - { - nClass = NET_IPV4; - nStartByte = 2; - } - // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address - else if (IsRFC4380()) - { - vchRet.push_back(NET_IPV4); - vchRet.push_back(GetByte(3) ^ 0xFF); - vchRet.push_back(GetByte(2) ^ 0xFF); - return vchRet; - } - else if (IsTor()) - { - nClass = NET_TOR; - nStartByte = 6; - nBits = 4; - } - // for he.net, use /36 groups - else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70) - nBits = 36; - // for the rest of the IPv6 network, use /32 groups - else - nBits = 32; - - vchRet.push_back(nClass); - while (nBits >= 8) - { - vchRet.push_back(GetByte(15 - nStartByte)); - nStartByte++; - nBits -= 8; - } - if (nBits > 0) - vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1)); - - return vchRet; -} - -uint64_t CNetAddr::GetHash() const -{ - uint256 hash = Hash(&ip[0], &ip[16]); - uint64_t nRet; - memcpy(&nRet, &hash, sizeof(nRet)); - return nRet; -} - -// private extensions to enum Network, only returned by GetExtNetwork, -// and only used in GetReachabilityFrom -static const int NET_UNKNOWN = NET_MAX + 0; -static const int NET_TEREDO = NET_MAX + 1; -int static GetExtNetwork(const CNetAddr *addr) -{ - if (addr == NULL) - return NET_UNKNOWN; - if (addr->IsRFC4380()) - return NET_TEREDO; - return addr->GetNetwork(); -} - -/** Calculates a metric for how reachable (*this) is from a given partner */ -int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const -{ - enum Reachability { - REACH_UNREACHABLE, - REACH_DEFAULT, - REACH_TEREDO, - REACH_IPV6_WEAK, - REACH_IPV4, - REACH_IPV6_STRONG, - REACH_PRIVATE - }; - - if (!IsRoutable()) - return REACH_UNREACHABLE; - - int ourNet = GetExtNetwork(this); - int theirNet = GetExtNetwork(paddrPartner); - bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); - - switch(theirNet) { - case NET_IPV4: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_IPV4: return REACH_IPV4; - } - case NET_IPV6: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_TEREDO: return REACH_TEREDO; - case NET_IPV4: return REACH_IPV4; - case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled - } - case NET_TOR: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well - case NET_TOR: return REACH_PRIVATE; - } - case NET_TEREDO: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_TEREDO: return REACH_TEREDO; - case NET_IPV6: return REACH_IPV6_WEAK; - case NET_IPV4: return REACH_IPV4; - } - case NET_UNKNOWN: - case NET_UNROUTABLE: - default: - switch(ourNet) { - default: return REACH_DEFAULT; - case NET_TEREDO: return REACH_TEREDO; - case NET_IPV6: return REACH_IPV6_WEAK; - case NET_IPV4: return REACH_IPV4; - case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address - } - } -} - -void CService::Init() -{ - port = 0; -} - -CService::CService() -{ - Init(); -} - -CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn) -{ -} - -CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) -{ -} - -CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) -{ -} - -CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) -{ - assert(addr.sin_family == AF_INET); -} - -CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port)) -{ - assert(addr.sin6_family == AF_INET6); -} - -bool CService::SetSockAddr(const struct sockaddr *paddr) -{ - switch (paddr->sa_family) { - case AF_INET: - *this = CService(*(const struct sockaddr_in*)paddr); - return true; - case AF_INET6: - *this = CService(*(const struct sockaddr_in6*)paddr); - return true; - default: - return false; - } -} - -CService::CService(const char *pszIpPort) -{ - Init(); - CService ip; - if (Lookup(pszIpPort, ip, 0, false)) - *this = ip; -} - -CService::CService(const char *pszIpPort, int portDefault) -{ - Init(); - CService ip; - if (Lookup(pszIpPort, ip, portDefault, false)) - *this = ip; -} - -CService::CService(const std::string &strIpPort) -{ - Init(); - CService ip; - if (Lookup(strIpPort.c_str(), ip, 0, false)) - *this = ip; -} - -CService::CService(const std::string &strIpPort, int portDefault) -{ - Init(); - CService ip; - if (Lookup(strIpPort.c_str(), ip, portDefault, false)) - *this = ip; -} - -unsigned short CService::GetPort() const -{ - return port; -} - -bool operator==(const CService& a, const CService& b) -{ - return (CNetAddr)a == (CNetAddr)b && a.port == b.port; -} - -bool operator!=(const CService& a, const CService& b) -{ - return (CNetAddr)a != (CNetAddr)b || a.port != b.port; -} - -bool operator<(const CService& a, const CService& b) -{ - return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); -} - -bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const -{ - if (IsIPv4()) { - if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) - return false; - *addrlen = sizeof(struct sockaddr_in); - struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr; - memset(paddrin, 0, *addrlen); - if (!GetInAddr(&paddrin->sin_addr)) - return false; - paddrin->sin_family = AF_INET; - paddrin->sin_port = htons(port); - return true; - } - if (IsIPv6()) { - if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) - return false; - *addrlen = sizeof(struct sockaddr_in6); - struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr; - memset(paddrin6, 0, *addrlen); - if (!GetIn6Addr(&paddrin6->sin6_addr)) - return false; - paddrin6->sin6_scope_id = scopeId; - paddrin6->sin6_family = AF_INET6; - paddrin6->sin6_port = htons(port); - return true; - } - return false; -} - -std::vector<unsigned char> CService::GetKey() const -{ - std::vector<unsigned char> vKey; - vKey.resize(18); - memcpy(&vKey[0], ip, 16); - vKey[16] = port / 0x100; - vKey[17] = port & 0x0FF; - return vKey; -} - -std::string CService::ToStringPort() const -{ - return strprintf("%u", port); -} - -std::string CService::ToStringIPPort() const -{ - if (IsIPv4() || IsTor()) { - return ToStringIP() + ":" + ToStringPort(); - } else { - return "[" + ToStringIP() + "]:" + ToStringPort(); - } -} - -std::string CService::ToString() const -{ - return ToStringIPPort(); -} - -void CService::SetPort(unsigned short portIn) -{ - port = portIn; -} - -CSubNet::CSubNet(): - valid(false) -{ - memset(netmask, 0, sizeof(netmask)); -} - -CSubNet::CSubNet(const std::string &strSubnet) +bool LookupSubNet(const char* pszName, CSubNet& ret) { + std::string strSubnet(pszName); size_t slash = strSubnet.find_last_of('/'); std::vector<CNetAddr> vIP; - valid = true; - // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address - memset(netmask, 255, sizeof(netmask)); - std::string strAddress = strSubnet.substr(0, slash); if (LookupHost(strAddress.c_str(), vIP, 1, false)) { - network = vIP[0]; + CNetAddr network = vIP[0]; if (slash != strSubnet.npos) { std::string strNetmask = strSubnet.substr(slash + 1); int32_t n; // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n - const int astartofs = network.IsIPv4() ? 12 : 0; - if (ParseInt32(strNetmask, &n)) // If valid number, assume /24 symtex - { - if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address - { - n += astartofs*8; - // Clear bits [n..127] - for (; n < 128; ++n) - netmask[n>>3] &= ~(1<<(7-(n&7))); - } - else - { - valid = false; - } + if (ParseInt32(strNetmask, &n)) { // If valid number, assume /24 syntax + ret = CSubNet(network, n); + return ret.IsValid(); } else // If not a valid number, try full netmask syntax { - if (LookupHost(strNetmask.c_str(), vIP, 1, false)) // Never allow lookup for netmask - { - // Copy only the *last* four bytes in case of IPv4, the rest of the mask should stay 1's as - // we don't want pchIPv4 to be part of the mask. - for(int x=astartofs; x<16; ++x) - netmask[x] = vIP[0].ip[x]; - } - else - { - valid = false; + // Never allow lookup for netmask + if (LookupHost(strNetmask.c_str(), vIP, 1, false)) { + ret = CSubNet(network, vIP[0]); + return ret.IsValid(); } } } - } - else - { - valid = false; - } - - // Normalize network according to netmask - for(int x=0; x<16; ++x) - 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()) - return false; - for(int x=0; x<16; ++x) - if ((addr.ip[x] & netmask[x]) != network.ip[x]) - return false; - return true; -} - -static inline int NetmaskBits(uint8_t x) -{ - switch(x) { - case 0x00: return 0; break; - case 0x80: return 1; break; - case 0xc0: return 2; break; - case 0xe0: return 3; break; - case 0xf0: return 4; break; - case 0xf8: return 5; break; - case 0xfc: return 6; break; - case 0xfe: return 7; break; - case 0xff: return 8; break; - default: return -1; break; - } -} - -std::string CSubNet::ToString() const -{ - /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */ - int cidr = 0; - bool valid_cidr = true; - int n = network.IsIPv4() ? 12 : 0; - for (; n < 16 && netmask[n] == 0xff; ++n) - cidr += 8; - if (n < 16) { - int bits = NetmaskBits(netmask[n]); - if (bits < 0) - valid_cidr = false; else - cidr += bits; - ++n; - } - for (; n < 16 && valid_cidr; ++n) - if (netmask[n] != 0x00) - valid_cidr = false; - - /* Format output */ - std::string strNetmask; - if (valid_cidr) { - strNetmask = strprintf("%u", cidr); - } else { - if (network.IsIPv4()) - strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]); - else - strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x", - netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3], - netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7], - netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11], - netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]); + { + ret = CSubNet(network); + return ret.IsValid(); + } } - - return network.ToString() + "/" + strNetmask; -} - -bool CSubNet::IsValid() const -{ - return valid; -} - -bool operator==(const CSubNet& a, const CSubNet& b) -{ - return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16); -} - -bool operator!=(const CSubNet& a, const CSubNet& b) -{ - return !(a==b); -} - -bool operator<(const CSubNet& a, const CSubNet& b) -{ - return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0)); + return false; } #ifdef WIN32 diff --git a/src/netbase.h b/src/netbase.h index 65187a17c..bb12019a8 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -10,6 +10,7 @@ #endif #include "compat.h" +#include "netaddress.h" #include "serialize.h" #include <stdint.h> @@ -24,168 +25,6 @@ static const int DEFAULT_CONNECT_TIMEOUT = 5000; //! -dns default static const int DEFAULT_NAME_LOOKUP = true; -#ifdef WIN32 -// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error -#undef SetPort -#endif - -enum Network -{ - NET_UNROUTABLE = 0, - NET_IPV4, - NET_IPV6, - NET_TOR, - - NET_MAX, -}; - -/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ -class CNetAddr -{ - protected: - unsigned char ip[16]; // in network byte order - uint32_t scopeId; // for scoped/link-local ipv6 addresses - - public: - CNetAddr(); - CNetAddr(const struct in_addr& ipv4Addr); - explicit CNetAddr(const char *pszIp); - explicit CNetAddr(const std::string &strIp); - void Init(); - void SetIP(const CNetAddr& ip); - - /** - * Set raw IPv4 or IPv6 address (in network byte order) - * @note Only NET_IPV4 and NET_IPV6 are allowed for network. - */ - void SetRaw(Network network, const uint8_t *data); - - bool SetSpecial(const std::string &strName); // for Tor addresses - bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) - bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) - bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) - bool IsRFC2544() const; // IPv4 inter-network communcations (192.18.0.0/15) - bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10) - bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24) - bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) - bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) - bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) - bool IsRFC4193() const; // IPv6 unique local (FC00::/7) - bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) - bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) - bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) - bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) - bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) - bool IsTor() const; - bool IsLocal() const; - bool IsRoutable() const; - bool IsValid() const; - bool IsMulticast() const; - enum Network GetNetwork() const; - std::string ToString() const; - std::string ToStringIP() const; - unsigned int GetByte(int n) const; - uint64_t GetHash() const; - bool GetInAddr(struct in_addr* pipv4Addr) const; - std::vector<unsigned char> GetGroup() const; - int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; - - CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0); - bool GetIn6Addr(struct in6_addr* pipv6Addr) const; - - friend bool operator==(const CNetAddr& a, const CNetAddr& b); - friend bool operator!=(const CNetAddr& a, const CNetAddr& b); - friend bool operator<(const CNetAddr& a, const CNetAddr& b); - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(FLATDATA(ip)); - } - - friend class CSubNet; -}; - -class CSubNet -{ - protected: - /// Network (base) address - CNetAddr network; - /// Netmask, in network byte order - uint8_t netmask[16]; - /// Is this value valid? (only used to signal parse errors) - bool valid; - - public: - CSubNet(); - explicit CSubNet(const std::string &strSubnet); - - //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; - bool IsValid() const; - - 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 */ -class CService : public CNetAddr -{ - protected: - unsigned short port; // host order - - public: - CService(); - CService(const CNetAddr& ip, unsigned short port); - CService(const struct in_addr& ipv4Addr, unsigned short port); - CService(const struct sockaddr_in& addr); - explicit CService(const char *pszIpPort, int portDefault); - explicit CService(const char *pszIpPort); - explicit CService(const std::string& strIpPort, int portDefault); - explicit CService(const std::string& strIpPort); - void Init(); - void SetPort(unsigned short portIn); - unsigned short GetPort() const; - bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; - bool SetSockAddr(const struct sockaddr* paddr); - friend bool operator==(const CService& a, const CService& b); - friend bool operator!=(const CService& a, const CService& b); - friend bool operator<(const CService& a, const CService& b); - std::vector<unsigned char> GetKey() const; - std::string ToString() const; - std::string ToStringPort() const; - std::string ToStringIPPort() const; - - CService(const struct in6_addr& ipv6Addr, unsigned short port); - CService(const struct sockaddr_in6& addr); - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(FLATDATA(ip)); - unsigned short portN = htons(port); - READWRITE(FLATDATA(portN)); - if (ser_action.ForRead()) - port = ntohs(portN); - } -}; - class proxyType { public: @@ -207,9 +46,11 @@ bool IsProxy(const CNetAddr &addr); bool SetNameProxy(const proxyType &addrProxy); bool HaveNameProxy(); bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup); +bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup); bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup); bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions); -bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); +CService LookupNumeric(const char *pszName, int portDefault = 0); +bool LookupSubNet(const char *pszName, CSubNet& subnet); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed = 0); bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = 0); /** Return readable error string for a network error code */ diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index f2148bfe1..48080abc7 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -31,7 +31,7 @@ * DUP CHECKSIG DROP ... repeated 100 times... OP_1 */ -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled) { std::vector<std::vector<unsigned char> > vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) @@ -50,10 +50,13 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) return false; + else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH)) + return false; + return whichType != TX_NONSTANDARD; } -bool IsStandardTx(const CTransaction& tx, std::string& reason) +bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled) { if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; @@ -64,8 +67,8 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) // 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 = GetTransactionCost(tx); - if (sz >= MAX_STANDARD_TX_COST) { + unsigned int sz = GetTransactionWeight(tx); + if (sz >= MAX_STANDARD_TX_WEIGHT) { reason = "tx-size"; return false; } @@ -92,7 +95,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) unsigned int nDataOut = 0; txnouttype whichType; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey, whichType)) { + if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) { reason = "scriptpubkey"; return false; } @@ -151,12 +154,14 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) return true; } -int64_t GetVirtualTransactionSize(int64_t nCost) +unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; + +int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost) { - return (nCost + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; + return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; } -int64_t GetVirtualTransactionSize(const CTransaction& tx) +int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost) { - return GetVirtualTransactionSize(GetTransactionCost(tx)); + return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost); } diff --git a/src/policy/policy.h b/src/policy/policy.h index fefb562ff..6bf5ca0ee 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -14,21 +14,22 @@ class CCoinsViewCache; -/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/ +/** Default for -blockmaxsize, which controls the maximum size of block 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 = 0; -/** Default for -blockmaxcost, which control the range of block costs the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_COST = 3000000; -/** The maximum size for transactions we're willing to relay/mine */ -static const unsigned int MAX_STANDARD_TX_COST = 400000; +/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ +static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000; +/** The maximum weight for transactions we're willing to relay/mine */ +static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000; /** 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_COST = MAX_BLOCK_SIGOPS_COST/5; /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300; +/** Default for -bytespersigop */ +static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; /** * Standard script verification flags that standard transactions will comply * with. However scripts violating these flags may still be present in valid @@ -54,12 +55,12 @@ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_ static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false); /** * Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, std::string& reason); +bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled = false); /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending @@ -67,8 +68,10 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); -/** Compute the virtual transaction size (cost reinterpreted as bytes). */ -int64_t GetVirtualTransactionSize(int64_t nCost); -int64_t GetVirtualTransactionSize(const CTransaction& tx); +extern unsigned int nBytesPerSigOp; + +/** Compute the virtual transaction size (weight reinterpreted as bytes). */ +int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost); +int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0); #endif // BITCOIN_POLICY_POLICY_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index df900388f..0e6ab4dd7 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -32,11 +32,11 @@ std::string CBlock::ToString() const return s.str(); } -int64_t GetBlockCost(const CBlock& block) +int64_t GetBlockWeight(const CBlock& block) { - // This implements the cost = (stripped_size * 4) + witness_size formula, + // This implements the weight = (stripped_size * 4) + witness_size formula, // using only serialization with and without witness data. As witness_size // is equal to total_size - stripped_size, this formula is identical to: - // cost = (stripped_size * 3) + total_size. + // weight = (stripped_size * 3) + total_size. return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); } diff --git a/src/primitives/block.h b/src/primitives/block.h index e2a309e63..72dfed985 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -154,7 +154,7 @@ struct CBlockLocator } }; -/** Compute the consensus-critical block cost (see BIP 141). */ -int64_t GetBlockCost(const CBlock& tx); +/** Compute the consensus-critical block weight (see BIP 141). */ +int64_t GetBlockWeight(const CBlock& tx); #endif // BITCOIN_PRIMITIVES_BLOCK_H diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 7f10409c0..8d6380564 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -121,7 +121,7 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const // Providing any more cleanup incentive than making additional inputs free would // risk encouraging people to create junk outputs to redeem later. if (nTxSize == 0) - nTxSize = (GetTransactionCost(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; + nTxSize = (GetTransactionWeight(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it) { unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size()); @@ -149,7 +149,7 @@ std::string CTransaction::ToString() const return str; } -int64_t GetTransactionCost(const CTransaction& tx) +int64_t GetTransactionWeight(const CTransaction& tx) { return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index e87ad90f0..5689d15bf 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -213,7 +213,7 @@ public: std::string ToString() const; }; -class CTxinWitness +class CTxInWitness { public: CScriptWitness scriptWitness; @@ -228,14 +228,14 @@ public: bool IsNull() const { return scriptWitness.IsNull(); } - CTxinWitness() { } + CTxInWitness() { } }; class CTxWitness { public: /** In case vtxinwit is missing, all entries are treated as if they were empty CTxInWitnesses */ - std::vector<CTxinWitness> vtxinwit; + std::vector<CTxInWitness> vtxinwit; ADD_SERIALIZE_METHODS; @@ -290,6 +290,8 @@ struct CMutableTransaction; */ template<typename Stream, typename Operation, typename TxType> inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, int nType, int nVersion) { + const bool fAllowWitness = !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS); + READWRITE(*const_cast<int32_t*>(&tx.nVersion)); unsigned char flags = 0; if (ser_action.ForRead()) { @@ -298,7 +300,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in const_cast<CTxWitness*>(&tx.wit)->SetNull(); /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */ READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin)); - if (tx.vin.size() == 0 && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if (tx.vin.size() == 0 && fAllowWitness) { /* We read a dummy or an empty vin. */ READWRITE(flags); if (flags != 0) { @@ -309,7 +311,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in /* We read a non-empty vin. Assume a normal vout follows. */ READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout)); } - if ((flags & 1) && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if ((flags & 1) && fAllowWitness) { /* The witness flag is present, and we support witnesses. */ flags ^= 1; const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size()); @@ -322,7 +324,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in } else { // Consistency check assert(tx.wit.vtxinwit.size() <= tx.vin.size()); - if (!(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if (fAllowWitness) { /* Check whether witnesses need to be serialized. */ if (!tx.wit.IsNull()) { flags |= 1; @@ -459,7 +461,7 @@ struct CMutableTransaction uint256 GetHash() const; }; -/** Compute the cost of a transaction, as defined by BIP 141 */ -int64_t GetTransactionCost(const CTransaction &tx); +/** Compute the weight of a transaction, as defined by BIP 141 */ +int64_t GetTransactionWeight(const CTransaction &tx); #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/protocol.h b/src/protocol.h index 15f27e2d2..015215b2a 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -10,7 +10,7 @@ #ifndef BITCOIN_PROTOCOL_H #define BITCOIN_PROTOCOL_H -#include "netbase.h" +#include "netaddress.h" #include "serialize.h" #include "uint256.h" #include "version.h" diff --git a/src/pubkey.h b/src/pubkey.h index db5444ea9..aebfdbc82 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -13,7 +13,7 @@ #include <stdexcept> #include <vector> -/** +/** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; @@ -156,7 +156,7 @@ public: /* * Check syntactic correctness. - * + * * Note that this is consensus critical as CheckSig() calls it! */ bool IsValid() const @@ -203,8 +203,11 @@ struct CExtPubKey { friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - a.chaincode == b.chaincode && a.pubkey == b.pubkey; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.pubkey == b.pubkey; } void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc index 54d36ac01..8dd07c3d4 100644 --- a/src/qt/bitcoin_locale.qrc +++ b/src/qt/bitcoin_locale.qrc @@ -5,6 +5,7 @@ <file alias="ar">locale/bitcoin_ar.qm</file> <file alias="be_BY">locale/bitcoin_be_BY.qm</file> <file alias="bg">locale/bitcoin_bg.qm</file> + <file alias="bg_BG">locale/bitcoin_bg_BG.qm</file> <file alias="ca_ES">locale/bitcoin_ca_ES.qm</file> <file alias="ca">locale/bitcoin_ca.qm</file> <file alias="ca@valencia">locale/[email protected]</file> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 9042e3b56..2afefb733 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -902,17 +902,22 @@ void BitcoinGUI::closeEvent(QCloseEvent *event) #ifndef Q_OS_MAC // Ignored on Mac if(clientModel && clientModel->getOptionsModel()) { - if(!clientModel->getOptionsModel()->getMinimizeToTray() && - !clientModel->getOptionsModel()->getMinimizeOnClose()) + if(!clientModel->getOptionsModel()->getMinimizeOnClose()) { // close rpcConsole in case it was open to make some space for the shutdown window rpcConsole->close(); QApplication::quit(); } + else + { + QMainWindow::showMinimized(); + event->ignore(); + } } -#endif +#else QMainWindow::closeEvent(event); +#endif } void BitcoinGUI::showEvent(QShowEvent *event) diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 7cf32cd34..bca5b7282 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -186,12 +186,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is " "included in share/rpcuser. This option can be specified multiple times"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"WARNING: abnormally high number of blocks generated, %d blocks received in " -"the last %d hours (%d expected)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"WARNING: check your network connection, %d blocks received in the last %d " -"hours (%d expected)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: The network does not appear to fully agree! Some miners appear to " "be experiencing issues."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -317,9 +311,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of d QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: %u)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block cost (default: %d)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum BIP141 block cost (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: %d)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "Show all debugging options (usage: --help -help-debug)"), QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 108500654..14661b857 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -179,11 +179,6 @@ bool ClientModel::isReleaseVersion() const return CLIENT_VERSION_IS_RELEASE; } -QString ClientModel::clientName() const -{ - return QString::fromStdString(CLIENT_NAME); -} - QString ClientModel::formatClientStartupTime() const { return QDateTime::fromTime_t(nClientStartupTime).toString(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 439680431..99fd574b9 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -73,7 +73,6 @@ public: QString formatFullVersion() const; QString formatSubVersion() const; bool isReleaseVersion() const; - QString clientName() const; QString formatClientStartupTime() const; QString dataDir() const; diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index c17efcf1b..9dc641979 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -41,36 +41,13 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Client name</string> - </property> - </widget> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QLabel" name="clientName"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>N/A</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item row="2" column="0"> <widget class="QLabel" name="label_6"> <property name="text"> <string>Client version</string> </property> </widget> </item> - <item row="2" column="1" colspan="2"> + <item row="1" column="1" colspan="2"> <widget class="QLabel" name="clientVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -86,7 +63,7 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="labelClientUserAgent"> <property name="text"> <string>User Agent</string> @@ -96,7 +73,7 @@ </property> </widget> </item> - <item row="3" column="1" colspan="2"> + <item row="2" column="1" colspan="2"> <widget class="QLabel" name="clientUserAgent"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -112,7 +89,7 @@ </property> </widget> </item> - <item row="4" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_berkeleyDBVersion"> <property name="text"> <string>Using BerkeleyDB version</string> @@ -122,7 +99,7 @@ </property> </widget> </item> - <item row="4" column="1" colspan="2"> + <item row="3" column="1" colspan="2"> <widget class="QLabel" name="berkeleyDBVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -138,14 +115,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="4" column="0"> <widget class="QLabel" name="label_12"> <property name="text"> <string>Datadir</string> </property> </widget> </item> - <item row="5" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="QLabel" name="dataDir"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -164,14 +141,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="5" column="0"> <widget class="QLabel" name="label_13"> <property name="text"> <string>Startup time</string> </property> </widget> </item> - <item row="6" column="1" colspan="2"> + <item row="5" column="1" colspan="2"> <widget class="QLabel" name="startupTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -187,7 +164,7 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="labelNetwork"> <property name="font"> <font> @@ -200,14 +177,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Name</string> </property> </widget> </item> - <item row="8" column="1" colspan="2"> + <item row="7" column="1" colspan="2"> <widget class="QLabel" name="networkName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -223,14 +200,14 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> <string>Number of connections</string> </property> </widget> </item> - <item row="9" column="1" colspan="2"> + <item row="8" column="1" colspan="2"> <widget class="QLabel" name="numberOfConnections"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -246,7 +223,7 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_10"> <property name="font"> <font> @@ -259,14 +236,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Current number of blocks</string> </property> </widget> </item> - <item row="11" column="1" colspan="2"> + <item row="10" column="1" colspan="2"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -282,14 +259,14 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="labelLastBlockTime"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="12" column="1" colspan="2"> + <item row="11" column="1" colspan="2"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -305,7 +282,7 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="labelMempoolTitle"> <property name="font"> <font> @@ -318,14 +295,14 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="labelNumberOfTransactions"> <property name="text"> <string>Current number of transactions</string> </property> </widget> </item> - <item row="14" column="1"> + <item row="13" column="1"> <widget class="QLabel" name="mempoolNumberTxs"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -341,14 +318,14 @@ </property> </widget> </item> - <item row="15" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="labelMemoryUsage"> <property name="text"> <string>Memory usage</string> </property> </widget> </item> - <item row="15" column="1"> + <item row="14" column="1"> <widget class="QLabel" name="mempoolSize"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -364,7 +341,7 @@ </property> </widget> </item> - <item row="13" column="2" rowspan="3"> + <item row="12" column="2" rowspan="3"> <layout class="QVBoxLayout" name="verticalLayoutDebugButton"> <property name="spacing"> <number>3</number> @@ -404,7 +381,7 @@ </item> </layout> </item> - <item row="16" column="0"> + <item row="15" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 4327de9b0..947a4c682 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -107,6 +107,23 @@ QFont fixedPitchFont() #endif } +// Just some dummy data to generate an convincing random-looking (but consistent) address +static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47}; + +// Generate a dummy address with invalid CRC, starting with the network prefix. +static std::string DummyAddress(const CChainParams ¶ms) +{ + std::vector<unsigned char> sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); + sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata)); + for(int i=0; i<256; ++i) { // Try every trailing byte + std::string s = EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)); + if (!CBitcoinAddress(s).IsValid()) + return s; + sourcedata[sourcedata.size()-1] += 1; + } + return ""; +} + void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) { parent->setFocusProxy(widget); @@ -115,7 +132,8 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) #if QT_VERSION >= 0x040700 // We don't want translators to use own addresses in translations // and this is the only place, where this address is supplied. - widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg("1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L")); + widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg( + QString::fromStdString(DummyAddress(Params())))); #endif widget->setValidator(new BitcoinAddressEntryValidator(parent)); widget->setCheckValidator(new BitcoinAddressCheckValidator(parent)); diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts index 7c2d294c7..97ada8dd5 100644 --- a/src/qt/locale/bitcoin_af.ts +++ b/src/qt/locale/bitcoin_af.ts @@ -257,10 +257,6 @@ <translation>Bitcoin Kern</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>WAARSKUWING: toets die status van u netwerk, %d blokke ontvang in die laaste %d ure (%d verwag)</translation> - </message> - <message> <source>Do not keep transactions in the mempool longer than <n> hours (default: %u)</source> <translation>Moenie transaksies vir langer as <n> ure in die geheuepoel hou nie (verstek: %u)</translation> </message> diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 78fd07443..af62207df 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -111,10 +111,6 @@ <translation>الخروج من التطبيق</translation> </message> <message> - <source>&About %1</source> - <translation>&عن %1</translation> - </message> - <message> <source>Show information about %1</source> <translation>أظهر المعلومات حولة %1</translation> </message> @@ -307,6 +303,20 @@ <translation>اللحاق بالركب ...</translation> </message> <message> + <source>Date: %1 +</source> + <translation>التاريخ %1 + + +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>علامه: %1 +</translation> + </message> + <message> <source>Sent transaction</source> <translation>المعاملات المرسلة</translation> </message> @@ -326,10 +336,18 @@ <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation>اختيار العمله</translation> + </message> + <message> <source>Quantity:</source> <translation>الكمية :</translation> </message> <message> + <source>Bytes:</source> + <translation>بايت</translation> + </message> + <message> <source>Amount:</source> <translation>القيمة :</translation> </message> @@ -342,6 +360,10 @@ <translation>رسوم :</translation> </message> <message> + <source>Dust:</source> + <translation>غبار:</translation> + </message> + <message> <source>After Fee:</source> <translation>بعد الرسوم :</translation> </message> @@ -350,8 +372,20 @@ <translation>تعديل :</translation> </message> <message> + <source>(un)select all</source> + <translation>عدم اختيار الجميع</translation> + </message> + <message> + <source>Tree mode</source> + <translation>صيغة الشجرة</translation> + </message> + <message> + <source>List mode</source> + <translation>صيغة القائمة</translation> + </message> + <message> <source>Amount</source> - <translation>المبلغ</translation> + <translation>مبلغ</translation> </message> <message> <source>Received with label</source> @@ -363,11 +397,11 @@ </message> <message> <source>Date</source> - <translation>التاريخ</translation> + <translation>تاريخ</translation> </message> <message> <source>Confirmations</source> - <translation>تأكيد</translation> + <translation>تأكيدات</translation> </message> <message> <source>Confirmed</source> @@ -389,6 +423,14 @@ <translation>&وصف</translation> </message> <message> + <source>The label associated with this address list entry</source> + <translation>الملصق المرتبط بقائمة العناوين المدخلة</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>العنوان المرتبط بقائمة العناوين المدخلة. و التي يمكن تعديلها فقط بواسطة ارسال العناوين</translation> + </message> + <message> <source>&Address</source> <translation>&العنوان</translation> </message> @@ -443,6 +485,14 @@ <translation>اختر دليل البيانات عند بدء التشغير (افتراضي: %u)</translation> </message> <message> + <source>Set language, for example "de_DE" (default: system locale)</source> + <translation>أضع لغة, على سبيل المثال " de_DE " (افتراضي:- مكان النظام)</translation> + </message> + <message> + <source>Start minimized</source> + <translation>الدخول مصغر</translation> + </message> + <message> <source>Set SSL root certificates for payment request (default: -system-)</source> <translation>أضع شهادة بروتوكول الشبقة الأمنية لطلب المدفوع (افتراضي: -نظام-)</translation> </message> @@ -450,7 +500,11 @@ <source>Show splash screen on startup (default: %u)</source> <translation>أظهر شاشة البداية عند بدء التشغيل (افتراضي: %u)</translation> </message> - </context> + <message> + <source>Reset all settings changed in the GUI</source> + <translation>اعد تعديل جميع النظم المتغيرة في GUI</translation> + </message> +</context> <context> <name>Intro</name> <message> @@ -473,6 +527,14 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open URI</source> + <translation>افتح URL</translation> + </message> + <message> + <source>Open payment request from URI or file</source> + <translation>حدد طلب الدفع من ملف او URI</translation> + </message> + <message> <source>Select payment request file</source> <translation>حدد ملف طلب الدفع</translation> </message> @@ -528,10 +590,18 @@ <translation>منفذ البروكسي (مثلا 9050)</translation> </message> <message> + <source>Used for reaching peers via:</source> + <translation>مستخدم للاتصال بالاصدقاء من خلال:</translation> + </message> + <message> <source>&Window</source> <translation>نافذه</translation> </message> <message> + <source>Hide tray icon</source> + <translation>اخفاء لوحة الايقون</translation> + </message> + <message> <source>&Display</source> <translation>&عرض</translation> </message> @@ -616,10 +686,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>اسم العميل</translation> - </message> - <message> <source>N/A</source> <translation>غير معروف</translation> </message> @@ -664,6 +730,10 @@ <translation>تم الإرسال</translation> </message> <message> + <source>&Peers</source> + <translation>&اصدقاء</translation> + </message> + <message> <source>Direction</source> <translation>جهة</translation> </message> @@ -704,6 +774,22 @@ <translation>خارج:</translation> </message> <message> + <source>1 &hour</source> + <translation>1 &ساعة</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 & يوم</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 & اسبوع</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 & سنة</translation> + </message> + <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> <translation>استخدم اسهم الاعلى و الاسفل للتنقل بين السجلات و <b>Ctrl-L</b> لمسح الشاشة</translation> </message> @@ -724,6 +810,18 @@ <translation>%1 قيقا بايت</translation> </message> <message> + <source>never</source> + <translation>ابدا</translation> + </message> + <message> + <source>Inbound</source> + <translation>داخل</translation> + </message> + <message> + <source>Outbound</source> + <translation>خارجي</translation> + </message> + <message> <source>Yes</source> <translation>نعم</translation> </message> @@ -809,6 +907,10 @@ <translation>الكمية :</translation> </message> <message> + <source>Bytes:</source> + <translation>بايت</translation> + </message> + <message> <source>Amount:</source> <translation>القيمة :</translation> </message> @@ -837,6 +939,14 @@ <translation>إخفاء</translation> </message> <message> + <source>normal</source> + <translation>طبيعي</translation> + </message> + <message> + <source>fast</source> + <translation>سريع</translation> + </message> + <message> <source>Send to multiple recipients at once</source> <translation>إرسال إلى عدة مستلمين في وقت واحد</translation> </message> @@ -849,6 +959,10 @@ <translation>مسح كل حقول النموذج المطلوبة</translation> </message> <message> + <source>Dust:</source> + <translation>غبار</translation> + </message> + <message> <source>Clear &All</source> <translation>مسح الكل</translation> </message> @@ -880,6 +994,18 @@ <translation>&وصف :</translation> </message> <message> + <source>Choose previously used address</source> + <translation>اختر عنوانا مستخدم سابقا</translation> + </message> + <message> + <source>This is a normal payment.</source> + <translation>هذا دفع اعتيادي</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>عنوان البت كوين المرسل اليه الدفع</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> @@ -892,6 +1018,10 @@ <translation>Alt+P</translation> </message> <message> + <source>Remove this entry</source> + <translation>ازل هذه المداخله</translation> + </message> + <message> <source>Message:</source> <translation>الرسائل</translation> </message> @@ -914,6 +1044,10 @@ <translation>&توقيع الرسالة</translation> </message> <message> + <source>Choose previously used address</source> + <translation>اختر عنوانا مستخدم سابقا</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 3bb881318..acb60cf41 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -64,6 +64,10 @@ <context> <name>BanTableModel</name> <message> + <source>IP/Netmask</source> + <translation>IP/Netmask</translation> + </message> + <message> <source>Banned Until</source> <translation>Със забранен достъп до</translation> </message> @@ -107,6 +111,14 @@ <translation>Изход от приложението</translation> </message> <message> + <source>&About %1</source> + <translation>Относно %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Покажи информация относно %1</translation> + </message> + <message> <source>About &Qt</source> <translation>За &Qt</translation> </message> @@ -119,6 +131,10 @@ <translation>&Опции...</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation>Промени настройки за %1</translation> + </message> + <message> <source>&Encrypt Wallet...</source> <translation>&Шифриране на портфейла...</translation> </message> @@ -143,6 +159,10 @@ <translation>Отвори &URI...</translation> </message> <message> + <source>Reindexing blocks on disk...</source> + <translation>Повторно индексиране на блоковете на диска...</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>Изпращане към Биткоин адрес</translation> </message> @@ -238,14 +258,46 @@ <source>&Command-line options</source> <translation>&Налични команди</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n активна връзка към Биткойн мрежата</numerusform><numerusform>%n активни връзки към Биткойн мрежата</numerusform></translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Индексиране на блокове на диска...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Обработване на блокове на диска...</translation> + </message> <message> <source>No block source available...</source> <translation>Липсва източник на блоковете...</translation> </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Преработен %n блок от историята с транзакции.</numerusform><numerusform>Преработени %n блокове от историята с транзакции.</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n час</numerusform><numerusform>%n часа</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n ден</numerusform><numerusform>%n дни</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n седмица</numerusform><numerusform>%n седмици</numerusform></translation> + </message> <message> <source>%1 and %2</source> <translation>%1 и %2</translation> </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n година</numerusform><numerusform>%n години</numerusform></translation> + </message> <message> <source>%1 behind</source> <translation>%1 зад</translation> @@ -275,6 +327,14 @@ <translation>Синхронизиран</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Покажи %1 помощно съобщение за да получиш лист с възможни Биткойн команди</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 клиент</translation> + </message> + <message> <source>Catching up...</source> <translation>Зарежда блокове...</translation> </message> @@ -415,6 +475,14 @@ <translation>&Име</translation> </message> <message> + <source>The label associated with this address list entry</source> + <translation>Етикетът свързан с това въведение в листа с адреси</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>Адресът свързан с това въведение в листа с адреси. Това може да бъде променено само за адреси за изпращане.</translation> + </message> + <message> <source>&Address</source> <translation>&Адрес</translation> </message> @@ -453,6 +521,10 @@ <translation>(%1-битов)</translation> </message> <message> + <source>About %1</source> + <translation>Относно %1</translation> + </message> + <message> <source>Command-line options</source> <translation>Списък с команди</translation> </message> @@ -464,7 +536,35 @@ <source>command-line options</source> <translation>Списък с налични команди</translation> </message> - </context> + <message> + <source>UI Options:</source> + <translation>Опции на интерфейс:</translation> + </message> + <message> + <source>Choose data directory on startup (default: %u)</source> + <translation>Избери директория за данни при стартирване (по подразбиране: %u)</translation> + </message> + <message> + <source>Set language, for example "de_DE" (default: system locale)</source> + <translation>Избери език, примерно "de_DE" (по подразбиране: system locale)</translation> + </message> + <message> + <source>Start minimized</source> + <translation>Стартирай минимизиран</translation> + </message> + <message> + <source>Set SSL root certificates for payment request (default: -system-)</source> + <translation>Задай SSL root сертификат за молба за изплащане (по подразбиране: -system-)</translation> + </message> + <message> + <source>Show splash screen on startup (default: %u)</source> + <translation>Покажи splash екран при стартирване (по подразбиране %u)</translation> + </message> + <message> + <source>Reset all settings changed in the GUI</source> + <translation>Нулиране на всички настройки променени в GUI</translation> + </message> +</context> <context> <name>Intro</name> <message> @@ -472,6 +572,10 @@ <translation>Добре дошли</translation> </message> <message> + <source>Welcome to %1.</source> + <translation>Добре дошли в %1.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Използване на директория по подразбиране</translation> </message> @@ -483,13 +587,29 @@ <source>Error</source> <translation>Грешка</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB свободно пространство на разположение</numerusform><numerusform>%n GB свободно пространство на разположение</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(%n GB е нужен)</numerusform><numerusform>(%n GB са нужни)</numerusform></translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> <source>Open URI</source> <translation>Отваряне на URI</translation> </message> + <message> + <source>Open payment request from URI or file</source> + <translation>Отвори молба за изплащане от URI или файл</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -762,10 +882,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Име на клиента</translation> - </message> - <message> <source>N/A</source> <translation>Несъществуващ</translation> </message> diff --git a/src/qt/locale/bitcoin_bg_BG.ts b/src/qt/locale/bitcoin_bg_BG.ts new file mode 100644 index 000000000..4bddb5ff4 --- /dev/null +++ b/src/qt/locale/bitcoin_bg_BG.ts @@ -0,0 +1,236 @@ +<TS language="bg_BG" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Клик с десен бутон на мишката за промяна на адрес или етикет</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Създай нов адрес</translation> + </message> + <message> + <source>&New</source> + <translation>Нов</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Копирай текущо избрания адрес към клипборда</translation> + </message> + <message> + <source>&Copy</source> + <translation>Копирай</translation> + </message> + <message> + <source>C&lose</source> + <translation>Затвори</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Изтрий текущо избрания адрес от листа</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Изнеси данните в избрания раздел към файл</translation> + </message> + <message> + <source>&Export</source> + <translation>Изнеси</translation> + </message> + <message> + <source>&Delete</source> + <translation>Изтрий</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>Диалог за пропуск</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Въведи парола</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Нова парола</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Повтори парола</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Мрежова маска</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Блокиран до</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>Подпиши съобщение...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Синхронизиране с мрежата...</translation> + </message> + <message> + <source>&Overview</source> + <translation>Преглед</translation> + </message> + <message> + <source>Node</source> + <translation>Възел</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Покажи общ преглед на портфейла</translation> + </message> + <message> + <source>&Transactions</source> + <translation>Транзакции</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Разгледай история на транзакциите</translation> + </message> + <message> + <source>E&xit</source> + <translation>Изход</translation> + </message> + <message> + <source>Quit application</source> + <translation>Излез от приложението</translation> + </message> + <message> + <source>&About %1</source> + <translation>За %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Покажи информация за %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>Относно Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Покажи информация отностно Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>Настройки...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Промени конфигурации за %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>Криптирай портфейл</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>Направи резервно копие на портфейла...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>Промени паролата...</translation> + </message> + <message> + <source>&Sending addresses...</source> + <translation>Адреси за пращане...</translation> + </message> + <message> + <source>&Receiving addresses...</source> + <translation>Адреси за получаване...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Отвори URI</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>Повторно индексиране на блоковете на диска...</translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + </context> +<context> + <name>EditAddressDialog</name> + </context> +<context> + <name>FreespaceChecker</name> + </context> +<context> + <name>HelpMessageDialog</name> + </context> +<context> + <name>Intro</name> + </context> +<context> + <name>OpenURIDialog</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + </context> +<context> + <name>RPCConsole</name> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + </context> +<context> + <name>SendCoinsDialog</name> + </context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</name> + </context> +<context> + <name>SplashScreen</name> + </context> +<context> + <name>TrafficGraphWidget</name> + </context> +<context> + <name>TransactionDescDialog</name> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>bitcoin-core</name> + <message> + <source>Bitcoin Core</source> + <translation>Биткойн ядро</translation> + </message> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 3eb384868..ed259c4d0 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -926,10 +926,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nom del client</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1739,14 +1735,6 @@ <translation>Aquesta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: s'ha generat un nombre anòmalament alt de blocs, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes.</translation> </message> diff --git a/src/qt/locale/[email protected] b/src/qt/locale/[email protected] index 1fdf0249a..df0f750a6 100644 --- a/src/qt/locale/[email protected] +++ b/src/qt/locale/[email protected] @@ -870,10 +870,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nom del client</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1571,14 +1567,6 @@ <translation>Esta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: s'ha generat un nombre anòmalament alt de blocs, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Avís: la xarxa no pareix que hi estiga plenament d'acord. Alguns miners pareix que estan experimentant problemes.</translation> </message> diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 30004e10e..f985a6928 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -926,10 +926,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nom del client</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1735,14 +1731,6 @@ <translation>Aquesta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: s'ha generat un nombre anòmalament alt de blocs, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVÍS: comproveu la vostra connexió a la xarxa, %d blocs rebuts en les darreres %d hores (se n'esperaven %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes.</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index d76839723..2dfa295ce 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -918,10 +918,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Název klienta</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1715,14 +1711,6 @@ <translation>Použít UPnP k namapování naslouchacího portu (výchozí: 1, pokud naslouchá a nepoužívá -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>UPOZORNĚNÍ: vygenerováno nezvykle mnoho bloků – přijato %d bloků jen za posledních %d hodin (očekáváno %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>UPOZORNĚNÍ: zkontroluj své spojení do sítě – bylo přijato %d bloků za posledních %d hodin (očekáváno %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Upozornění: Síť podle všeho není v konzistentním stavu. Někteří těžaři jsou zřejmě v potížích.</translation> </message> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 91903088c..d298c81bd 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Klientnavn</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1879,16 +1875,12 @@ <translation>Dette er en foreløbig testudgivelse - brug på eget ansvar - brug ikke til udvinding eller handelsprogrammer</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Brug UPnP for at konfigurere den lyttende port (standard: 1 under lytning og ingen -proxy)</translation> - </message> - <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVARSEL: unormalt mange blokke er genereret; %d blokke er modtaget i løbet af de seneste %d timer (%d forventet)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Kan ikke spole databasen tilbage til en tilstand inden en splitning. Du er nødt til at downloade blokkæden igen</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVARSEL: tjek din netværksforbindelse; %d blokke er modtaget i løbet af de seneste %d timer (%d forventet)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Brug UPnP for at konfigurere den lyttende port (standard: 1 under lytning og ingen -proxy)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2099,10 +2091,18 @@ <translation>Genopbyg kædetilstand ud fra de aktuelt indekserede blokke</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Spoler blokke tilbage…</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Sæt cache-størrelse for database i megabytes (%d til %d; standard: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Sæt maksimal blokudgift (standard: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Sæt maksimum blokstørrelse i byte (standard: %d)</translation> </message> diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 639bc3cf2..2708324d1 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -782,6 +782,14 @@ <translation>&Programmfenster</translation> </message> <message> + <source>&Hide the icon from the system tray.</source> + <translation>&Das Icon im System Tray verstecken.</translation> + </message> + <message> + <source>Hide tray icon</source> + <translation>Tray Icon verstecken</translation> + </message> + <message> <source>Show only a tray icon after minimizing the window.</source> <translation>Nur ein Symbol im Infobereich anzeigen, nachdem das Programmfenster minimiert wurde.</translation> </message> @@ -982,10 +990,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Clientname</translation> - </message> - <message> <source>N/A</source> <translation>k.A.</translation> </message> @@ -1010,6 +1014,10 @@ <translation>Verwendete BerkeleyDB-Version</translation> </message> <message> + <source>Datadir</source> + <translation>Datenverzeichnis</translation> + </message> + <message> <source>Startup time</source> <translation>Startzeit</translation> </message> @@ -1094,6 +1102,10 @@ <translation>User-Agent</translation> </message> <message> + <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <translation>Öffnet die %1-Debugprotokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern.</translation> + </message> + <message> <source>Decrease font size</source> <translation>Schrift verkleinern</translation> </message> @@ -1787,6 +1799,10 @@ <translation>An die angegebene Adresse binden und immer abhören. Für IPv6 "[Host]:Port"-Notation verwenden</translation> </message> <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde %s bereits gestartet.</translation> + </message> + <message> <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source> <translation>Alle Wallet-Transaktionen löschen und nur diese Teilbereiche der Blockkette durch -rescan beim Starten wiederherstellen</translation> </message> @@ -1803,6 +1819,14 @@ <translation>Leite Transaktionen von Peers auf der Positivliste auf jeden Fall weiter, auch wenn sie die lokale Weiterleitungsregeln verletzen (Standardeinstellung: %d)</translation> </message> <message> + <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <translation>Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation> + </message> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation> + </message> + <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> <translation>Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (%u bis %d, 0 = automatisch, <0 = so viele Kerne frei lassen, Standard: %d)</translation> </message> @@ -1819,14 +1843,6 @@ <translation>UPnP verwenden, um eine Portweiterleitung einzurichten (Standard: 1, wenn abgehört wird und -proxy nicht gesetzt ist)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>Warnung: Es wurde eine ungewöhnlich hohe Anzahl Blöcke erzeugt, %d Blöcke wurden in den letzten %d Stunden empfangen (%d wurden erwartet).</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>Warnung: Überprüpfen Sie ihre Netzwerkverbindung, %d Blöcke wurden in den letzten %d Stunden empfangen (%d wurden erwartet).</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Warnung: Das Netzwerk scheint nicht vollständig übereinzustimmen! Einige Miner scheinen Probleme zu haben.</translation> </message> @@ -1839,6 +1855,14 @@ <translation>Gegenstellen die sich von der angegebenen Netzmaske oder IP-Adresse aus verbinden immer zulassen. Kann mehrmals angegeben werden.</translation> </message> <message> + <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source> + <translation>Sie müssen die Datenbank mit Hilfe von -reindex-chainstate neu aufbauen, um -txindex zu verändern</translation> + </message> + <message> + <source>%s corrupt, salvage failed</source> + <translation>%s beschädigt, Datenrettung fehlgeschlagen</translation> + </message> + <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool muss mindestens %d MB betragen</translation> </message> @@ -1851,6 +1875,10 @@ <translation>Hänge ein Kommentar zur User Agent-Zeichenkette an</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet on startup</source> + <translation>Es wird versucht, private Schlüssel beim Starten aus einem beschädigtem Wallet wiederherzustellen</translation> + </message> + <message> <source>Block creation options:</source> <translation>Blockerzeugungsoptionen:</translation> </message> @@ -1915,6 +1943,14 @@ <translation>Fehler beim Laden von %s</translation> </message> <message> + <source>Error loading %s: Wallet corrupted</source> + <translation>Fehler beim Laden von %s: Das Wallet ist beschädigt</translation> + </message> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Fehler beim Laden von %s: Das Wallet benötigt eine neuere Version von %s</translation> + </message> + <message> <source>Error loading block database</source> <translation>Fehler beim Laden der Blockdatenbank</translation> </message> @@ -1971,6 +2007,10 @@ <translation>Nur zu Knoten des Netzwerktyps <net> verbinden (ipv4, ipv6 oder onion)</translation> </message> <message> + <source>Print this help message and exit</source> + <translation>Drucke diese Hilfemeldung und beende</translation> + </message> + <message> <source>Print version and exit</source> <translation>Gibt die Versionsnummer aus und beendet das Programm</translation> </message> diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 59779692d..2814e4f6e 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -835,10 +835,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Όνομα Πελάτη</translation> - </message> - <message> <source>N/A</source> <translation>Μη διαθέσιμο</translation> </message> diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 9723ffa39..79c3e87b2 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -1218,12 +1218,12 @@ <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+118"/> + <location filename="../guiutil.cpp" line="+135"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+763"/> + <location line="+764"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -1262,13 +1262,7 @@ <context> <name>RPCConsole</name> <message> - <location filename="../forms/debugwindow.ui" line="+46"/> - <source>Client name</source> - <translation>Client name</translation> - </message> - <message> - <location line="+10"/> - <location line="+23"/> + <location filename="../forms/debugwindow.ui" line="+56"/> <location line="+26"/> <location line="+26"/> <location line="+23"/> @@ -1305,7 +1299,7 @@ <translation>Client version</translation> </message> <message> - <location line="-45"/> + <location line="-22"/> <source>&Information</source> <translation>&Information</translation> </message> @@ -1320,7 +1314,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+79"/> + <location line="+56"/> <source>Using BerkeleyDB version</source> <translation type="unfinished"></translation> </message> @@ -1399,7 +1393,7 @@ <message> <location line="+60"/> <location filename="../rpcconsole.cpp" line="+295"/> - <location line="+635"/> + <location line="+634"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> @@ -1550,7 +1544,7 @@ <translation>Clear console</translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-204"/> + <location filename="../rpcconsole.cpp" line="-203"/> <source>&Disconnect Node</source> <translation type="unfinished"></translation> </message> @@ -1588,7 +1582,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+118"/> + <location line="+117"/> <source>Welcome to the %1 RPC console.</source> <translation type="unfinished"></translation> </message> @@ -2232,32 +2226,32 @@ <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+298"/> + <location filename="../bitcoinstrings.cpp" line="+292"/> <source>Options:</source> <translation>Options:</translation> </message> <message> - <location line="+31"/> + <location line="+30"/> <source>Specify data directory</source> <translation>Specify data directory</translation> </message> <message> - <location line="-90"/> + <location line="-89"/> <source>Connect to a node to retrieve peer addresses, and disconnect</source> <translation>Connect to a node to retrieve peer addresses, and disconnect</translation> </message> <message> - <location line="+93"/> + <location line="+92"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> <message> - <location line="-109"/> + <location line="-108"/> <source>Accept command line and JSON-RPC commands</source> <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="-134"/> + <location line="-128"/> <source>If <category> is not supplied or if <category> = 1, output all debugging information.</source> <translation type="unfinished"></translation> </message> @@ -2282,7 +2276,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+125"/> + <location line="+119"/> <source>Error: A fatal internal error occurred, see debug.log for details</source> <translation type="unfinished"></translation> </message> @@ -2302,17 +2296,17 @@ <translation>Run in the background as a daemon and accept commands</translation> </message> <message> - <location line="+31"/> + <location line="+30"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-122"/> + <location line="-121"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> <message> - <location line="-212"/> + <location line="-206"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -2423,16 +2417,6 @@ </message> <message> <location line="+12"/> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</translation> </message> @@ -2702,17 +2686,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Set maximum block cost (default: %d)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> + <location line="+3"/> <source>Set maximum block size in bytes (default: %d)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> + <location line="+9"/> <source>Specify wallet file (within data directory)</source> <translation>Specify wallet file (within data directory)</translation> </message> @@ -2782,7 +2761,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-328"/> + <location line="-321"/> <source>Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source> <translation type="unfinished"></translation> </message> @@ -2867,7 +2846,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+32"/> + <location line="+26"/> <source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source> <translation type="unfinished"></translation> </message> @@ -2962,7 +2941,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+3"/> + <source>Set maximum BIP141 block cost (default: %d)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show all debugging options (usage: --help -help-debug)</source> <translation type="unfinished"></translation> </message> @@ -3057,17 +3041,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-66"/> + <location line="-65"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-224"/> + <location line="-218"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+152"/> + <location line="+146"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> @@ -3077,7 +3061,7 @@ <translation>Loading addresses...</translation> </message> <message> - <location line="-270"/> + <location line="-264"/> <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source> <translation type="unfinished"></translation> </message> @@ -3157,7 +3141,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+7"/> <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source> <translation type="unfinished"></translation> </message> @@ -3243,11 +3227,6 @@ </message> <message> <location line="+3"/> - <source>Set minimum block size in bytes (default: %u)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> <source>Set the number of threads to service RPC calls (default: %d)</source> <translation type="unfinished"></translation> </message> @@ -3282,7 +3261,7 @@ <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-74"/> + <location line="-73"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts index 89653e7aa..1893aaca0 100644 --- a/src/qt/locale/bitcoin_en_GB.ts +++ b/src/qt/locale/bitcoin_en_GB.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Client name</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1879,16 +1875,12 @@ <translation>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</translation> - </message> - <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Unable to rewind the database to a pre-fork state. You will need to re-download the blockchain</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2099,10 +2091,18 @@ <translation>Rebuild chain state from the currently indexed blocks</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Set database cache size in megabytes (%d to %d, default: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Set maximum block cost (default: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Set maximum block size in bytes (default: %d)</translation> </message> diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 043b28abc..4471aeb72 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -742,10 +742,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nomo de kliento</translation> - </message> - <message> <source>N/A</source> <translation>neaplikebla</translation> </message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index fc430e86b..c67016637 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -990,10 +990,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nombre del cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/D</translation> </message> @@ -1878,16 +1874,12 @@ <translation>Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería.</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>No es posible reconstruir la base de datos a un estado anterior. Debe descargar de nuevo la cadena de bloques.</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVERTENCIA: anormalmente alto número de bloques generado, %d bloques recibidos en las últimas horas %d (%d espera)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVERTENCIA: comprueba tu conexión de red, %d bloques recibidos en las últimas %d horas (%d esperados)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2098,10 +2090,18 @@ <translation>Reconstruir el estado de la cadena a partir de los bloques indexados</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Verificando bloques...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Asignar tamaño de cache en megabytes (entre %d y %d; predeterminado: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Establecer tamaño máximo de bloque (por defecto: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Establecer tamaño máximo de bloque en bytes (predeterminado: %d)</translation> </message> diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index ff0fce611..188641d6e 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -458,10 +458,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nombre del cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index 3f4380840..ba963d2b8 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -640,10 +640,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nombre del cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/D</translation> </message> diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts index 26432190a..0a6ea1e1d 100644 --- a/src/qt/locale/bitcoin_es_MX.ts +++ b/src/qt/locale/bitcoin_es_MX.ts @@ -45,6 +45,10 @@ <context> <name>AskPassphraseDialog</name> <message> + <source>Passphrase Dialog</source> + <translation>Dialogo de contraseña</translation> + </message> + <message> <source>Enter passphrase</source> <translation>Ingrese la contraseña</translation> </message> @@ -59,6 +63,10 @@ </context> <context> <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Máscara de red</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -179,6 +187,10 @@ <translation>&Recibir</translation> </message> <message> + <source>&Show / Hide</source> + <translation>&Mostrar / Ocultar</translation> + </message> + <message> <source>&File</source> <translation>&Archivo</translation> </message> diff --git a/src/qt/locale/bitcoin_es_UY.ts b/src/qt/locale/bitcoin_es_UY.ts index 8d361620d..c565a63cd 100644 --- a/src/qt/locale/bitcoin_es_UY.ts +++ b/src/qt/locale/bitcoin_es_UY.ts @@ -108,7 +108,7 @@ </message> <message> <source>Send coins to a Bitcoin address</source> - <translation>Enviar monedas a una dirección BItCoin</translation> + <translation>Enviar monedas a una dirección Bitcoin</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index e861d4e47..0d659fd71 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -542,10 +542,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Kliendi nimi</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 5bebb3582..98543ded4 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -67,7 +67,11 @@ <source>IP/Netmask</source> <translation>آیپی/نتماسک</translation> </message> - </context> + <message> + <source>Banned Until</source> + <translation>مسدود شده تا</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -111,6 +115,10 @@ <translation>&حدود%1</translation> </message> <message> + <source>Show information about %1</source> + <translation>نمایش اطلاعات دربارهٔ %1</translation> + </message> + <message> <source>About &Qt</source> <translation>دربارهٔ &کیوت</translation> </message> @@ -510,6 +518,10 @@ </context> <context> <name>OpenURIDialog</name> + <message> + <source>Open URI</source> + <translation>بازکردن آدرس</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -526,6 +538,10 @@ <translation>پذیرش اتصالات از بیرون</translation> </message> <message> + <source>Allow incoming connections</source> + <translation>اجازه دادن به اتصالات دریافتی</translation> + </message> + <message> <source>Reset all client options to default.</source> <translation>بازنشانی تمام تنظیمات به پیشفرض.</translation> </message> @@ -691,7 +707,11 @@ </context> <context> <name>PeerTableModel</name> - </context> + <message> + <source>Ping Time</source> + <translation>زمان پینگ</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -730,10 +750,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>نام کلاینت</translation> - </message> - <message> <source>N/A</source> <translation>ناموجود</translation> </message> @@ -802,6 +818,14 @@ <translation>آخرین دریافتی</translation> </message> <message> + <source>Ping Time</source> + <translation>زمان پینگ</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>انتظار پینگ</translation> + </message> + <message> <source>Last block time</source> <translation>زمان آخرین بلوک</translation> </message> @@ -838,6 +862,22 @@ <translation>برای نمایش یک مرور کلی از دستورات ممکن، عبارت <b>help</b> را بنویسید.</translation> </message> <message> + <source>%1 B</source> + <translation>%1 بایت</translation> + </message> + <message> + <source>%1 KB</source> + <translation>%1 کیلوبایت</translation> + </message> + <message> + <source>%1 MB</source> + <translation>%1 مگابایت</translation> + </message> + <message> + <source>%1 GB</source> + <translation>%1 گیگابایت</translation> + </message> + <message> <source>never</source> <translation>هرگز</translation> </message> @@ -891,7 +931,11 @@ <source>Copy &Address</source> <translation>&کپی نشانی</translation> </message> - </context> + <message> + <source>&Save Image...</source> + <translation>&ذخیره عکس...</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> <message> @@ -939,6 +983,18 @@ <translation>پنهان کردن</translation> </message> <message> + <source>Recommended:</source> + <translation>توصیه شده:</translation> + </message> + <message> + <source>Custom:</source> + <translation>سفارشی:</translation> + </message> + <message> + <source>Confirmation time:</source> + <translation>روز تایید:</translation> + </message> + <message> <source>normal</source> <translation>نرمال</translation> </message> @@ -1028,6 +1084,10 @@ </context> <context> <name>ShutdownWindow</name> + <message> + <source>%1 is shutting down...</source> + <translation>%1 در حال خاموش شدن است...</translation> + </message> </context> <context> <name>SignVerifyMessageDialog</name> @@ -1255,6 +1315,10 @@ <translation>گزینههای کیف پول:</translation> </message> <message> + <source>(default: %u)</source> + <translation>(پیشفرض %u)</translation> + </message> + <message> <source>Information</source> <translation>اطلاعات</translation> </message> diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index b329612de..8faa3ce65 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -300,10 +300,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>نام کنسول RPC</translation> - </message> - <message> <source>Client version</source> <translation>ویرایش کنسول RPC</translation> </message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index c2226e9b9..b7b3115e2 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -930,10 +930,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Pääteohjelman nimi</translation> - </message> - <message> <source>N/A</source> <translation>Ei saatavilla</translation> </message> @@ -1719,14 +1715,6 @@ <translation>Käytä UPnP:ta kuuntelevan portin kartoitukseen (oletus: 1 kun kuunnellaan ja -proxy ei käytössä)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>VAROITUS: epätavallisen monta lohkoa generoitu, vastaanotettu %d lohkoa viimeisen %d tunnin aikana (odotettavissa %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>VAROITUS: tarkista verkkoyhteytesi, vastaanotettu %d lohkoa viimeisen %d tunnin aikana (odotettavissa %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Varoitus: Tietoverkko ei ole sovussa! Luohijat näyttävät kokevan virhetilanteita.</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index fe745f99b..0b538d766 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nom du client</translation> - </message> - <message> <source>N/A</source> <translation>N.D.</translation> </message> @@ -1859,16 +1855,12 @@ <translation>Ceci est une pré-version de test - l'utiliser à vos risques et périls - ne pas l'utiliser pour miner ou pour des applications marchandes</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 lors de l'écoute et pas de mandataire -proxy)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Impossible de rebobiner la base de données à un état préfourche. Vous devrez retélécharger la chaîne de blocs</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVERTISSEMENT : un nombre anormalement élevé de blocs a été généré, %d blocs reçus durant les %d dernières heures (%d attendus)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVERTISSEMENT : vérifiez votre connexion réseau, %d blocs reçus durant les %d dernières heures (%d attendus)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 lors de l'écoute et pas de mandataire -proxy)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2071,10 +2063,18 @@ <translation>Reconstruire l'état de la chaîne à partir des blocs indexés actuellement</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Rebobinage des blocs...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Définir la taille du cache de la base de données en mégaoctets (%d to %d, default: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Définir le coût maximal de bloc (par défaut : %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Définir la taille minimale de bloc en octets (par défaut : %d)</translation> </message> @@ -2191,6 +2191,10 @@ <translation>Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL <https://www.openssl.org/> et un logiciel cryptographique écrit par Eric Young, ainsi qu'un logiciel UPnP écrit par Thomas Bernard.</translation> </message> <message> + <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source> + <translation>Utiliser une génération de clef hiérarchique déterministe (HD) après BIP32. N'a d'effet que lors de la création/premier lancement du porte-monnaie</translation> + </message> + <message> <source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source> <translation>Les pairs de la liste blanche ne peuvent pas être bannis DoS et leurs transactions sont toujours relayées, même si elles sont déjà dans le mempool, utile p. ex. pour une passerelle</translation> </message> diff --git a/src/qt/locale/bitcoin_fr_FR.ts b/src/qt/locale/bitcoin_fr_FR.ts index f7fd7e6a1..a6f6ac4fd 100644 --- a/src/qt/locale/bitcoin_fr_FR.ts +++ b/src/qt/locale/bitcoin_fr_FR.ts @@ -255,6 +255,10 @@ <translation><numerusform>%n connexion active au réseau Bitcoin</numerusform><numerusform>%n connexions actives au réseau Bitcoin</numerusform></translation> </message> <message> + <source>Indexing blocks on disk...</source> + <translation>Indexation des blocs sur le disque...</translation> + </message> + <message> <source>No block source available...</source> <translation>Aucun bloc source disponible</translation> </message> @@ -307,6 +311,10 @@ <translation>À jour</translation> </message> <message> + <source>%1 client</source> + <translation>%1 client</translation> + </message> + <message> <source>Catching up...</source> <translation>Rattrapage...</translation> </message> @@ -512,6 +520,10 @@ <translation>Bienvenue </translation> </message> <message> + <source>Welcome to %1.</source> + <translation>Bienvenue sur %1.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Utiliser le répertoire par défaut </translation> </message> @@ -642,6 +654,14 @@ <translation>&Fenêtre</translation> </message> <message> + <source>&Hide the icon from the system tray.</source> + <translation>&Cacher l'icône dans la zone de notification.</translation> + </message> + <message> + <source>Hide tray icon</source> + <translation>Cacher l'icône de la zone de notification</translation> + </message> + <message> <source>&Minimize to the tray instead of the taskbar</source> <translation>&Minimiser dans la barre système au lieu de la barre des tâches</translation> </message> @@ -790,10 +810,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nom du client</translation> - </message> - <message> <source>N/A</source> <translation>N/A </translation> </message> @@ -1327,6 +1343,10 @@ <translation>Fonctionner en arrière-plan en tant que démon et accepter les commandes</translation> </message> <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Impossible de démarrer le serveur HTTP. Voir le journal de débogage pour plus de détails.</translation> + </message> + <message> <source>Bitcoin Core</source> <translation>Bitcoin Core</translation> </message> diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts index f3673b6dc..9aa7b5509 100644 --- a/src/qt/locale/bitcoin_gl.ts +++ b/src/qt/locale/bitcoin_gl.ts @@ -596,10 +596,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nome do cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index fbe16364e..4a293c1c3 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -828,10 +828,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>שם לקוח</translation> - </message> - <message> <source>N/A</source> <translation>לא זמין</translation> </message> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 0d8d3d5c9..f5accfb0b 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -658,10 +658,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Ime klijenta</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index bddc430f2..9eb0cf76c 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -806,10 +806,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Kliens néve</translation> - </message> - <message> <source>N/A</source> <translation>Nem elérhető</translation> </message> diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts index fe07ab7a2..feb6f690c 100644 --- a/src/qt/locale/bitcoin_id_ID.ts +++ b/src/qt/locale/bitcoin_id_ID.ts @@ -854,10 +854,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nama Klien</translation> - </message> - <message> <source>N/A</source> <translation>T/S</translation> </message> diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index b92dbb2cb..55bc9c3c8 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -931,10 +931,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nome del client</translation> - </message> - <message> <source>N/A</source> <translation>N/D</translation> </message> @@ -1748,14 +1744,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Utilizza UPnP per mappare la porta in ascolto (default: 1 quando in ascolto e -proxy non è specificato)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>ATTENZIONE, il numero di blocchi generati è insolitamente elevato: %d blocchi ricevuti nelle ultime %d ore (%d previsti)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ATTENZIONE, si consiglia di verificare la connessione di rete: %d blocchi ricevuti nelle ultime %d ore (%d previsti)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Attenzione: La rete non sembra trovarsi in pieno consenso! Alcuni minatori sembrano riscontrare problemi.</translation> </message> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index b2dae186d..4948cc306 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>クライアント名</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1879,16 +1875,12 @@ <translation>これはリリース前のテストビルドです - 各自の責任で利用すること - 採掘や商取引に使用しないでください</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1)</translation> - </message> - <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告:異常に多くの数のブロックが生成されています。%d ブロックが最近 %d 時間以内に受け取られました。(期待値: %d)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>データベースをフォーク前の状態に巻き戻せませんでした。ブロックチェーンを再ダウンロードする必要があります</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告:ネットワーク接続を確認してください。%d ブロックが最近 %d 時間以内にに受け取られました。(期待値: %d)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2100,10 +2092,18 @@ <translation>既にインデックスされたブロックからチェイン状態を再構築する</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>ブロックを巻き戻しています...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>データベースのキャッシュサイズをメガバイトで設定 (%dから%d。初期値: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>最大ブロックコストを設定 (初期値: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>最大ブロックサイズをバイトで設定 (初期値: %d)</translation> </message> diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index 22e7651f6..80508be8e 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -664,10 +664,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>კლიენტი</translation> - </message> - <message> <source>N/A</source> <translation>მიუწვდ.</translation> </message> diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index 11e5d35af..012632c0e 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -926,10 +926,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>클라이언트 이름</translation> - </message> - <message> <source>N/A</source> <translation>없음</translation> </message> @@ -1759,14 +1755,6 @@ <translation>리슨(Listen) 포트를 할당하기 위해 UPnP 사용 (기본값: 열려있거나 -proxy 옵션을 사용하지 않을 시 1)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>경고: 비정상적으로 많은 블록이 생성되고 있습니다. %d 블록은 마지막 %d에 수신되었습니다 (%d 예측됨)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>경고: 네트워크 연결을 확인해 주세요. %d 블록은 마지막 %d에 수신되었습니다 (%d 예측됨)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>경고 : 모든 네트워크가 동의해야 하나, 일부 채굴자들에게 문제가 있는 것으로 보입니다. </translation> </message> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index ebaddba7e..dc532fe01 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -444,10 +444,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nomen clientis</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 9e98baa77..1f6cda1f5 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -564,10 +564,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Kliento pavadinimas</translation> - </message> - <message> <source>N/A</source> <translation>nėra</translation> </message> diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index bac587569..38333531e 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -652,10 +652,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Klienta vārds</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts index e38320ac5..d9ef0d127 100644 --- a/src/qt/locale/bitcoin_mn.ts +++ b/src/qt/locale/bitcoin_mn.ts @@ -292,10 +292,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Клиентийн нэр</translation> - </message> - <message> <source>N/A</source> <translation>Алга Байна</translation> </message> diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts index de4c32c2d..acfb38e41 100644 --- a/src/qt/locale/bitcoin_ms_MY.ts +++ b/src/qt/locale/bitcoin_ms_MY.ts @@ -18,6 +18,15 @@ <translation>&Salin</translation> </message> <message> + <source>Delete the currently selected address from the list</source> + <translation>Padam alamat semasa yang dipilih dari senaraiyang dipilih dari senarai</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation> +Alihkan fail data ke dalam tab semasa</translation> + </message> + <message> <source>&Export</source> <translation>&Eksport</translation> </message> diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index b5ffdb2e1..4538fd6e1 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -930,10 +930,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Klientnavn</translation> - </message> - <message> <source>N/A</source> <translation>-</translation> </message> @@ -1747,14 +1743,6 @@ <translation>Bruk UPnP for lytteport (standardverdi: 1 ved lytting og uten -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVARSEL: unormalt høyt antall blokker generert, %d blokker mottatt de siste %d timene (%d forventet)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ADVARSEL: kontroller nettverkstilkoblingen, mottok %d blokker i de siste %d timene (%d forventet)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Advarsel: Nettverket ser ikke ut til å være enig! Noen minere ser ut til å ha problemer.</translation> </message> diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 3009c154e..781c5a8fd 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -870,7 +870,7 @@ </message> <message> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> - <translation>De weergegeven informatie kan verouderd zijn. Uw portemonnee synchroniseert automaticsh met het Bitcoinnetwerk nadat een verbinding is gelegd, maar dit proces is nog niet voltooid.</translation> + <translation>De weergegeven informatie kan verouderd zijn. Uw portemonnee synchroniseert automatisch met het Bitcoinnetwerk nadat een verbinding is gelegd, maar dit proces is nog niet voltooid.</translation> </message> <message> <source>Watch-only:</source> @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Clientnaam</translation> - </message> - <message> <source>N/A</source> <translation>N.v.t.</translation> </message> @@ -1871,14 +1867,6 @@ <translation>Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er geluisterd worden en geen -proxy is meegegeven)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>WAARSCHUWING: abnormaal hoog aantal blokken is gegenereerd, %d blokken ontvangen in de laatste %d uren (%d verwacht)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>WAARSCHUWING: controleer uw netwerkverbinding, %d blokken ontvangen in de laatste %d uren (%d verwacht)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Waarschuwing: Het lijkt erop dat het netwerk geen consensus kan vinden! Sommige delvers lijken problemen te ondervinden.</translation> </message> diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts index 12151a576..535154333 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -428,10 +428,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Lagyu ning kliente</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 6d41cbeef..09f748b83 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -300,7 +300,7 @@ </message> <message> <source>%1 behind</source> - <translation>%1 wstecz</translation> + <translation>%1 za</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nazwa klienta</translation> - </message> - <message> <source>N/A</source> <translation>NIEDOSTĘPNE</translation> </message> @@ -1840,14 +1836,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Użyj UPnP do mapowania portu nasłuchu (domyślnie: 1 gdy nasłuchuje i brak -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>UWAGA: nienaturalnie duża liczba wygenerowanych bloków, %d bloków otrzymano w ostatnich %d godzinach (%d oczekiwanych)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>UWAGA: sprawdź swoje połączenie sieciowe, %d bloków otrzymano w ostatnich %d godzinach (%d oczekiwanych)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Ostrzeżenie: Sieć nie wydaje się w pełni zgodna! Niektórzy górnicy wydają się doświadczać problemów.</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index fe9dd6626..ee48c6734 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -115,6 +115,10 @@ <translation>&About %1</translation> </message> <message> + <source>Show information about %1</source> + <translation>Mostrar informações sobre %1</translation> + </message> + <message> <source>About &Qt</source> <translation>Sobre &Qt</translation> </message> @@ -572,6 +576,14 @@ <translation>Bem vindo ao %1</translation> </message> <message> + <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <translation>Como essa é a primeira vez que o programa é executado, você pode escolher onde %1 armazenará seus dados.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source> + <translation>O %1 irá baixar e armazenar uma cópia do block chain do Bitcoin. Pelo menos %2GB de dados serão armazenados neste diretório, e ele crescerá ao longo do tempo. A carteira também será armazenada neste diretório.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Use o diretório de dados padrão</translation> </message> @@ -982,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nome do cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> @@ -1010,6 +1018,10 @@ <translation>Versão do BerkeleyDB</translation> </message> <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> <source>Startup time</source> <translation>Horário de inicialização</translation> </message> @@ -1094,6 +1106,10 @@ <translation>User Agent</translation> </message> <message> + <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <translation>Abrir o arquivo de log de depuração do %1 localizado no diretório atual de dados. Isso pode levar alguns segundos para arquivos de log grandes.</translation> + </message> + <message> <source>Decrease font size</source> <translation>Diminuir o tamanho da fonte</translation> </message> @@ -1795,6 +1811,10 @@ <translation>Vincular ao endereço fornecido e sempre escutar nele. Use a notação [host]:port para IPv6</translation> </message> <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Não foi possível obter exclusividade de escrita no endereço %s. O %s provavelmente já está sendo executado.</translation> + </message> + <message> <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source> <translation>Apaga todas as transações da carteira e somente recupera essas partes da blockchain usando o comando -rescan na inicialização</translation> </message> @@ -1803,6 +1823,14 @@ <translation>Distribuido sob a licença MIT software license. Veja os termos em <http://www.opensource.org/licenses/mit-license.php>.</translation> </message> <message> + <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source> + <translation>Erro ao carregar %s. Não é permitido habilitar HD em carteiras não-HD pre existentes.</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <translation>Erro ao ler arquivo %s! Todas as chaves foram lidas corretamente, mas os dados de transação ou o livro de endereos podem estar faltando ou incorretos.</translation> + </message> + <message> <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source> <translation>Executa um comando quando uma transação da carteira mudar (%s no comando será substituído por TxID)</translation> </message> @@ -1811,6 +1839,22 @@ <translation>Força a retransmissão de transações de pares da lista branca, mesmo quando violam a política local de retransmissão (default: %d)</translation> </message> <message> + <source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source> + <translation>A mediana máxima permitida de peer time compensa o ajuste. Perspectiva local de horário pode ser influenciada por pares à frente ou atrás neste montante. (padrão: %u segundos)</translation> + </message> + <message> + <source>Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)</source> + <translation>Preço máximo total (in %s) aplicado a uma única transação de carteira ou transação crua; aplicar isto tão baixo pode abortar grandes transações (padrão: %s)</translation> + </message> + <message> + <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <translation>Por favor verifique que a data e o horário de seu computador estão corretos. Se o relógio de seu computador estiver incorreto, %s não funcionarão corretamente.</translation> + </message> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software.</translation> + </message> + <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> <translation>Define o número de threads de verificação de script (%u a %d, 0 = automático, <0 = número de cores deixados livres, padrão: %d)</translation> </message> @@ -1827,14 +1871,6 @@ <translation>Use UPnP para mapear a porta escutada (padrão: 1 quando escutando e sem -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVISO: números estranhamente altos de blocos gerados, %d blocos recebidos nas últimas %d horas (%d esperados)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ATENÇÃO: verifique sua conexão %d blocos recebidos nas últimas %d horas (%d tempo estimado)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Atenção: A rede não parecem concordar plenamente! Alguns mineiros parecem estar enfrentando problemas.</translation> </message> @@ -1859,6 +1895,10 @@ <translation>Adiciona comentário ao user-agent do navegador</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet on startup</source> + <translation>Tentando recuperar a chape privada da carteira corrompida ao inicializar</translation> + </message> + <message> <source>Block creation options:</source> <translation>Opções de criação de blocos:</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 16b912dfd..eed262e01 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -618,6 +618,10 @@ <translation>&Principal</translation> </message> <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Começar o %1 automaticamente ao iniciar a sessão no sistema.</translation> + </message> + <message> <source>&Start %1 on system login</source> <translation>&Iniciar o %1 no início de sessão do sistema</translation> </message> @@ -963,10 +967,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nome do Cliente</translation> - </message> - <message> <source>N/A</source> <translation>N/D</translation> </message> @@ -1812,14 +1812,6 @@ <translation>Utilizar UPnP para mapear a porta de escuta (predefinição: 1 quando escutar e sem -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVISO: gerado um número anormalmente elevado de blocos, %d blocos recebidos nas últimas %d horas (%d esperados)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>AVISO: verifique a sua conexão à rede, %d blocos recebidos nas últimas %d horas (%d esperados)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Aviso: A rede não parece estar completamente de acordo! Parece que alguns mineiros estão com dificuldades técnicas.</translation> </message> @@ -1844,6 +1836,10 @@ <translation>Anexar um comentário para a entrada de agente do utilizador</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet on startup</source> + <translation>Tentar reuperar as chaves privadas de um "wallet" ao iniciar</translation> + </message> + <message> <source>Block creation options:</source> <translation>Opções da criação de bloco:</translation> </message> diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index e6f591aa9..489ed0763 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -914,10 +914,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Nume client</translation> - </message> - <message> <source>N/A</source> <translation>indisponibil</translation> </message> diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index e2949a948..60f5d5dfa 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -131,6 +131,10 @@ <translation>&Параметры</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation>Изменить конфигурационные настройки для %1</translation> + </message> + <message> <source>&Encrypt Wallet...</source> <translation>&Зашифровать бумажник...</translation> </message> @@ -552,7 +556,11 @@ <source>Show splash screen on startup (default: %u)</source> <translation>Показывать экран-заставку при запуске (по умолчанию: %u)</translation> </message> - </context> + <message> + <source>Reset all settings changed in the GUI</source> + <translation>Сбросить все настройки, измененные в графическом интерфейсе</translation> + </message> +</context> <context> <name>Intro</name> <message> @@ -564,6 +572,14 @@ <translation>Добро пожаловать в %1</translation> </message> <message> + <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> + <translation>При первом запуске программы вы можете выбрать где %1 будет хранить свои данные.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source> + <translation>%1 скачает и сохранит копию цепи блоков. Как минимум %2GB будут записаны в этот каталог, и со временем он будет расти. Бумажник также будет сохранен в этом каталоге.</translation> + </message> + <message> <source>Use the default data directory</source> <translation>Использовать каталог данных по умолчанию</translation> </message> @@ -618,6 +634,14 @@ <translation>&Главная</translation> </message> <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Автоматически запускать %1 после входа в систему.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Запускать %1 при входе в систему</translation> + </message> + <message> <source>Size of &database cache</source> <translation>Размер кэша &БД</translation> </message> @@ -754,6 +778,10 @@ <translation>&Окно</translation> </message> <message> + <source>&Hide the icon from the system tray.</source> + <translation>&Скрыть иконку из системного трея.</translation> + </message> + <message> <source>Hide tray icon</source> <translation>Скрыть иконку в трее</translation> </message> @@ -778,6 +806,10 @@ <translation>&Язык интерфейса:</translation> </message> <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>Здесь можно установить язык пользовательского интерфейса. Настройки вступят в силу после перезагрузки %1</translation> + </message> + <message> <source>&Unit to show amounts in:</source> <translation>&Отображать суммы в единицах: </translation> </message> @@ -958,10 +990,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Имя клиента</translation> - </message> - <message> <source>N/A</source> <translation>Н/Д</translation> </message> @@ -986,6 +1014,10 @@ <translation>Используется версия BerkeleyDB</translation> </message> <message> + <source>Datadir</source> + <translation>Каталог для данных</translation> + </message> + <message> <source>Startup time</source> <translation>Время запуска</translation> </message> @@ -1070,6 +1102,18 @@ <translation>Юзер-агент</translation> </message> <message> + <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> + <translation>Открыть отладочный лог-файл %1 из текущего каталога данных. Это может занять несколько секунд для больших лог-файлов.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Уменьшить размер текста</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Увеличить размер текста</translation> + </message> + <message> <source>Services</source> <translation>Сервисы</translation> </message> @@ -1174,6 +1218,10 @@ <translation>&Разблокировать узел</translation> </message> <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Добро пожаловать в консоль RPC %1.</translation> + </message> + <message> <source>Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.</source> <translation>Используйте стрелки вверх и вниз для просмотра истории и <b>Ctrl-L</b> для очистки экрана.</translation> </message> @@ -1553,6 +1601,10 @@ <context> <name>ShutdownWindow</name> <message> + <source>%1 is shutting down...</source> + <translation>%1 выключается...</translation> + </message> + <message> <source>Do not shut down the computer until this window disappears.</source> <translation>Не выключайте компьютер, пока это окно не исчезнет.</translation> </message> @@ -1743,10 +1795,22 @@ <translation>Bitcoin Core</translation> </message> <message> + <source>The %s developers</source> + <translation>Разработчики %s</translation> + </message> + <message> + <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Установлено очень большое значение -fallbackfee! Это комиссия за транзацию, которую вы можете заплатить, если оценка размера комиссии не доступна. </translation> + </message> + <message> <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source> <translation>Привязаться к указанному адресу и всегда прослушивать только его. Используйте [хост]:порт для IPv6</translation> </message> <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Невозможно заблокировать каталог данных %s. %s возможно уже работает.</translation> + </message> + <message> <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source> <translation>Удалить все транзакции бумажника с возможностью восстановить эти части цепи блоков с помощью -rescan при запуске</translation> </message> @@ -1755,6 +1819,10 @@ <translation>Распространяется под лицензией MIT, см. приложенный файл COPYING или <http://www.opensource.org/licenses/mit-license.php>.</translation> </message> <message> + <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <translation>Ошибка чтения %s! Все ключи прочитаны верно, но данные транзакций или записи адресной книги могут отсутствовать или быть неправильными.</translation> + </message> + <message> <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source> <translation>Выполнить команду, когда меняется транзакция в бумажнике (%s в команде заменяется на TxID)</translation> </message> @@ -1763,6 +1831,10 @@ <translation>Всегда разрешать транзакции, полученные от участников из белого списка (по умолчанию: %d)</translation> </message> <message> + <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <translation>Пожалуйста убедитесь в корректности установки времени и даты на вашем компьютере! Если время установлено неверно, %s не будет работать правильно.</translation> + </message> + <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> <translation>Задать число потоков проверки скрипта (от %u до %d, 0=авто, <0 = оставить столько ядер свободными, по умолчанию: %d)</translation> </message> @@ -1779,14 +1851,6 @@ <translation>Использовать UPnP для проброса порта (по умолчанию: 1, если используется прослушивание и нет -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>ВНИМАНИЕ: сгенерировано ненормально большое число блоков, %d блоков получено за последние %d часов (ожидалось %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>ВНИМАНИЕ: проверьте сетевое подключение, получено %d блоков за последние %d часов (ожидалось %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Внимание: похоже, в сети нет полного согласия! Некоторый майнеры, возможно, испытывают проблемы.</translation> </message> @@ -1799,6 +1863,10 @@ <translation>Вносить в белый список участников, подключающихся с указанной маски сети или IP. Можно использовать многократно.</translation> </message> <message> + <source>%s corrupt, salvage failed</source> + <translation>%s поврежден, восстановить не удалось</translation> + </message> + <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool должен быть как минимум %d MB</translation> </message> @@ -1811,6 +1879,10 @@ <translation>Добавить комментарий к строке пользовательского агента</translation> </message> <message> + <source>Attempt to recover private keys from a corrupt wallet on startup</source> + <translation>Попытаться восстановить приватные ключи из повреждённого бумажника при запуске</translation> + </message> + <message> <source>Block creation options:</source> <translation>Параметры создания блоков:</translation> </message> @@ -1823,6 +1895,10 @@ <translation>Параметры подключения:</translation> </message> <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation>БД блоков повреждена</translation> </message> @@ -1867,6 +1943,14 @@ <translation>Ошибка загрузки %s</translation> </message> <message> + <source>Error loading %s: Wallet corrupted</source> + <translation>Ошибка загрузки %s: Бумажник поврежден</translation> + </message> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Ошибка загрузки %s: Для бумажника требуется более новая версия %s</translation> + </message> + <message> <source>Error loading block database</source> <translation>Ошибка чтения базы данных блоков</translation> </message> @@ -1895,10 +1979,18 @@ <translation>Неверный -onion адрес: '%s'</translation> </message> <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Неверная сумма для -%s=<amount>: '%s'</translation> + </message> + <message> <source>Keep the transaction memory pool below <n> megabytes (default: %u)</source> <translation>Сбрасывать транзакции из памяти на диск каждые <n> мегабайт (по умолчанию: %u)</translation> </message> <message> + <source>Loading banlist...</source> + <translation>Загрузка банлиста...</translation> + </message> + <message> <source>Location of the auth cookie (default: data dir)</source> <translation>Расположение куки входы(по умолчанию: data dir)</translation> </message> @@ -1911,6 +2003,10 @@ <translation>Соединяться только по сети <net> (ipv4, ipv6 или onion)</translation> </message> <message> + <source>Print this help message and exit</source> + <translation>Вывести эту справку и выйти</translation> + </message> + <message> <source>Print version and exit</source> <translation>Написать версию и выйти</translation> </message> @@ -1923,10 +2019,18 @@ <translation>Режим удаления блоков несовместим с -txindex.</translation> </message> <message> + <source>Rebuild chain state from the currently indexed blocks</source> + <translation>Перестроить индекс цепи из текущих индексированных блоков</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Установить размер кэша БД в мегабайтах(от %d до %d, по умолчанию: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Задать максимальную стоимость блока (по умолчанию: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Задать максимальный размер блока в байтах (по умолчанию: %d)</translation> </message> @@ -1935,6 +2039,14 @@ <translation>Укажите файл бумажника (внутри каталога данных)</translation> </message> <message> + <source>The source code is available from %s.</source> + <translation>Исходный код доступен в %s.</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <translation>Невозможно привязаться к %s на этом компьютере. Возможно, %s уже работает.</translation> + </message> + <message> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation>Неподдерживаемый аргумент -benchmark проигнорирован, используйте -debug=bench.</translation> </message> @@ -1967,6 +2079,14 @@ <translation>Бумажник %s располагается вне каталога данных %s</translation> </message> <message> + <source>Wallet debugging/testing options:</source> + <translation>Параметры отладки/тестирования бумажника:</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Необходимо перезаписать бумажник, перезапустите %s для завершения операции.</translation> + </message> + <message> <source>Wallet options:</source> <translation>Настройки бумажника:</translation> </message> @@ -2267,6 +2387,10 @@ <translation>Внимание: Получена неизвестная версия блока! Возможно неизвестные правила вступили в силу.</translation> </message> <message> + <source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source> + <translation>Внимание: Файл бумажника поврежден, данные восстановлены! Оригинальный %s сохранен как %s в %s; Если баланс или транзакции некорректны, вы должны восстановить файл из резервной копии.</translation> + </message> + <message> <source>(default: %s)</source> <translation>(по умолчанию: %s)</translation> </message> diff --git a/src/qt/locale/bitcoin_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts index a6f9ffccb..66419728e 100644 --- a/src/qt/locale/bitcoin_ru_RU.ts +++ b/src/qt/locale/bitcoin_ru_RU.ts @@ -2,6 +2,10 @@ <context> <name>AddressBookPage</name> <message> + <source>Right-click to edit address or label</source> + <translation>Кликните правой кнопкой мыши для редоктирования адреса или ярлыка</translation> + </message> + <message> <source>Create a new address</source> <translation>Создать новый адрес</translation> </message> @@ -40,7 +44,11 @@ </context> <context> <name>AskPassphraseDialog</name> - </context> + <message> + <source>Repeat new passphrase</source> + <translation>Повторите новый пароль</translation> + </message> +</context> <context> <name>BanTableModel</name> </context> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index e2b8a0201..a4f0ebcb4 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -930,10 +930,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Meno klienta</translation> - </message> - <message> <source>N/A</source> <translation>nie je k dispozícii</translation> </message> @@ -1708,14 +1704,6 @@ <translation>Toto je pred-testovacia verzia - použitie je na vlastné riziko - nepoužívajte na tvorbu bitcoin ani obchodovanie.</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>VAROVANIE: príliš veľa vygenerovaných blokov; %d prijatých blokov v posledných %d hodinách (očakávaných %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>VAROVANIE: skontrolujte sieťové pripojenie, %d prijatých blokov za posledných %d hodín (očakávané %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Varovanie: Javí sa že sieť sieť úplne nesúhlasí! Niektorí mineri zjavne majú ťažkosti. diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts index 155be7bb2..16ef20ea3 100644 --- a/src/qt/locale/bitcoin_sl_SI.ts +++ b/src/qt/locale/bitcoin_sl_SI.ts @@ -870,10 +870,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Ime odjemalca</translation> - </message> - <message> <source>N/A</source> <translation>Neznano</translation> </message> @@ -1567,14 +1563,6 @@ <translation>To je preizkusna različica še neizdanega programa. Uporabljate jo na lastno odgovornost. Programa ne uporabljajte je za rudarjenje ali trgovske aplikacije.</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>OPOZORILO: Generirano je bilo nenavadno veliko število blokov. Št. prejetih blokov: %d v št. ur: %d (pričakovanih je %d blokov)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>OPOZORILO: Preverite vašo omrežno povezavo. Št. prejetih blokov: %d v št. ur: %d (pričakovanih je %d blokov)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Opozorilo: Trenutno na omrežju ni videti konsenza! Videti je, kot da bi imeli nekateri rudarji težave.</translation> </message> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index a637cebe2..ee46974d8 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Klientnamn</translation> - </message> - <message> <source>N/A</source> <translation>ej tillgänglig</translation> </message> @@ -1875,16 +1871,12 @@ <translation>Detta är ett förhands testbygge - använd på egen risk - använd inte för mining eller handels applikationer</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Använd UPnP för att mappa den lyssnande porten (förvalt: 1 när lyssning aktiverat och utan -proxy)</translation> - </message> - <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>Varning: Onormalt antal block block genererade. %d block mottagna senaste %d timmarna (%d förväntade)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Kan inte spola tillbaka databasen till obeskärt läge. Du måste ladda ner blockkedjan igen</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>Varning: Kontrollera din närverksanslutning. %d block mottagna senaste %d timmarna, (%d förväntade)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Använd UPnP för att mappa den lyssnande porten (förvalt: 1 när lyssning aktiverat och utan -proxy)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2095,10 +2087,18 @@ <translation>Återskapa blockkedjans status från aktuella indexerade block</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Spolar tillbaka blocken...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Sätt databasens cachestorlek i megabyte (%d till %d, förvalt: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Sätt maximal blockkostnad (förvalt: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Sätt maximal blockstorlek i byte (förvalt: %d)</translation> </message> diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts index 6878d23fe..921171c54 100644 --- a/src/qt/locale/bitcoin_ta.ts +++ b/src/qt/locale/bitcoin_ta.ts @@ -372,10 +372,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>வாடிக்கையாளர் பெயர்</translation> - </message> - <message> <source>N/A</source> <translation>N/A</translation> </message> diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index 263093914..34c752634 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -765,6 +765,30 @@ <source>Tor</source> <translation>Tor</translation> </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> + <translation>เชื่อมต่อกับ เครือข่าย Bitcoin ผ่านทาง พร้อกซี่ SOCKS5 แยกต่างหาก สำหรับ Tor เซอร์วิส</translation> + </message> + <message> + <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source> + <translation>ใช้ พร็อกซี่ SOCKS5 แยก เพื่อเข้าถึง peers ผ่าน Tor เซอร์วิสซ่อน:</translation> + </message> + <message> + <source>&Window</source> + <translation>&วันโดว์</translation> + </message> + <message> + <source>&Hide the icon from the system tray.</source> + <translation>&ซ่อนไอคอน จากเทรย์ระบบ</translation> + </message> + <message> + <source>Hide tray icon</source> + <translation>ซ่อนไอคอนเทรย์</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>แสดงเทรย์ไอคอน หลังมืนิไมส์วินโดว์ เท่านั้น</translation> + </message> </context> <context> <name>OverviewPage</name> diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index f6ab2ca18..e3a811b50 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>İstemci ismi</translation> - </message> - <message> <source>N/A</source> <translation>Mevcut değil</translation> </message> @@ -1835,6 +1831,10 @@ <translation>MIT yazılım lisansı kapsamında yayınlanmıştır, ekteki COPYING dosyasına ya da <http://www.opensource.org/licenses/mit-license.php> adresine bakınız.</translation> </message> <message> + <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source> + <translation>%s yüklenmesinde hata: zaten var olan ve HD olmayan bir cüzdanda HD etkinleştirilemez.</translation> + </message> + <message> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <translation>%s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak muamele verileri ya da adres defteri unsurları hatalı veya eksik olabilir.</translation> </message> @@ -1859,6 +1859,10 @@ <translation>Lütfen bilgisayarınızın saat ve tarihinin doğru olduğunu kontrol ediniz! Saatinizde gecikme varsa %s doğru şekilde çalışamaz.</translation> </message> <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>%s programını faydalı buluyorsanız lütfen katkıda bulununuz. Yazılım hakkında daha fazla bilgi için %s adresini ziyaret ediniz.</translation> + </message> + <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> <translation>Betik kontrolü iş parçacıklarının sayısını belirler (%u ilâ %d, 0 = otomatik, <0 = bu sayıda çekirdeği kullanma, varsayılan: %d)</translation> </message> @@ -1871,16 +1875,12 @@ <translation>Bu yayın öncesi bir deneme sürümüdür - tüm riski siz üstlenmiş olursunuz - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde ve -proxy olmadığında 1)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>Veritabanını çatallama öncesi duruma geri sarmak mümkün değil. Blok zincirini tekrar indirmeniz gerekmektedir</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>İKAZ: anormal yüksek sayıda blok oluşturulmuştur, %d blok son %d saat içinde alınmıştır (%d bekleniyordu)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>İKAZ: ağ bağlantınızı kontrol ediniz, %d blok son %d saat içinde alınmıştır (%d bekleniyordu)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde ve -proxy olmadığında 1)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -1999,6 +1999,10 @@ <translation>%s unsurunun yüklenmesinde hata oluştu: cüzdan %s programının yeni bir sürümüne ihtiyaç duyuyor</translation> </message> <message> + <source>Error loading %s: You can't disable HD on a already existing HD wallet</source> + <translation>%s yüklenmesinde hata: zaten var olan HD bir cüzdanda HD devre dışı bırakılamaz.</translation> + </message> + <message> <source>Error loading block database</source> <translation>Blok veritabanının yüklenmesinde hata</translation> </message> @@ -2087,10 +2091,18 @@ <translation>Zincir durumunu güncel olarak endekslenen bloklardan yeniden derle</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>Bloklar geri sarılıyor...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>Veritabanı önbellek boyutunu megabayt olarak belirt (%d ilâ %d, varsayılan: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>Azami blok maliyetini ayarla (varsayılan: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>Azami blok boyutunu bayt olarak ayarla (varsayılan: %d)</translation> </message> @@ -2099,6 +2111,10 @@ <translation>Cüzdan dosyası belirtiniz (veri klasörünün içinde)</translation> </message> <message> + <source>The source code is available from %s.</source> + <translation>Kaynak kod şuradan elde edilebilir: %s.</translation> + </message> + <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation>Bu bilgisayarda %s unsuruna bağlanılamadı. %s muhtemelen hâlihazırda çalışmaktadır.</translation> </message> @@ -2211,6 +2227,10 @@ <translation>Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl.org/) için geliştirilen yazılımlar, Eric Young ([email protected]) tarafından hazırlanmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir.</translation> </message> <message> + <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source> + <translation>BIP32'den sonra hiyerarşik determinist (HD) anahtar üretimini kullan. Sadece cüzdan oluşturulmasında/ilk başlamada etkiye sahiptir.</translation> + </message> + <message> <source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source> <translation>Beyaz listeye alınan eşler DoS yasaklamasına uğramazlar ve muameleleri zaten mempool'da olsalar da daima aktarılır, bu mesela bir geçit için kullanışlıdır</translation> </message> diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 668e787a6..a06cc9e09 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -930,10 +930,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Назва клієнту</translation> - </message> - <message> <source>N/A</source> <translation>Н/Д</translation> </message> @@ -1747,14 +1743,6 @@ <translation>Використовувати UPnP для відображення порту, що прослуховується (типово: 1 при прослуховуванні та за відсутності -proxy)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>УВАГА: аномально висока кількість згенерованих блоків, %d блок(ів) було отримано за останні %d годин(и) (має бути %d)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>УВАГА: перевірте ваше мережеве з'єднання, %d блок(ів) було отримано за останні %d годин(и) (має бути %d)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>Увага: Частина мережі використовує інший головний ланцюжок! Деякі добувачі, можливо, зазнають проблем.</translation> </message> diff --git a/src/qt/locale/[email protected] b/src/qt/locale/[email protected] index ce3326297..0062abfc1 100644 --- a/src/qt/locale/[email protected] +++ b/src/qt/locale/[email protected] @@ -728,10 +728,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>Мижоз номи</translation> - </message> - <message> <source>N/A</source> <translation>Тўғри келмайди</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 8f467b79c..92a7006d3 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -930,10 +930,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>客户端名称</translation> - </message> - <message> <source>N/A</source> <translation>不可用</translation> </message> @@ -1764,14 +1760,6 @@ <translation>使用UPnP暴露本机监听端口(默认:1 当正在监听且不使用代理)</translation> </message> <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告:数据块生成数量异常,最近 %d 小时收到了 %d 个数据块(预期为 %d 个)</translation> - </message> - <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告:请检查您的网络连接,最近 %d 小时收到了 %d 个数据块(预期为 %d 个)</translation> - </message> - <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> <translation>警告:网络似乎并不完全同意!有些矿工似乎遇到了问题。</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index cbdb8f2c0..ab56f9679 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -994,10 +994,6 @@ <context> <name>RPCConsole</name> <message> - <source>Client name</source> - <translation>客戶端軟體名稱</translation> - </message> - <message> <source>N/A</source> <translation>未知</translation> </message> @@ -1865,7 +1861,7 @@ </message> <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <translation>如果你覺得 %s 有用,可以捐助我們。關於這個軟體的更多資訊請見 %s。</translation> + <translation>如果你覺得 %s 有用,可以幫助我們。關於這個軟體的更多資訊請見 %s。</translation> </message> <message> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> @@ -1880,16 +1876,12 @@ <translation>這是個還沒發表的測試版本 - 使用請自負風險 - 請不要用來開採或商業應用</translation> </message> <message> - <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> - <translation>是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線且沒有指定 -proxy 參數時為 1)</translation> - </message> - <message> - <source>WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告: 收到了不尋常地多的 %d 個區塊在過去 %d 小時內生產出來(預期是 %d 個)</translation> + <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> + <translation>沒辦法將資料庫倒轉回分岔前的狀態。必須要重新下載區塊鍊。</translation> </message> <message> - <source>WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)</source> - <translation>警告: 請檢查你的網路連線狀況,收到了 %d 個區塊是在過去 %d 小時內生產出來(預期是 %d 個)</translation> + <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source> + <translation>是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線且沒有指定 -proxy 參數時為 1)</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -2100,10 +2092,18 @@ <translation>從目前已編索引的區塊資料重建區塊鏈狀態</translation> </message> <message> + <source>Rewinding blocks...</source> + <translation>倒轉回區塊鏈之前的狀態...</translation> + </message> + <message> <source>Set database cache size in megabytes (%d to %d, default: %d)</source> <translation>設定資料庫快取大小是多少百萬位元組(MB,範圍: %d 到 %d,預設值: %d)</translation> </message> <message> + <source>Set maximum block cost (default: %d)</source> + <translation>設定區塊成本的最大值(預設值: %d)</translation> + </message> + <message> <source>Set maximum block size in bytes (default: %d)</source> <translation>設定區塊大小上限成多少位元組(預設值: %d)</translation> </message> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index f2db39889..f73bb8706 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -327,7 +327,8 @@ QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) cons { Q_UNUSED(pos); // Validate the proxy - proxyType addrProxy = proxyType(CService(input.toStdString(), 9050), true); + CService serv(LookupNumeric(input.toStdString().c_str(), 9050)); + proxyType addrProxy = proxyType(serv, true); if (addrProxy.IsValid()) return QValidator::Acceptable; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index cc2cbc0e6..d33ab6827 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -15,6 +15,7 @@ #include "init.h" #include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS #include "net.h" +#include "netbase.h" #include "txdb.h" // for -dbcache defaults #ifdef ENABLE_WALLET @@ -43,6 +44,8 @@ void OptionsModel::Init(bool resetSettings) if (resetSettings) Reset(); + checkAndMigrate(); + QSettings settings; // Ensure restart flag is unset on client startup @@ -429,3 +432,22 @@ bool OptionsModel::isRestartRequired() QSettings settings; return settings.value("fRestartRequired", false).toBool(); } + +void OptionsModel::checkAndMigrate() +{ + // Migration of default values + // Check if the QSettings container was already loaded with this client version + QSettings settings; + static const char strSettingsVersionKey[] = "nSettingsVersion"; + int settingsVersion = settings.contains(strSettingsVersionKey) ? settings.value(strSettingsVersionKey).toInt() : 0; + if (settingsVersion < CLIENT_VERSION) + { + // -dbcache was bumped from 100 to 300 in 0.13 + // see https://github.com/bitcoin/bitcoin/pull/8273 + // force people to upgrade to the new value if they are using 100MB + if (settingsVersion < 130000 && settings.contains("nDatabaseCache") && settings.value("nDatabaseCache").toLongLong() == 100) + settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache); + + settings.setValue(strSettingsVersionKey, CLIENT_VERSION); + } +}
\ No newline at end of file diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 3b491ceac..b23b5f260 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -84,9 +84,11 @@ private: /* settings that were overriden by command-line */ QString strOverriddenByCommandLine; - /// Add option to list of GUI options overridden through command line/config file + // Add option to list of GUI options overridden through command line/config file void addOverriddenOption(const std::string &option); + // Check settings version and upgrade default values if required + void checkAndMigrate(); Q_SIGNALS: void displayUnitChanged(int unit); void coinControlFeaturesChanged(bool); diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc index 19c3d5d97..94ae25647 100644 --- a/src/qt/res/bitcoin-qt-res.rc +++ b/src/qt/res/bitcoin-qt-res.rc @@ -1,4 +1,5 @@ IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" +IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" #include <windows.h> // needed for VERSIONINFO #include "../../clientversion.h" // holds the needed client version information diff --git a/src/qt/res/icons/bitcoin_testnet.ico b/src/qt/res/icons/bitcoin_testnet.ico Binary files differnew file mode 100644 index 000000000..909194ecd --- /dev/null +++ b/src/qt/res/icons/bitcoin_testnet.ico diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 11f3e49a0..bcaa9164c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -16,6 +16,7 @@ #include "bantablemodel.h" #include "chainparams.h" +#include "netbase.h" #include "rpc/server.h" #include "rpc/client.h" #include "util.h" @@ -451,7 +452,6 @@ void RPCConsole::setClientModel(ClientModel *model) // Provide initial values ui->clientVersion->setText(model->formatFullVersion()); ui->clientUserAgent->setText(model->formatSubVersion()); - ui->clientName->setText(model->clientName()); ui->dataDir->setText(model->dataDir()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); @@ -899,7 +899,10 @@ void RPCConsole::banSelectedNode(int bantime) int port = 0; SplitHostPort(nStr, port, addr); - CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime); + CNetAddr resolved; + if(!LookupHost(addr.c_str(), resolved, false)) + return; + CNode::Ban(resolved, BanReasonManuallyAdded, bantime); clearSelectedNode(); clientModel->getBanTableModel()->refresh(); @@ -913,8 +916,9 @@ void RPCConsole::unbanSelectedNode() // Get currently selected ban address QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address); - CSubNet possibleSubnet(strNode.toStdString()); + CSubNet possibleSubnet; + LookupSubNet(strNode.toStdString().c_str(), possibleSubnet); if (possibleSubnet.IsValid()) { CNode::Unban(possibleSubnet); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 20eefa1c5..e3c32d905 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -101,7 +101,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS))); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); - result.push_back(Pair("cost", (int)::GetBlockCost(block))); + result.push_back(Pair("weight", (int)::GetBlockWeight(block))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion))); @@ -559,7 +559,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"size\" : n, (numeric) The block size\n" " \"strippedsize\" : n, (numeric) The block size excluding witness data\n" - " \"cost\" : n (numeric) The block cost\n" + " \"weight\" : n (numeric) The block weight (BIP 141)\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" @@ -817,22 +817,23 @@ UniValue verifychain(const UniValue& params, bool fHelp) } /** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams) +static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) { - int nFound = 0; - CBlockIndex* pstart = pindex; - for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++) + UniValue rv(UniValue::VOBJ); + bool activated = false; + switch(version) { - if (pstart->nVersion >= minVersion) - ++nFound; - pstart = pstart->pprev; + case 2: + activated = pindex->nHeight >= consensusParams.BIP34Height; + break; + case 3: + activated = pindex->nHeight >= consensusParams.BIP66Height; + break; + case 4: + activated = pindex->nHeight >= consensusParams.BIP65Height; + break; } - - 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)); + rv.push_back(Pair("status", activated)); return rv; } @@ -841,8 +842,7 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* 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))); + rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams))); return rv; } @@ -897,13 +897,9 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " {\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" + " \"reject\": { (object) progress toward rejecting pre-softfork 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" " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n" diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4c4e59978..2479e5d59 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -224,7 +224,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) "{\n" " \"blocks\": nnn, (numeric) The current block\n" " \"currentblocksize\": nnn, (numeric) The last block size\n" - " \"currentblockcost\": nnn, (numeric) The last block cost\n" + " \"currentblockweight\": nnn, (numeric) The last block weight\n" " \"currentblocktx\": nnn, (numeric) The last block transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" " \"errors\": \"...\" (string) Current errors\n" @@ -243,7 +243,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); - obj.push_back(Pair("currentblockcost", (uint64_t)nLastBlockCost)); + obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); @@ -358,7 +358,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) " ],\n" " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n" - " \"cost\" : n, (numeric) total transaction size cost, as counted for purposes of block limits\n" + " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n" " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" " }\n" " ,...\n" @@ -377,7 +377,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" " \"sigoplimit\" : n, (numeric) cost limit of sigops in blocks\n" " \"sizelimit\" : n, (numeric) limit of block size\n" - " \"costlimit\" : n, (numeric) limit of block cost\n" + " \"weightlimit\" : n, (numeric) limit of block weight\n" " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" " \"bits\" : \"xxx\", (string) compressed target of next block\n" " \"height\" : n (numeric) The height of the next block\n" @@ -546,6 +546,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; + // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration + const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); @@ -574,8 +577,13 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) int index_in_template = i - 1; entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); - entry.push_back(Pair("sigops", pblocktemplate->vTxSigOpsCost[index_in_template])); - entry.push_back(Pair("cost", GetTransactionCost(tx))); + int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; + if (fPreSegWit) { + assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0); + nTxSigOps /= WITNESS_SCALE_FACTOR; + } + entry.push_back(Pair("sigops", nTxSigOps)); + entry.push_back(Pair("weight", GetTransactionWeight(tx))); transactions.push_back(entry); } @@ -657,9 +665,14 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); - result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS_COST)); + int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; + if (fPreSegWit) { + assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); + nSigOpLimit /= WITNESS_SCALE_FACTOR; + } + result.push_back(Pair("sigoplimit", nSigOpLimit)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE)); - result.push_back(Pair("costlimit", (int64_t)MAX_BLOCK_COST)); + result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); result.push_back(Pair("curtime", pblock->GetBlockTime())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index f2a29416e..a8c5bcd17 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -166,6 +166,8 @@ UniValue validateaddress(const UniValue& params, bool fHelp) " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n" + " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n" + " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n" "}\n" "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") @@ -200,6 +202,12 @@ UniValue validateaddress(const UniValue& params, bool fHelp) ret.pushKVs(detail); if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); + CKeyID keyID; + if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty()) + { + ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath)); + ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex())); + } #endif } return ret; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index b85c7b2e1..4ce122648 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -484,7 +484,7 @@ UniValue setban(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") - + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400") + + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") ); CSubNet subNet; @@ -494,10 +494,13 @@ UniValue setban(const UniValue& params, bool fHelp) if (params[0].get_str().find("/") != string::npos) isSubnet = true; - if (!isSubnet) - netAddr = CNetAddr(params[0].get_str()); + if (!isSubnet) { + CNetAddr resolved; + LookupHost(params[0].get_str().c_str(), resolved, false); + netAddr = resolved; + } else - subNet = CSubNet(params[0].get_str()); + LookupSubNet(params[0].get_str().c_str(), subNet); if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet"); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 23149baa6..5fb97f749 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -25,6 +25,8 @@ #include <boost/thread.hpp> #include <boost/algorithm/string/case_conv.hpp> // for to_upper() +#include <memory> // for unique_ptr + using namespace RPCServer; using namespace std; @@ -34,9 +36,8 @@ static std::string rpcWarmupStatus("RPC server started"); static CCriticalSection cs_rpcWarmup; /* Timer-creating functions */ static RPCTimerInterface* timerInterface = NULL; -/* Map of name to timer. - * @note Can be changed to std::unique_ptr when C++11 */ -static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers; +/* Map of name to timer. */ +static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers; static struct CRPCSignals { @@ -490,7 +491,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6 throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); deadlineTimers.erase(name); LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); - deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)))); + deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))); } CRPCTable tableRPC; diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 6f868d0d6..f73a8e30b 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -51,6 +51,7 @@ enum bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65) + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112) bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141) }; diff --git a/src/script/script.cpp b/src/script/script.cpp index da551c23e..ddf677556 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -132,7 +132,7 @@ const char* GetOpName(opcodetype opcode) // expanson case OP_NOP1 : return "OP_NOP1"; case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; - case OP_NOP3 : return "OP_NOP3"; + case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY"; case OP_NOP4 : return "OP_NOP4"; case OP_NOP5 : return "OP_NOP5"; case OP_NOP6 : return "OP_NOP6"; diff --git a/src/script/script.h b/src/script/script.h index 71af3754b..278774d32 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -167,8 +167,8 @@ enum opcodetype OP_NOP1 = 0xb0, OP_CHECKLOCKTIMEVERIFY = 0xb1, OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, - OP_NOP3 = 0xb2, - OP_CHECKSEQUENCEVERIFY = OP_NOP3, + OP_CHECKSEQUENCEVERIFY = 0xb2, + OP_NOP3 = OP_CHECKSEQUENCEVERIFY, OP_NOP4 = 0xb3, OP_NOP5 = 0xb4, OP_NOP6 = 0xb5, diff --git a/src/test/README.md b/src/test/README.md index b2d6be14f..61462642b 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -5,18 +5,15 @@ sense to simply use this framework rather than require developers to configure some other framework (we want as few impediments to creating unit tests as possible). -The build system is setup to compile an executable called "test_bitcoin" +The build system is setup to compile an executable called `test_bitcoin` that runs all of the unit tests. The main source file is called -test_bitcoin.cpp, which simply includes other files that contain the -actual unit tests (outside of a couple required preprocessor -directives). The pattern is to create one test file for each class or -source file for which you want to create unit tests. The file naming -convention is "<source_filename>_tests.cpp" and such files should wrap -their tests in a test suite called "<source_filename>_tests". For an -examples of this pattern, examine uint160_tests.cpp and -uint256_tests.cpp. - -Add the source files to /src/Makefile.test.include to add them to the build. +test_bitcoin.cpp. To add a new unit test file to our test suite you need +to add the file to `src/Makefile.test.include`. The pattern is to create +one test file for each class or source file for which you want to create +unit tests. The file naming convention is `<source_filename>_tests.cpp` +and such files should wrap their tests in a test suite +called `<source_filename>_tests`. For an example of this pattern, +examine `uint256_tests.cpp`. For further reading, I found the following website to be helpful in explaining how the boost unit test framework works: @@ -31,5 +28,5 @@ example, to run just the getarg_tests verbosely: test_bitcoin --run_test=getarg_tests/doubledash -Run test_bitcoin --help for the full list. +Run `test_bitcoin --help` for the full list. diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index b6cec24b5..5f150e481 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -7,6 +7,7 @@ #include <boost/test/unit_test.hpp> #include "hash.h" +#include "netbase.h" #include "random.h" using namespace std; @@ -50,6 +51,30 @@ public: } }; +static CNetAddr ResolveIP(const char* ip) +{ + CNetAddr addr; + BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip)); + return addr; +} + +static CNetAddr ResolveIP(std::string ip) +{ + return ResolveIP(ip.c_str()); +} + +static CService ResolveService(const char* ip, int port = 0) +{ + CService serv; + BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port)); + return serv; +} + +static CService ResolveService(std::string ip, int port = 0) +{ + return ResolveService(ip.c_str(), port); +} + BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(addrman_simple) @@ -59,7 +84,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2"); + CNetAddr source = ResolveIP("252.2.2.2"); // Test 1: Does Addrman respond correctly when empty. BOOST_CHECK(addrman.size() == 0); @@ -67,7 +92,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple) BOOST_CHECK(addr_null.ToString() == "[::]:0"); // Test 2: Does Addrman::Add work as expected. - CService addr1 = CService("250.1.1.1", 8333); + CService addr1 = ResolveService("250.1.1.1", 8333); addrman.Add(CAddress(addr1, NODE_NONE), source); BOOST_CHECK(addrman.size() == 1); CAddrInfo addr_ret1 = addrman.Select(); @@ -75,14 +100,14 @@ BOOST_AUTO_TEST_CASE(addrman_simple) // Test 3: Does IP address deduplication work correctly. // Expected dup IP should not be added. - CService addr1_dup = CService("250.1.1.1", 8333); + CService addr1_dup = ResolveService("250.1.1.1", 8333); addrman.Add(CAddress(addr1_dup, NODE_NONE), source); BOOST_CHECK(addrman.size() == 1); // Test 5: New table has one addr and we add a diff addr we should // have two addrs. - CService addr2 = CService("250.1.1.2", 8333); + CService addr2 = ResolveService("250.1.1.2", 8333); addrman.Add(CAddress(addr2, NODE_NONE), source); BOOST_CHECK(addrman.size() == 2); @@ -100,16 +125,16 @@ BOOST_AUTO_TEST_CASE(addrman_ports) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2"); + CNetAddr source = ResolveIP("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); // Test 7; Addr with same IP but diff port does not replace existing addr. - CService addr1 = CService("250.1.1.1", 8333); + CService addr1 = ResolveService("250.1.1.1", 8333); addrman.Add(CAddress(addr1, NODE_NONE), source); BOOST_CHECK(addrman.size() == 1); - CService addr1_port = CService("250.1.1.1", 8334); + CService addr1_port = ResolveService("250.1.1.1", 8334); addrman.Add(CAddress(addr1_port, NODE_NONE), source); BOOST_CHECK(addrman.size() == 1); CAddrInfo addr_ret2 = addrman.Select(); @@ -132,10 +157,10 @@ BOOST_AUTO_TEST_CASE(addrman_select) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2"); + CNetAddr source = ResolveIP("252.2.2.2"); // Test 9: Select from new with 1 addr in new. - CService addr1 = CService("250.1.1.1", 8333); + CService addr1 = ResolveService("250.1.1.1", 8333); addrman.Add(CAddress(addr1, NODE_NONE), source); BOOST_CHECK(addrman.size() == 1); @@ -156,24 +181,24 @@ BOOST_AUTO_TEST_CASE(addrman_select) // Add three addresses to new table. - CService addr2 = CService("250.3.1.1", 8333); - CService addr3 = CService("250.3.2.2", 9999); - CService addr4 = CService("250.3.3.3", 9999); + CService addr2 = ResolveService("250.3.1.1", 8333); + CService addr3 = ResolveService("250.3.2.2", 9999); + CService addr4 = ResolveService("250.3.3.3", 9999); - addrman.Add(CAddress(addr2, NODE_NONE), CService("250.3.1.1", 8333)); - addrman.Add(CAddress(addr3, NODE_NONE), CService("250.3.1.1", 8333)); - addrman.Add(CAddress(addr4, NODE_NONE), CService("250.4.1.1", 8333)); + addrman.Add(CAddress(addr2, NODE_NONE), ResolveService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr3, NODE_NONE), ResolveService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr4, NODE_NONE), ResolveService("250.4.1.1", 8333)); // Add three addresses to tried table. - CService addr5 = CService("250.4.4.4", 8333); - CService addr6 = CService("250.4.5.5", 7777); - CService addr7 = CService("250.4.6.6", 8333); + CService addr5 = ResolveService("250.4.4.4", 8333); + CService addr6 = ResolveService("250.4.5.5", 7777); + CService addr7 = ResolveService("250.4.6.6", 8333); - addrman.Add(CAddress(addr5, NODE_NONE), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr5, NODE_NONE), ResolveService("250.3.1.1", 8333)); addrman.Good(CAddress(addr5, NODE_NONE)); - addrman.Add(CAddress(addr6, NODE_NONE), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr6, NODE_NONE), ResolveService("250.3.1.1", 8333)); addrman.Good(CAddress(addr6, NODE_NONE)); - addrman.Add(CAddress(addr7, NODE_NONE), CService("250.1.1.3", 8333)); + addrman.Add(CAddress(addr7, NODE_NONE), ResolveService("250.1.1.3", 8333)); addrman.Good(CAddress(addr7, NODE_NONE)); // Test 11: 6 addrs + 1 addr from last test = 7. @@ -193,12 +218,12 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2"); + CNetAddr source = ResolveIP("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); for (unsigned int i = 1; i < 18; i++) { - CService addr = CService("250.1.1." + boost::to_string(i)); + CService addr = ResolveService("250.1.1." + boost::to_string(i)); addrman.Add(CAddress(addr, NODE_NONE), source); //Test 13: No collision in new table yet. @@ -206,11 +231,11 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions) } //Test 14: new table collision! - CService addr1 = CService("250.1.1.18"); + CService addr1 = ResolveService("250.1.1.18"); addrman.Add(CAddress(addr1, NODE_NONE), source); BOOST_CHECK(addrman.size() == 17); - CService addr2 = CService("250.1.1.19"); + CService addr2 = ResolveService("250.1.1.19"); addrman.Add(CAddress(addr2, NODE_NONE), source); BOOST_CHECK(addrman.size() == 18); } @@ -222,12 +247,12 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CNetAddr source = CNetAddr("252.2.2.2"); + CNetAddr source = ResolveIP("252.2.2.2"); BOOST_CHECK(addrman.size() == 0); for (unsigned int i = 1; i < 80; i++) { - CService addr = CService("250.1.1." + boost::to_string(i)); + CService addr = ResolveService("250.1.1." + boost::to_string(i)); addrman.Add(CAddress(addr, NODE_NONE), source); addrman.Good(CAddress(addr, NODE_NONE)); @@ -237,11 +262,11 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions) } //Test 16: tried table collision! - CService addr1 = CService("250.1.1.80"); + CService addr1 = ResolveService("250.1.1.80"); addrman.Add(CAddress(addr1, NODE_NONE), source); BOOST_CHECK(addrman.size() == 79); - CService addr2 = CService("250.1.1.81"); + CService addr2 = ResolveService("250.1.1.81"); addrman.Add(CAddress(addr2, NODE_NONE), source); BOOST_CHECK(addrman.size() == 80); } @@ -255,12 +280,12 @@ BOOST_AUTO_TEST_CASE(addrman_find) BOOST_CHECK(addrman.size() == 0); - CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE); - CAddress addr2 = CAddress(CService("250.1.2.1", 9999), NODE_NONE); - CAddress addr3 = CAddress(CService("251.255.2.1", 8333), NODE_NONE); + CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); + CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); + CAddress addr3 = CAddress(ResolveService("251.255.2.1", 8333), NODE_NONE); - CNetAddr source1 = CNetAddr("250.1.2.1"); - CNetAddr source2 = CNetAddr("250.1.2.2"); + CNetAddr source1 = ResolveIP("250.1.2.1"); + CNetAddr source2 = ResolveIP("250.1.2.2"); addrman.Add(addr1, source1); addrman.Add(addr2, source2); @@ -294,8 +319,8 @@ BOOST_AUTO_TEST_CASE(addrman_create) BOOST_CHECK(addrman.size() == 0); - CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE); - CNetAddr source1 = CNetAddr("250.1.2.1"); + CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); + CNetAddr source1 = ResolveIP("250.1.2.1"); int nId; CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId); @@ -317,8 +342,8 @@ BOOST_AUTO_TEST_CASE(addrman_delete) BOOST_CHECK(addrman.size() == 0); - CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE); - CNetAddr source1 = CNetAddr("250.1.2.1"); + CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); + CNetAddr source1 = ResolveIP("250.1.2.1"); int nId; addrman.Create(addr1, source1, &nId); @@ -344,18 +369,18 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) vector<CAddress> vAddr1 = addrman.GetAddr(); BOOST_CHECK(vAddr1.size() == 0); - CAddress addr1 = CAddress(CService("250.250.2.1", 8333), NODE_NONE); + CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false - CAddress addr2 = CAddress(CService("250.251.2.2", 9999), NODE_NONE); + CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE); addr2.nTime = GetAdjustedTime(); - CAddress addr3 = CAddress(CService("251.252.2.3", 8333), NODE_NONE); + CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE); addr3.nTime = GetAdjustedTime(); - CAddress addr4 = CAddress(CService("252.253.3.4", 8333), NODE_NONE); + CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE); addr4.nTime = GetAdjustedTime(); - CAddress addr5 = CAddress(CService("252.254.4.5", 8333), NODE_NONE); + CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE); addr5.nTime = GetAdjustedTime(); - CNetAddr source1 = CNetAddr("250.1.2.1"); - CNetAddr source2 = CNetAddr("250.2.3.3"); + CNetAddr source1 = ResolveIP("250.1.2.1"); + CNetAddr source2 = ResolveIP("250.2.3.3"); // Test 23: Ensure GetAddr works with new addresses. addrman.Add(addr1, source1); @@ -378,11 +403,11 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) int octet2 = (i / 256) % 256; int octet3 = (i / (256 * 2)) % 256; string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; - CAddress addr = CAddress(CService(strAddr), NODE_NONE); + CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE); // Ensure that for all addrs in addrman, isTerrible == false. addr.nTime = GetAdjustedTime(); - addrman.Add(addr, CNetAddr(strAddr)); + addrman.Add(addr, ResolveIP(strAddr)); if (i % 8 == 0) addrman.Good(addr); } @@ -403,10 +428,10 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CAddress addr1 = CAddress(CService("250.1.1.1", 8333), NODE_NONE); - CAddress addr2 = CAddress(CService("250.1.1.1", 9999), NODE_NONE); + CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); + CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE); - CNetAddr source1 = CNetAddr("250.1.1.1"); + CNetAddr source1 = ResolveIP("250.1.1.1"); CAddrInfo info1 = CAddrInfo(addr1, source1); @@ -431,8 +456,8 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) set<int> buckets; for (int i = 0; i < 255; i++) { CAddrInfo infoi = CAddrInfo( - CAddress(CService("250.1.1." + boost::to_string(i)), NODE_NONE), - CNetAddr("250.1.1." + boost::to_string(i))); + CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE), + ResolveIP("250.1.1." + boost::to_string(i))); int bucket = infoi.GetTriedBucket(nKey1); buckets.insert(bucket); } @@ -443,8 +468,8 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) buckets.clear(); for (int j = 0; j < 255; j++) { CAddrInfo infoj = CAddrInfo( - CAddress(CService("250." + boost::to_string(j) + ".1.1"), NODE_NONE), - CNetAddr("250." + boost::to_string(j) + ".1.1")); + CAddress(ResolveService("250." + boost::to_string(j) + ".1.1"), NODE_NONE), + ResolveIP("250." + boost::to_string(j) + ".1.1")); int bucket = infoj.GetTriedBucket(nKey1); buckets.insert(bucket); } @@ -460,10 +485,10 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) // Set addrman addr placement to be deterministic. addrman.MakeDeterministic(); - CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE); - CAddress addr2 = CAddress(CService("250.1.2.1", 9999), NODE_NONE); + CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); + CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); - CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source1 = ResolveIP("250.1.2.1"); CAddrInfo info1 = CAddrInfo(addr1, source1); @@ -484,8 +509,8 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) set<int> buckets; for (int i = 0; i < 255; i++) { CAddrInfo infoi = CAddrInfo( - CAddress(CService("250.1.1." + boost::to_string(i)), NODE_NONE), - CNetAddr("250.1.1." + boost::to_string(i))); + CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE), + ResolveIP("250.1.1." + boost::to_string(i))); int bucket = infoi.GetNewBucket(nKey1); buckets.insert(bucket); } @@ -496,9 +521,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) buckets.clear(); for (int j = 0; j < 4 * 255; j++) { CAddrInfo infoj = CAddrInfo(CAddress( - CService( + ResolveService( boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1"), NODE_NONE), - CNetAddr("251.4.1.1")); + ResolveIP("251.4.1.1")); int bucket = infoj.GetNewBucket(nKey1); buckets.insert(bucket); } @@ -509,8 +534,8 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) buckets.clear(); for (int p = 0; p < 255; p++) { CAddrInfo infoj = CAddrInfo( - CAddress(CService("250.1.1.1"), NODE_NONE), - CNetAddr("250." + boost::to_string(p) + ".1.1")); + CAddress(ResolveService("250.1.1.1"), NODE_NONE), + ResolveIP("250." + boost::to_string(p) + ".1.1")); int bucket = infoj.GetNewBucket(nKey1); buckets.insert(bucket); } diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp deleted file mode 100644 index 70f1f1227..000000000 --- a/src/test/alert_tests.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2013-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// Unit tests for alert system - -#include "chainparams.h" -#include "main.h" // For PartitionCheck - -#include "test/testutil.h" -#include "test/test_bitcoin.h" - -#include <boost/test/unit_test.hpp> - -BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup) - - -static bool falseFunc() { return false; } - -BOOST_AUTO_TEST_CASE(PartitionAlert) -{ - // Test PartitionCheck - CCriticalSection csDummy; - CBlockIndex indexDummy[100]; - CChainParams& params = Params(CBaseChainParams::MAIN); - int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; - - // Generate fake blockchain timestamps relative to - // an arbitrary time: - int64_t now = 1427379054; - SetMockTime(now); - for (int i = 0; i < 100; i++) - { - indexDummy[i].phashBlock = NULL; - if (i == 0) indexDummy[i].pprev = NULL; - else indexDummy[i].pprev = &indexDummy[i-1]; - indexDummy[i].nHeight = i; - indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing; - // Other members don't matter, the partition check code doesn't - // use them - } - - strMiscWarning = ""; - - // Test 1: chain with blocks every nPowTargetSpacing seconds, - // as normal, no worries: - PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); - BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning); - - // Test 2: go 3.5 hours without a block, expect a warning: - now += 3*60*60+30*60; - SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); - BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); - strMiscWarning = ""; - - // Test 3: test the "partition alerts only go off once per day" - // code: - now += 60*10; - SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); - - // Test 4: get 2.5 times as many blocks as expected: - now += 60*60*24; // Pretend it is a day later - SetMockTime(now); - int64_t quickSpacing = nPowTargetSpacing*2/5; - for (int i = 0; i < 100; i++) // Tweak chain timestamps: - indexDummy[i].nTime = now - (100-i)*quickSpacing; - PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); - BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); - strMiscWarning = ""; - - SetMockTime(0); -} - -BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py index 95dd3e81b..882b5c67b 100755 --- a/src/test/bitcoin-util-test.py +++ b/src/test/bitcoin-util-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # Copyright 2014 BitPay, Inc. # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in index 1618bdeb7..153f34a3d 100644 --- a/src/test/buildenv.py.in +++ b/src/test/buildenv.py.in @@ -1,2 +1,2 @@ -#!/usr/bin/python +#!/usr/bin/env python exeext="@EXEEXT@" diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 9b81e0c77..fcd545738 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -232,8 +232,8 @@ ["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC", "OK"], -["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"], -["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"], +["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"], ["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discourage NOPx flag allows OP_NOP"], @@ -443,7 +443,7 @@ ["NOP", "NOP1 1", "P2SH,STRICTENC", "OK"], ["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC", "OK"], -["NOP", "NOP3 1", "P2SH,STRICTENC", "OK"], +["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP6 1", "P2SH,STRICTENC", "OK"], @@ -701,7 +701,7 @@ ["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"], ["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"], -["2147483648", "NOP3", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"], +["2147483648", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"], ["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"], [" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."], @@ -857,13 +857,13 @@ ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["1", "NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], -["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["Ensure 100% coverage of discouraged NOPS"], ["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], ["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], -["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], +["1", "CHECKSEQUENCEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], ["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], ["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], ["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], @@ -2119,11 +2119,11 @@ ], ["CHECKSEQUENCEVERIFY tests"], -["", "NOP3", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], -["-1", "NOP3", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], -["0x0100", "NOP3", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], -["0", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], -["4294967296", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", +["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], +["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], +["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], +["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], +["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], ["The End"] ] diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 05502a83f..f8baee057 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -200,41 +200,41 @@ ["CHECKSEQUENCEVERIFY tests"], ["By-height locks, with argument just beyond txin.nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument missing"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument negative with by-blockheight txin.nSequence=0"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument/tx height/time mismatch, both versions"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"], @@ -246,9 +246,9 @@ "0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Failure due to insufficient tx.nVersion (<2)"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Unknown witness program version (with DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)"], diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index c9fe4e313..1ea70135b 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -236,77 +236,77 @@ ["CHECKSEQUENCEVERIFY tests"], ["By-height locks, with argument == 0 and == txin.nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["By-time locks, with argument == 0 and == txin.nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Upper sequence with upper sequence is fine"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument 2^31 with various nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument 2^32-1 with various nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Argument 3<<31 with various nSequence"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["5 byte non-minimally-encoded operandss are valid"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["The argument can be calculated rather than created directly by a PUSHDATA"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD CHECKSEQUENCEVERIFY 1"]], "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], ["Valid CHECKSEQUENCEVERIFY in scriptSig"], diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 82d61209b..fa9624f13 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -122,6 +122,10 @@ BOOST_AUTO_TEST_CASE(siphash) hasher3.Write(uint64_t(x)|(uint64_t(x+1)<<8)|(uint64_t(x+2)<<16)|(uint64_t(x+3)<<24)| (uint64_t(x+4)<<32)|(uint64_t(x+5)<<40)|(uint64_t(x+6)<<48)|(uint64_t(x+7)<<56)); } + + CHashWriter ss(SER_DISK, CLIENT_VERSION); + ss << CTransaction(); + BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index fd581db52..15fceb963 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -181,9 +181,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { - // Disable size accounting (CPFP does not support it) - mapArgs["-blockmaxsize"] = strprintf("%u", MAX_BLOCK_SERIALIZED_SIZE); - + // Note that by default, these tests run with size accounting enabled. const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index d005d6a16..6511e6ffa 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -9,6 +9,7 @@ #include "serialize.h" #include "streams.h" #include "net.h" +#include "netbase.h" #include "chainparams.h" using namespace std; @@ -51,8 +52,12 @@ public: int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); s << nUBuckets; - CAddress addr = CAddress(CService("252.1.1.1", 7777), NODE_NONE); - CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2")); + CService serv; + Lookup("252.1.1.1", serv, 7777, false); + CAddress addr = CAddress(serv, NODE_NONE); + CNetAddr resolved; + LookupHost("252.2.2.2", resolved, false); + CAddrInfo info = CAddrInfo(addr, resolved); s << info; } }; @@ -74,14 +79,17 @@ BOOST_AUTO_TEST_CASE(caddrdb_read) CAddrManUncorrupted addrmanUncorrupted; addrmanUncorrupted.MakeDeterministic(); - CService addr1 = CService("250.7.1.1", 8333); - CService addr2 = CService("250.7.2.2", 9999); - CService addr3 = CService("250.7.3.3", 9999); + CService addr1, addr2, addr3; + Lookup("250.7.1.1", addr1, 8333, false); + Lookup("250.7.2.2", addr2, 9999, false); + Lookup("250.7.3.3", addr3, 9999, false); // Add three addresses to new table. - addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), CService("252.5.1.1", 8333)); - addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), CService("252.5.1.1", 8333)); - addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), CService("252.5.1.1", 8333)); + CService source; + Lookup("252.5.1.1", source, 8333, false); + addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source); + addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source); + addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source); // Test that the de-serialization does not throw an exception. CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted); diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 4168f75e9..18ad5dc90 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -14,37 +14,54 @@ using namespace std; BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) +static CNetAddr ResolveIP(const char* ip) +{ + CNetAddr addr; + LookupHost(ip, addr, false); + return addr; +} + +static CSubNet ResolveSubNet(const char* subnet) +{ + CSubNet ret; + LookupSubNet(subnet, ret); + return ret; +} + BOOST_AUTO_TEST_CASE(netbase_networks) { - BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4); - BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6); - BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR); + BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4); + BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6); + BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR); + } BOOST_AUTO_TEST_CASE(netbase_properties) { - BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4()); - BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4()); - BOOST_CHECK(CNetAddr("::1").IsIPv6()); - BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918()); - BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918()); - BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918()); - BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849()); - BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927()); - BOOST_CHECK(CNetAddr("2002::1").IsRFC3964()); - BOOST_CHECK(CNetAddr("FC00::").IsRFC4193()); - BOOST_CHECK(CNetAddr("2001::2").IsRFC4380()); - BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843()); - BOOST_CHECK(CNetAddr("FE80::").IsRFC4862()); - BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052()); - BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor()); - BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal()); - BOOST_CHECK(CNetAddr("::1").IsLocal()); - BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable()); - BOOST_CHECK(CNetAddr("2001::1").IsRoutable()); - BOOST_CHECK(CNetAddr("127.0.0.1").IsValid()); + + BOOST_CHECK(ResolveIP("127.0.0.1").IsIPv4()); + BOOST_CHECK(ResolveIP("::FFFF:192.168.1.1").IsIPv4()); + BOOST_CHECK(ResolveIP("::1").IsIPv6()); + BOOST_CHECK(ResolveIP("10.0.0.1").IsRFC1918()); + BOOST_CHECK(ResolveIP("192.168.1.1").IsRFC1918()); + BOOST_CHECK(ResolveIP("172.31.255.255").IsRFC1918()); + BOOST_CHECK(ResolveIP("2001:0DB8::").IsRFC3849()); + BOOST_CHECK(ResolveIP("169.254.1.1").IsRFC3927()); + BOOST_CHECK(ResolveIP("2002::1").IsRFC3964()); + BOOST_CHECK(ResolveIP("FC00::").IsRFC4193()); + BOOST_CHECK(ResolveIP("2001::2").IsRFC4380()); + BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843()); + BOOST_CHECK(ResolveIP("FE80::").IsRFC4862()); + BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052()); + BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor()); + BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal()); + BOOST_CHECK(ResolveIP("::1").IsLocal()); + BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable()); + BOOST_CHECK(ResolveIP("2001::1").IsRoutable()); + BOOST_CHECK(ResolveIP("127.0.0.1").IsValid()); + } bool static TestSplitHost(string test, string host, int port) @@ -76,9 +93,7 @@ BOOST_AUTO_TEST_CASE(netbase_splithost) bool static TestParse(string src, string canon) { - CService addr; - if (!LookupNumeric(src.c_str(), addr, 65535)) - return canon == ""; + CService addr(LookupNumeric(src.c_str(), 65535)); return canon == addr.ToString(); } @@ -90,165 +105,185 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) BOOST_CHECK(TestParse("::", "[::]:65535")); BOOST_CHECK(TestParse("[::]:8333", "[::]:8333")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); - BOOST_CHECK(TestParse(":::", "")); + BOOST_CHECK(TestParse(":::", "[::]:0")); } BOOST_AUTO_TEST_CASE(onioncat_test) { + // values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat - CNetAddr addr1("5wyqrzbvrdsumnok.onion"); - CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"); + CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion")); + CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca")); BOOST_CHECK(addr1 == addr2); BOOST_CHECK(addr1.IsTor()); BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion"); BOOST_CHECK(addr1.IsRoutable()); + } BOOST_AUTO_TEST_CASE(subnet_test) { - BOOST_CHECK(CSubNet("1.2.3.0/24") == CSubNet("1.2.3.0/255.255.255.0")); - BOOST_CHECK(CSubNet("1.2.3.0/24") != CSubNet("1.2.4.0/255.255.255.0")); - BOOST_CHECK(CSubNet("1.2.3.0/24").Match(CNetAddr("1.2.3.4"))); - BOOST_CHECK(!CSubNet("1.2.2.0/24").Match(CNetAddr("1.2.3.4"))); - BOOST_CHECK(CSubNet("1.2.3.4").Match(CNetAddr("1.2.3.4"))); - BOOST_CHECK(CSubNet("1.2.3.4/32").Match(CNetAddr("1.2.3.4"))); - BOOST_CHECK(!CSubNet("1.2.3.4").Match(CNetAddr("5.6.7.8"))); - BOOST_CHECK(!CSubNet("1.2.3.4/32").Match(CNetAddr("5.6.7.8"))); - BOOST_CHECK(CSubNet("::ffff:127.0.0.1").Match(CNetAddr("127.0.0.1"))); - BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8"))); - BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9"))); - BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); - BOOST_CHECK(CSubNet("192.168.0.1/24").Match(CNetAddr("192.168.0.2"))); - BOOST_CHECK(CSubNet("192.168.0.20/29").Match(CNetAddr("192.168.0.18"))); - BOOST_CHECK(CSubNet("1.2.2.1/24").Match(CNetAddr("1.2.2.4"))); - BOOST_CHECK(CSubNet("1.2.2.110/31").Match(CNetAddr("1.2.2.111"))); - BOOST_CHECK(CSubNet("1.2.2.20/26").Match(CNetAddr("1.2.2.63"))); + + BOOST_CHECK(ResolveSubNet("1.2.3.0/24") == ResolveSubNet("1.2.3.0/255.255.255.0")); + BOOST_CHECK(ResolveSubNet("1.2.3.0/24") != ResolveSubNet("1.2.4.0/255.255.255.0")); + BOOST_CHECK(ResolveSubNet("1.2.3.0/24").Match(ResolveIP("1.2.3.4"))); + BOOST_CHECK(!ResolveSubNet("1.2.2.0/24").Match(ResolveIP("1.2.3.4"))); + BOOST_CHECK(ResolveSubNet("1.2.3.4").Match(ResolveIP("1.2.3.4"))); + BOOST_CHECK(ResolveSubNet("1.2.3.4/32").Match(ResolveIP("1.2.3.4"))); + BOOST_CHECK(!ResolveSubNet("1.2.3.4").Match(ResolveIP("5.6.7.8"))); + BOOST_CHECK(!ResolveSubNet("1.2.3.4/32").Match(ResolveIP("5.6.7.8"))); + BOOST_CHECK(ResolveSubNet("::ffff:127.0.0.1").Match(ResolveIP("127.0.0.1"))); + BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:0/112").Match(ResolveIP("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(ResolveSubNet("192.168.0.1/24").Match(ResolveIP("192.168.0.2"))); + BOOST_CHECK(ResolveSubNet("192.168.0.20/29").Match(ResolveIP("192.168.0.18"))); + BOOST_CHECK(ResolveSubNet("1.2.2.1/24").Match(ResolveIP("1.2.2.4"))); + BOOST_CHECK(ResolveSubNet("1.2.2.110/31").Match(ResolveIP("1.2.2.111"))); + BOOST_CHECK(ResolveSubNet("1.2.2.20/26").Match(ResolveIP("1.2.2.63"))); // All-Matching IPv6 Matches arbitrary IPv4 and IPv6 - BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); - BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4"))); + BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1.2.3.4"))); // All-Matching IPv4 does not Match IPv6 - BOOST_CHECK(!CSubNet("0.0.0.0/0").Match(CNetAddr("1:2:3:4:5:6:7:1234"))); + BOOST_CHECK(!ResolveSubNet("0.0.0.0/0").Match(ResolveIP("1:2:3:4:5:6:7:1234"))); // Invalid subnets Match nothing (not even invalid addresses) - BOOST_CHECK(!CSubNet().Match(CNetAddr("1.2.3.4"))); - BOOST_CHECK(!CSubNet("").Match(CNetAddr("4.5.6.7"))); - BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("0.0.0.0"))); - BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("hab"))); + BOOST_CHECK(!CSubNet().Match(ResolveIP("1.2.3.4"))); + BOOST_CHECK(!ResolveSubNet("").Match(ResolveIP("4.5.6.7"))); + BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("0.0.0.0"))); + BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("hab"))); // Check valid/invalid - BOOST_CHECK(CSubNet("1.2.3.0/0").IsValid()); - BOOST_CHECK(!CSubNet("1.2.3.0/-1").IsValid()); - BOOST_CHECK(CSubNet("1.2.3.0/32").IsValid()); - BOOST_CHECK(!CSubNet("1.2.3.0/33").IsValid()); - BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/0").IsValid()); - BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/33").IsValid()); - BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/-1").IsValid()); - 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()); + BOOST_CHECK(ResolveSubNet("1.2.3.0/0").IsValid()); + BOOST_CHECK(!ResolveSubNet("1.2.3.0/-1").IsValid()); + BOOST_CHECK(ResolveSubNet("1.2.3.0/32").IsValid()); + BOOST_CHECK(!ResolveSubNet("1.2.3.0/33").IsValid()); + BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/0").IsValid()); + BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/33").IsValid()); + BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/-1").IsValid()); + BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/128").IsValid()); + BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/129").IsValid()); + BOOST_CHECK(!ResolveSubNet("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/32"); + BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).IsValid()); + BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.1"))); + BOOST_CHECK(!CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.2"))); + BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).ToString() == "127.0.0.1/32"); - 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/128"); + CSubNet subnet = CSubNet(ResolveIP("1.2.3.4"), 32); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); + subnet = CSubNet(ResolveIP("1.2.3.4"), 8); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); + subnet = CSubNet(ResolveIP("1.2.3.4"), 0); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); - CSubNet subnet = CSubNet("1.2.3.4/255.255.255.255"); + subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.255.255.255")); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); - subnet = CSubNet("1.2.3.4/255.255.255.254"); + subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.0.0.0")); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); + subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("0.0.0.0")); + BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); + + BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).IsValid()); + BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128"); + + subnet = ResolveSubNet("1.2.3.4/255.255.255.255"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.254"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31"); - subnet = CSubNet("1.2.3.4/255.255.255.252"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.252"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30"); - subnet = CSubNet("1.2.3.4/255.255.255.248"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.248"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29"); - subnet = CSubNet("1.2.3.4/255.255.255.240"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.240"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28"); - subnet = CSubNet("1.2.3.4/255.255.255.224"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.224"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27"); - subnet = CSubNet("1.2.3.4/255.255.255.192"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.192"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26"); - subnet = CSubNet("1.2.3.4/255.255.255.128"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.128"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25"); - subnet = CSubNet("1.2.3.4/255.255.255.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.255.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24"); - subnet = CSubNet("1.2.3.4/255.255.254.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.254.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23"); - subnet = CSubNet("1.2.3.4/255.255.252.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.252.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22"); - subnet = CSubNet("1.2.3.4/255.255.248.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.248.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21"); - subnet = CSubNet("1.2.3.4/255.255.240.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.240.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20"); - subnet = CSubNet("1.2.3.4/255.255.224.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.224.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19"); - subnet = CSubNet("1.2.3.4/255.255.192.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.192.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18"); - subnet = CSubNet("1.2.3.4/255.255.128.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.128.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17"); - subnet = CSubNet("1.2.3.4/255.255.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16"); - subnet = CSubNet("1.2.3.4/255.254.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.254.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15"); - subnet = CSubNet("1.2.3.4/255.252.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.252.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14"); - subnet = CSubNet("1.2.3.4/255.248.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.248.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13"); - subnet = CSubNet("1.2.3.4/255.240.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.240.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12"); - subnet = CSubNet("1.2.3.4/255.224.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.224.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11"); - subnet = CSubNet("1.2.3.4/255.192.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.192.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10"); - subnet = CSubNet("1.2.3.4/255.128.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.128.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9"); - subnet = CSubNet("1.2.3.4/255.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/255.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); - subnet = CSubNet("1.2.3.4/254.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/254.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7"); - subnet = CSubNet("1.2.3.4/252.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/252.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6"); - subnet = CSubNet("1.2.3.4/248.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/248.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5"); - subnet = CSubNet("1.2.3.4/240.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/240.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4"); - subnet = CSubNet("1.2.3.4/224.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/224.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3"); - subnet = CSubNet("1.2.3.4/192.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/192.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2"); - subnet = CSubNet("1.2.3.4/128.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/128.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1"); - subnet = CSubNet("1.2.3.4/0.0.0.0"); + subnet = ResolveSubNet("1.2.3.4/0.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); - subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128"); - subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000"); + subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000"); BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16"); - subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000"); + subnet = ResolveSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000"); BOOST_CHECK_EQUAL(subnet.ToString(), "::/0"); - subnet = CSubNet("1.2.3.4/255.255.232.0"); + subnet = ResolveSubNet("1.2.3.4/255.255.232.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0"); - subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); + subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); + } BOOST_AUTO_TEST_CASE(netbase_getgroup) { - BOOST_CHECK(CNetAddr("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable() - BOOST_CHECK(CNetAddr("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable() - BOOST_CHECK(CNetAddr("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable() - BOOST_CHECK(CNetAddr("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable() - BOOST_CHECK(CNetAddr("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4 - BOOST_CHECK(CNetAddr("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6145 - BOOST_CHECK(CNetAddr("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6052 - BOOST_CHECK(CNetAddr("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC3964 - BOOST_CHECK(CNetAddr("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC4380 - BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == boost::assign::list_of((unsigned char)NET_TOR)(239)); // Tor - BOOST_CHECK(CNetAddr("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(4)(112)(175)); //he.net - BOOST_CHECK(CNetAddr("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); //IPv6 + + BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable() + BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable() + BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable() + BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable() + BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4 + BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6145 + BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6052 + BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC3964 + BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC4380 + BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == boost::assign::list_of((unsigned char)NET_TOR)(239)); // Tor + BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(4)(112)(175)); //he.net + BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); //IPv6 + } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 8dea38833..e8a63ae60 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -84,7 +84,7 @@ ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction * and witness such that spendingTx spends output zero of creationTx. * Also inserts creationTx's output into the coins view. */ -void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CTxinWitness& witness) +void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CTxInWitness& witness) { creationTx.nVersion = 1; creationTx.vin.resize(1); @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) // Do not use a valid signature to avoid using wallet operations. CScript scriptSig = CScript() << OP_0 << OP_0; - BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxinWitness()); + BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxInWitness()); // Legacy counting only includes signature operations in scriptSigs and scriptPubKeys // of a transaction and does not take the actual executed sig operations into account. // spendingTx in itself does not contain a signature operation. @@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript); - BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxinWitness()); + BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxInWitness()); assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2 * WITNESS_SCALE_FACTOR); assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY); } @@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript p2pk = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; CScript scriptPubKey = GetScriptForWitness(p2pk); CScript scriptSig = CScript(); - CTxinWitness witness; + CTxInWitness witness; CScriptWitness scriptWitness; scriptWitness.stack.push_back(vector<unsigned char>(0)); scriptWitness.stack.push_back(vector<unsigned char>(0)); @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript scriptSig = GetScriptForWitness(p2pk); CScript scriptPubKey = GetScriptForDestination(CScriptID(scriptSig)); scriptSig = CScript() << ToByteVector(scriptSig); - CTxinWitness witness; + CTxInWitness witness; CScriptWitness scriptWitness; scriptWitness.stack.push_back(vector<unsigned char>(0)); scriptWitness.stack.push_back(vector<unsigned char>(0)); @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; CScript scriptPubKey = GetScriptForWitness(witnessScript); CScript scriptSig = CScript(); - CTxinWitness witness; + CTxInWitness witness; CScriptWitness scriptWitness; scriptWitness.stack.push_back(vector<unsigned char>(0)); scriptWitness.stack.push_back(vector<unsigned char>(0)); @@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) CScript redeemScript = GetScriptForWitness(witnessScript); CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); CScript scriptSig = CScript() << ToByteVector(redeemScript); - CTxinWitness witness; + CTxInWitness witness; CScriptWitness scriptWitness; scriptWitness.stack.push_back(vector<unsigned char>(0)); scriptWitness.stack.push_back(vector<unsigned char>(0)); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 856f9b842..056f2982c 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -60,6 +60,11 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); InitBlockIndex(chainparams); + { + CValidationState state; + bool ok = ActivateBestChain(state, chainparams); + BOOST_CHECK(ok); + } nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); diff --git a/src/timedata.cpp b/src/timedata.cpp index b6bcf86fb..25fc49412 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -8,7 +8,7 @@ #include "timedata.h" -#include "netbase.h" +#include "netaddress.h" #include "sync.h" #include "ui_interface.h" #include "util.h" diff --git a/src/tinyformat.h b/src/tinyformat.h index c6ec0419b..17f0360c4 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -67,7 +67,9 @@ // weekday, month, day, hour, min); // std::cout << date; // -// These are the three primary interface functions. +// These are the three primary interface functions. There is also a +// convenience function printfln() which appends a newline to the usual result +// of printf() for super simple logging. // // // User defined format functions @@ -86,6 +88,18 @@ // defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an // example, see the implementation of printf() at the end of the source file. // +// Sometimes it's useful to be able to pass a list of format arguments through +// to a non-template function. The FormatList class is provided as a way to do +// this by storing the argument list in a type-opaque way. Continuing the +// example from above, we construct a FormatList using makeFormatList(): +// +// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min); +// +// The format list can now be passed into any non-template function and used +// via a call to the vformat() function: +// +// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList); +// // // Additional API information // -------------------------- @@ -118,6 +132,7 @@ namespace tfm = tinyformat; //------------------------------------------------------------------------------ // Implementation details. +#include <algorithm> #include <cassert> #include <iostream> #include <sstream> @@ -133,20 +148,20 @@ namespace tfm = tinyformat; # endif #endif -#ifdef __GNUC__ -# define TINYFORMAT_NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) -# define TINYFORMAT_NOINLINE __declspec(noinline) -#else -# define TINYFORMAT_NOINLINE -#endif - #if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201 // std::showpos is broken on old libstdc++ as provided with OSX. See // http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html # define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND #endif +#ifdef __APPLE__ +// Workaround OSX linker warning: xcode uses different default symbol +// visibilities for static libs vs executables (see issue #25) +# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden"))) +#else +# define TINYFORMAT_HIDDEN +#endif + namespace tinyformat { //------------------------------------------------------------------------------ @@ -247,6 +262,29 @@ struct convertToInt<T,true> static int invoke(const T& value) { return static_cast<int>(value); } }; +// Format at most ntrunc characters to the given stream. +template<typename T> +inline void formatTruncated(std::ostream& out, const T& value, int ntrunc) +{ + std::ostringstream tmp; + tmp << value; + std::string result = tmp.str(); + out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size()))); +} +#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \ +inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \ +{ \ + std::streamsize len = 0; \ + while(len < ntrunc && value[len] != 0) \ + ++len; \ + out.write(value, len); \ +} +// Overload for const char* and char*. Could overload for signed & unsigned +// char too, but these are technically unneeded for printf compatibility. +TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char) +TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char) +#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR + } // namespace detail @@ -255,18 +293,20 @@ struct convertToInt<T,true> // desired. -// Format a value into a stream. Called from format() for all types by default. -// -// Users may override this for their own types. When this function is called, -// the stream flags will have been modified according to the format string. -// The format specification is provided in the range [fmtBegin, fmtEnd). -// -// By default, formatValue() uses the usual stream insertion operator -// operator<< to format the type T, with special cases for the %c and %p -// conversions. +/// Format a value into a stream, delegating to operator<< by default. +/// +/// Users may override this for their own types. When this function is called, +/// the stream flags will have been modified according to the format string. +/// The format specification is provided in the range [fmtBegin, fmtEnd). For +/// truncating conversions, ntrunc is set to the desired maximum number of +/// characters, for example "%.7s" calls formatValue with ntrunc = 7. +/// +/// By default, formatValue() uses the usual stream insertion operator +/// operator<< to format the type T, with special cases for the %c and %p +/// conversions. template<typename T> inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, - const char* fmtEnd, const T& value) + const char* fmtEnd, int ntrunc, const T& value) { #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS // Since we don't support printing of wchar_t using "%ls", make it fail at @@ -288,6 +328,12 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND else if(detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/; #endif + else if(ntrunc >= 0) + { + // Take care not to overread C strings in truncating conversions like + // "%.4s" where at most 4 characters may be read. + detail::formatTruncated(out, value, ntrunc); + } else out << value; } @@ -296,7 +342,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, // Overloaded version for char types to support printing as an integer #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \ - const char* fmtEnd, charType value) \ + const char* fmtEnd, int /**/, charType value) \ { \ switch(*(fmtEnd-1)) \ { \ @@ -435,225 +481,91 @@ cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' + namespace detail { -// Class holding current position in format string and an output stream into -// which arguments are formatted. -class FormatIterator +// Type-opaque holder for an argument to format(), with associated actions on +// the type held as explicit function pointers. This allows FormatArg's for +// each argument to be allocated as a homogenous array inside FormatList +// whereas a naive implementation based on inheritance does not. +class FormatArg { public: - // Flags for features not representable with standard stream state - enum ExtraFormatFlags - { - Flag_None = 0, - Flag_TruncateToPrecision = 1<<0, // truncate length to stream precision() - Flag_SpacePadPositive = 1<<1, // pad positive values with spaces - Flag_VariableWidth = 1<<2, // variable field width in arg list - Flag_VariablePrecision = 1<<3 // variable field precision in arg list - }; - - // out is the output stream, fmt is the full format string - FormatIterator(std::ostream& out, const char* fmt) - : m_out(out), - m_fmt(fmt), - m_extraFlags(Flag_None), - m_wantWidth(false), - m_wantPrecision(false), - m_variableWidth(0), - m_variablePrecision(0), - m_origWidth(out.width()), - m_origPrecision(out.precision()), - m_origFlags(out.flags()), - m_origFill(out.fill()) + FormatArg() {} + + template<typename T> + FormatArg(const T& value) + : m_value(static_cast<const void*>(&value)), + m_formatImpl(&formatImpl<T>), + m_toIntImpl(&toIntImpl<T>) { } - // Print remaining part of format string. - void finish() + void format(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc) const { - // It would be nice if we could do this from the destructor, but we - // can't if TINFORMAT_ERROR is used to throw an exception! - m_fmt = printFormatStringLiteral(m_out, m_fmt); - if(*m_fmt != '\0') - TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); + m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value); } - ~FormatIterator() + int toInt() const { - // Restore stream state - m_out.width(m_origWidth); - m_out.precision(m_origPrecision); - m_out.flags(m_origFlags); - m_out.fill(m_origFill); + return m_toIntImpl(m_value); } - template<typename T> - void accept(const T& value); - private: - // Parse and return an integer from the string c, as atoi() - // On return, c is set to one past the end of the integer. - static int parseIntAndAdvance(const char*& c) + template<typename T> + TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc, const void* value) { - int i = 0; - for(;*c >= '0' && *c <= '9'; ++c) - i = 10*i + (*c - '0'); - return i; + formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value)); } - // Format at most truncLen characters of a C string to the given - // stream. Return true if formatting proceeded (generic version always - // returns false) template<typename T> - static bool formatCStringTruncate(std::ostream& /*out*/, const T& /*value*/, - std::streamsize /*truncLen*/) + TINYFORMAT_HIDDEN static int toIntImpl(const void* value) { - return false; - } -# define TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(type) \ - static bool formatCStringTruncate(std::ostream& out, type* value, \ - std::streamsize truncLen) \ - { \ - std::streamsize len = 0; \ - while(len < truncLen && value[len] != 0) \ - ++len; \ - out.write(value, len); \ - return true; \ - } - // Overload for const char* and char*. Could overload for signed & - // unsigned char too, but these are technically unneeded for printf - // compatibility. - TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(const char) - TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(char) -# undef TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE - - // Print literal part of format string and return next format spec - // position. - // - // Skips over any occurrences of '%%', printing a literal '%' to the - // output. The position of the first % character of the next - // nontrivial format spec is returned, or the end of string. - static const char* printFormatStringLiteral(std::ostream& out, - const char* fmt) - { - const char* c = fmt; - for(; true; ++c) - { - switch(*c) - { - case '\0': - out.write(fmt, static_cast<std::streamsize>(c - fmt)); - return c; - case '%': - out.write(fmt, static_cast<std::streamsize>(c - fmt)); - if(*(c+1) != '%') - return c; - // for "%%", tack trailing % onto next literal section. - fmt = ++c; - break; - } - } + return convertToInt<T>::invoke(*static_cast<const T*>(value)); } - static const char* streamStateFromFormat(std::ostream& out, - unsigned int& extraFlags, - const char* fmtStart, - int variableWidth, - int variablePrecision); - - // Private copy & assign: Kill gcc warnings with -Weffc++ - FormatIterator(const FormatIterator&); - FormatIterator& operator=(const FormatIterator&); - - // Stream, current format string & state - std::ostream& m_out; - const char* m_fmt; - unsigned int m_extraFlags; - // State machine info for handling of variable width & precision - bool m_wantWidth; - bool m_wantPrecision; - int m_variableWidth; - int m_variablePrecision; - // Saved stream state - std::streamsize m_origWidth; - std::streamsize m_origPrecision; - std::ios::fmtflags m_origFlags; - char m_origFill; + const void* m_value; + void (*m_formatImpl)(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc, const void* value); + int (*m_toIntImpl)(const void* value); }; -// Accept a value for formatting into the internal stream. -template<typename T> -TINYFORMAT_NOINLINE // < greatly reduces bloat in optimized builds -void FormatIterator::accept(const T& value) +// Parse and return an integer from the string c, as atoi() +// On return, c is set to one past the end of the integer. +inline int parseIntAndAdvance(const char*& c) { - // Parse the format string - const char* fmtEnd = 0; - if(m_extraFlags == Flag_None && !m_wantWidth && !m_wantPrecision) - { - m_fmt = printFormatStringLiteral(m_out, m_fmt); - fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, 0, 0); - m_wantWidth = (m_extraFlags & Flag_VariableWidth) != 0; - m_wantPrecision = (m_extraFlags & Flag_VariablePrecision) != 0; - } - // Consume value as variable width and precision specifier if necessary - if(m_extraFlags & (Flag_VariableWidth | Flag_VariablePrecision)) - { - if(m_wantWidth || m_wantPrecision) - { - int v = convertToInt<T>::invoke(value); - if(m_wantWidth) - { - m_variableWidth = v; - m_wantWidth = false; - } - else if(m_wantPrecision) - { - m_variablePrecision = v; - m_wantPrecision = false; - } - return; - } - // If we get here, we've set both the variable precision and width as - // required and we need to rerun the stream state setup to insert these. - fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, - m_variableWidth, m_variablePrecision); - } + int i = 0; + for(;*c >= '0' && *c <= '9'; ++c) + i = 10*i + (*c - '0'); + return i; +} - // Format the value into the stream. - if(!(m_extraFlags & (Flag_SpacePadPositive | Flag_TruncateToPrecision))) - formatValue(m_out, m_fmt, fmtEnd, value); - else +// Print literal part of format string and return next format spec +// position. +// +// Skips over any occurrences of '%%', printing a literal '%' to the +// output. The position of the first % character of the next +// nontrivial format spec is returned, or the end of string. +inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt) +{ + const char* c = fmt; + for(;; ++c) { - // The following are special cases where there's no direct - // correspondence between stream formatting and the printf() behaviour. - // Instead, we simulate the behaviour crudely by formatting into a - // temporary string stream and munging the resulting string. - std::ostringstream tmpStream; - tmpStream.copyfmt(m_out); - if(m_extraFlags & Flag_SpacePadPositive) - tmpStream.setf(std::ios::showpos); - // formatCStringTruncate is required for truncating conversions like - // "%.4s" where at most 4 characters of the c-string should be read. - // If we didn't include this special case, we might read off the end. - if(!( (m_extraFlags & Flag_TruncateToPrecision) && - formatCStringTruncate(tmpStream, value, m_out.precision()) )) - { - // Not a truncated c-string; just format normally. - formatValue(tmpStream, m_fmt, fmtEnd, value); - } - std::string result = tmpStream.str(); // allocates... yuck. - if(m_extraFlags & Flag_SpacePadPositive) + switch(*c) { - for(size_t i = 0, iend = result.size(); i < iend; ++i) - if(result[i] == '+') - result[i] = ' '; + case '\0': + out.write(fmt, c - fmt); + return c; + case '%': + out.write(fmt, c - fmt); + if(*(c+1) != '%') + return c; + // for "%%", tack trailing % onto next literal section. + fmt = ++c; + break; + default: + break; } - if((m_extraFlags & Flag_TruncateToPrecision) && - (int)result.size() > (int)m_out.precision()) - m_out.write(result.c_str(), m_out.precision()); - else - m_out << result; } - m_extraFlags = Flag_None; - m_fmt = fmtEnd; } @@ -663,13 +575,14 @@ void FormatIterator::accept(const T& value) // with the form "%[flags][width][.precision][length]type". // // Formatting options which can't be natively represented using the ostream -// state are returned in the extraFlags parameter which is a bitwise -// combination of values from the ExtraFormatFlags enum. -inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, - unsigned int& extraFlags, - const char* fmtStart, - int variableWidth, - int variablePrecision) +// state are returned in spacePadPositive (for space padded positive numbers) +// and ntrunc (for truncating conversions). argIndex is incremented if +// necessary to pull out variable width and precision . The function returns a +// pointer to the character after the end of the current format spec. +inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive, + int& ntrunc, const char* fmtStart, + const detail::FormatArg* formatters, + int& argIndex, int numFormatters) { if(*fmtStart != '%') { @@ -684,9 +597,9 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, out.unsetf(std::ios::adjustfield | std::ios::basefield | std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | std::ios::showpoint | std::ios::showpos | std::ios::uppercase); - extraFlags = Flag_None; bool precisionSet = false; bool widthSet = false; + int widthExtra = 0; const char* c = fmtStart + 1; // 1) Parse flags for(;; ++c) @@ -713,12 +626,15 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, case ' ': // overridden by show positive sign, '+' flag. if(!(out.flags() & std::ios::showpos)) - extraFlags |= Flag_SpacePadPositive; + spacePadPositive = true; continue; case '+': out.setf(std::ios::showpos); - extraFlags &= ~Flag_SpacePadPositive; + spacePadPositive = false; + widthExtra = 1; continue; + default: + break; } break; } @@ -731,15 +647,19 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, if(*c == '*') { widthSet = true; - if(variableWidth < 0) + int width = 0; + if(argIndex < numFormatters) + width = formatters[argIndex++].toInt(); + else + TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width"); + if(width < 0) { // negative widths correspond to '-' flag set out.fill(' '); out.setf(std::ios::left, std::ios::adjustfield); - variableWidth = -variableWidth; + width = -width; } - out.width(variableWidth); - extraFlags |= Flag_VariableWidth; + out.width(width); ++c; } // 3) Parse precision @@ -750,8 +670,10 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, if(*c == '*') { ++c; - extraFlags |= Flag_VariablePrecision; - precision = variablePrecision; + if(argIndex < numFormatters) + precision = formatters[argIndex++].toInt(); + else + TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision"); } else { @@ -814,7 +736,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, break; case 's': if(precisionSet) - extraFlags |= Flag_TruncateToPrecision; + ntrunc = static_cast<int>(out.precision()); // Make %s print booleans as "true" and "false" out.setf(std::ios::boolalpha); break; @@ -826,6 +748,8 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly " "terminated by end of string"); return c; + default: + break; } if(intConversion && precisionSet && !widthSet) { @@ -833,7 +757,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, // padded with zeros on the left). This isn't really supported by the // iostreams, but we can approximately simulate it with the width if // the width isn't otherwise used. - out.width(out.precision()); + out.width(out.precision() + widthExtra); out.setf(std::ios::internal, std::ios::adjustfield); out.fill('0'); } @@ -841,170 +765,282 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, } - //------------------------------------------------------------------------------ -// Private format function on top of which the public interface is implemented. -// We enforce a mimimum of one value to be formatted to prevent bugs looking like -// -// const char* myStr = "100% broken"; -// printf(myStr); // Parses % as a format specifier -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - -template<typename T1> -void format(FormatIterator& fmtIter, const T1& value1) +inline void formatImpl(std::ostream& out, const char* fmt, + const detail::FormatArg* formatters, + int numFormatters) { - fmtIter.accept(value1); - fmtIter.finish(); + // Saved stream state + std::streamsize origWidth = out.width(); + std::streamsize origPrecision = out.precision(); + std::ios::fmtflags origFlags = out.flags(); + char origFill = out.fill(); + + for (int argIndex = 0; argIndex < numFormatters; ++argIndex) + { + // Parse the format string + fmt = printFormatStringLiteral(out, fmt); + bool spacePadPositive = false; + int ntrunc = -1; + const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt, + formatters, argIndex, numFormatters); + if (argIndex >= numFormatters) + { + // Check args remain after reading any variable width/precision + TINYFORMAT_ERROR("tinyformat: Not enough format arguments"); + return; + } + const FormatArg& arg = formatters[argIndex]; + // Format the arg into the stream. + if(!spacePadPositive) + arg.format(out, fmt, fmtEnd, ntrunc); + else + { + // The following is a special case with no direct correspondence + // between stream formatting and the printf() behaviour. Simulate + // it crudely by formatting into a temporary string stream and + // munging the resulting string. + std::ostringstream tmpStream; + tmpStream.copyfmt(out); + tmpStream.setf(std::ios::showpos); + arg.format(tmpStream, fmt, fmtEnd, ntrunc); + std::string result = tmpStream.str(); // allocates... yuck. + for(size_t i = 0, iend = result.size(); i < iend; ++i) + if(result[i] == '+') result[i] = ' '; + out << result; + } + fmt = fmtEnd; + } + + // Print remaining part of format string. + fmt = printFormatStringLiteral(out, fmt); + if(*fmt != '\0') + TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); + + // Restore stream state + out.width(origWidth); + out.precision(origPrecision); + out.flags(origFlags); + out.fill(origFill); } -// General version for C++11 -template<typename T1, typename... Args> -void format(FormatIterator& fmtIter, const T1& value1, const Args&... args) +} // namespace detail + + +/// List of template arguments format(), held in a type-opaque way. +/// +/// A const reference to FormatList (typedef'd as FormatListRef) may be +/// conveniently used to pass arguments to non-template functions: All type +/// information has been stripped from the arguments, leaving just enough of a +/// common interface to perform formatting as required. +class FormatList { - fmtIter.accept(value1); - format(fmtIter, args...); -} + public: + FormatList(detail::FormatArg* formatters, int N) + : m_formatters(formatters), m_N(N) { } -#else + friend void vformat(std::ostream& out, const char* fmt, + const FormatList& list); -inline void format(FormatIterator& fmtIter) + private: + const detail::FormatArg* m_formatters; + int m_N; +}; + +/// Reference to type-opaque format list for passing to vformat() +typedef const FormatList& FormatListRef; + + +namespace detail { + +// Format list subclass with fixed storage to avoid dynamic allocation +template<int N> +class FormatListN : public FormatList { - fmtIter.finish(); -} + public: +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + template<typename... Args> + FormatListN(const Args&... args) + : FormatList(&m_formatterStore[0], N), + m_formatterStore { FormatArg(args)... } + { static_assert(sizeof...(args) == N, "Number of args must be N"); } +#else // C++98 version + void init(int) {} +# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \ + \ + template<TINYFORMAT_ARGTYPES(n)> \ + FormatListN(TINYFORMAT_VARARGS(n)) \ + : FormatList(&m_formatterStore[0], n) \ + { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \ + \ + template<TINYFORMAT_ARGTYPES(n)> \ + void init(int i, TINYFORMAT_VARARGS(n)) \ + { \ + m_formatterStore[i] = FormatArg(v1); \ + init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \ + } -// General version for C++98 -#define TINYFORMAT_MAKE_FORMAT_DETAIL(n) \ -template<TINYFORMAT_ARGTYPES(n)> \ -void format(detail::FormatIterator& fmtIter, TINYFORMAT_VARARGS(n)) \ -{ \ - fmtIter.accept(v1); \ - format(fmtIter TINYFORMAT_PASSARGS_TAIL(n)); \ -} + TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR) +# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR +#endif -TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_DETAIL) -#undef TINYFORMAT_MAKE_FORMAT_DETAIL + private: + FormatArg m_formatterStore[N]; +}; -#endif // End C++98 variadic template emulation for format() +// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard +template<> class FormatListN<0> : public FormatList +{ + public: FormatListN() : FormatList(0, 0) {} +}; } // namespace detail //------------------------------------------------------------------------------ -// Implement all the main interface functions here in terms of detail::format() +// Primary API functions #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES -// C++11 - the simple case -template<typename T1, typename... Args> -void format(std::ostream& out, const char* fmt, const T1& v1, const Args&... args) +/// Make type-agnostic format list from list of template arguments. +/// +/// The exact return type of this function is an implementation detail and +/// shouldn't be relied upon. Instead it should be stored as a FormatListRef: +/// +/// FormatListRef formatList = makeFormatList( /*...*/ ); +template<typename... Args> +detail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args) { - detail::FormatIterator fmtIter(out, fmt); - format(fmtIter, v1, args...); + return detail::FormatListN<sizeof...(args)>(args...); } -template<typename T1, typename... Args> -std::string format(const char* fmt, const T1& v1, const Args&... args) +#else // C++98 version + +inline detail::FormatListN<0> makeFormatList() +{ + return detail::FormatListN<0>(); +} +#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \ +template<TINYFORMAT_ARGTYPES(n)> \ +detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) \ +{ \ + return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n)); \ +} +TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST) +#undef TINYFORMAT_MAKE_MAKEFORMATLIST + +#endif + +/// Format list of arguments to the stream according to the given format string. +/// +/// The name vformat() is chosen for the semantic similarity to vprintf(): the +/// list of format arguments is held in a single function argument. +inline void vformat(std::ostream& out, const char* fmt, FormatListRef list) +{ + detail::formatImpl(out, fmt, list.m_formatters, list.m_N); +} + + +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + +/// Format list of arguments to the stream according to given format string. +template<typename... Args> +void format(std::ostream& out, const char* fmt, const Args&... args) +{ + vformat(out, fmt, makeFormatList(args...)); +} + +/// Format list of arguments according to the given format string and return +/// the result as a string. +template<typename... Args> +std::string format(const char* fmt, const Args&... args) { std::ostringstream oss; - format(oss, fmt, v1, args...); + format(oss, fmt, args...); return oss.str(); } -template<typename T1, typename... Args> -std::string format(const std::string &fmt, const T1& v1, const Args&... args) +/// Format list of arguments to std::cout, according to the given format string +template<typename... Args> +void printf(const char* fmt, const Args&... args) +{ + format(std::cout, fmt, args...); +} + +template<typename... Args> +void printfln(const char* fmt, const Args&... args) +{ + format(std::cout, fmt, args...); + std::cout << '\n'; +} + +#else // C++98 version + +inline void format(std::ostream& out, const char* fmt) +{ + vformat(out, fmt, makeFormatList()); +} + +inline std::string format(const char* fmt) { std::ostringstream oss; - format(oss, fmt.c_str(), v1, args...); + format(oss, fmt); return oss.str(); } -template<typename T1, typename... Args> -void printf(const char* fmt, const T1& v1, const Args&... args) +inline void printf(const char* fmt) { - format(std::cout, fmt, v1, args...); + format(std::cout, fmt); } -#else +inline void printfln(const char* fmt) +{ + format(std::cout, fmt); + std::cout << '\n'; +} -// C++98 - define the interface functions using the wrapping macros #define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ \ template<TINYFORMAT_ARGTYPES(n)> \ void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \ { \ - tinyformat::detail::FormatIterator fmtIter(out, fmt); \ - tinyformat::detail::format(fmtIter, TINYFORMAT_PASSARGS(n)); \ + vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \ } \ \ template<TINYFORMAT_ARGTYPES(n)> \ std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \ { \ std::ostringstream oss; \ - tinyformat::format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ + format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ return oss.str(); \ } \ \ template<TINYFORMAT_ARGTYPES(n)> \ -std::string format(const std::string &fmt, TINYFORMAT_VARARGS(n)) \ +void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ { \ - std::ostringstream oss; \ - tinyformat::format(oss, fmt.c_str(), TINYFORMAT_PASSARGS(n)); \ - return oss.str(); \ + format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ } \ \ template<TINYFORMAT_ARGTYPES(n)> \ -void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ +void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \ { \ - tinyformat::format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ + format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ + std::cout << '\n'; \ } TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) #undef TINYFORMAT_MAKE_FORMAT_FUNCS -#endif - -//------------------------------------------------------------------------------ -// Define deprecated wrapping macro for backward compatibility in tinyformat -// 1.x. Will be removed in version 2! -#define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS -#define TINYFORMAT_WRAP_FORMAT_N(n, returnType, funcName, funcDeclSuffix, \ - bodyPrefix, streamName, bodySuffix) \ -template<TINYFORMAT_ARGTYPES(n)> \ -returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt, \ - TINYFORMAT_VARARGS(n)) funcDeclSuffix \ -{ \ - bodyPrefix \ - tinyformat::format(streamName, fmt, TINYFORMAT_PASSARGS(n)); \ - bodySuffix \ -} \ - -#define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix, \ - bodyPrefix, streamName, bodySuffix) \ -inline \ -returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \ - ) funcDeclSuffix \ -{ \ - bodyPrefix \ - tinyformat::detail::FormatIterator(streamName, fmt).finish(); \ - bodySuffix \ -} \ -TINYFORMAT_WRAP_FORMAT_N(1 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(2 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(3 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(4 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(5 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(6 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(7 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(8 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(9 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(10, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(11, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(12, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(13, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(14, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(15, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ -TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +#endif +// Added for Bitcoin Core +template<typename... Args> +std::string format(const std::string &fmt, const Args&... args) +{ + std::ostringstream oss; + format(oss, fmt.c_str(), args...); + return oss.str(); +} } // namespace tinyformat diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 0d6b65567..99c45d489 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -4,6 +4,7 @@ #include "torcontrol.h" #include "utilstrencodings.h" +#include "netbase.h" #include "net.h" #include "util.h" #include "crypto/hmac_sha256.h" @@ -437,8 +438,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep if ((i = m.find("PrivateKey")) != m.end()) private_key = i->second; } - - service = CService(service_id+".onion", GetListenPort()); + service = LookupNumeric(std::string(service_id+".onion").c_str(), GetListenPort()); LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); @@ -462,7 +462,8 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. if (GetArg("-onion", "") == "") { - proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); + CService resolved(LookupNumeric("127.0.0.1", 9050)); + proxyType addrOnion = proxyType(resolved, true); SetProxy(NET_TOR, addrOnion); SetLimited(NET_TOR, false); } diff --git a/src/txdb.h b/src/txdb.h index ce3c39d7f..5b98d2792 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -22,11 +22,19 @@ class CCoinsViewDBCursor; class uint256; //! -dbcache default (MiB) -static const int64_t nDefaultDbCache = 100; -//! max. -dbcache in (MiB) +static const int64_t nDefaultDbCache = 300; +//! max. -dbcache (MiB) static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; -//! min. -dbcache in (MiB) +//! min. -dbcache (MiB) static const int64_t nMinDbCache = 4; +//! Max memory allocated to block tree DB specific cache, if no -txindex (MiB) +static const int64_t nMaxBlockDBCache = 2; +//! Max memory allocated to block tree DB specific cache, if -txindex (MiB) +// Unlike for the UTXO database, for the txindex scenario the leveldb cache make +// a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991 +static const int64_t nMaxBlockDBAndTxIndexCache = 1024; +//! Max memory allocated to coin DB specific cache (MiB) +static const int64_t nMaxCoinsDBCache = 8; struct CDiskTxPos : public CDiskBlockPos { diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a48a6d946..b631c4848 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -28,7 +28,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxCost = GetTransactionCost(_tx); + nTxWeight = GetTransactionWeight(_tx); nModSize = _tx.CalculateModifiedSize(GetTxSize()); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); @@ -75,7 +75,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) size_t CTxMemPoolEntry::GetTxSize() const { - return GetVirtualTransactionSize(nTxCost); + return GetVirtualTransactionSize(nTxWeight, sigOpCost); } // Update the given tx for any in-mempool descendants. @@ -657,6 +657,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins)); + const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); LOCK(cs); list<const CTxMemPoolEntry*> waitingOnDependants; @@ -737,7 +738,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const waitingOnDependants.push_back(&(*it)); else { CValidationState state; - assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); + bool fCheckResult = tx.IsCoinBase() || + Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight); + assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, 1000000); } } @@ -751,7 +754,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove++; assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { - assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL)); + bool fCheckResult = entry->GetTx().IsCoinBase() || + Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight); + assert(fCheckResult); UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; } diff --git a/src/txmempool.h b/src/txmempool.h index e5a500e19..2c2127f32 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -78,7 +78,7 @@ class CTxMemPoolEntry private: std::shared_ptr<const CTransaction> tx; CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups - size_t nTxCost; //!< ... and avoid recomputing tx cost (also used for GetTxSize()) + size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) size_t nModSize; //!< ... and modified size for priority size_t nUsageSize; //!< ... and total memory usage int64_t nTime; //!< Local time when entering the mempool @@ -122,7 +122,7 @@ public: double GetPriority(unsigned int currentHeight) const; const CAmount& GetFee() const { return nFee; } size_t GetTxSize() const; - size_t GetTxCost() const { return nTxCost; } + size_t GetTxWeight() const { return nTxWeight; } int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return entryHeight; } bool WasClearAtEntry() const { return hadNoDependencies; } diff --git a/src/util.h b/src/util.h index ac4b94778..39328b51e 100644 --- a/src/util.h +++ b/src/util.h @@ -77,33 +77,17 @@ int LogPrintStr(const std::string &str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) -template<typename T1, typename... Args> -static inline int LogPrint(const char* category, const char* fmt, const T1& v1, const Args&... args) +template<typename... Args> +static inline int LogPrint(const char* category, const char* fmt, const Args&... args) { if(!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(fmt, v1, args...)); + return LogPrintStr(tfm::format(fmt, args...)); } -template<typename T1, typename... Args> -bool error(const char* fmt, const T1& v1, const Args&... args) +template<typename... Args> +bool error(const char* fmt, const Args&... args) { - LogPrintStr("ERROR: " + tfm::format(fmt, v1, args...) + "\n"); - return false; -} - -/** - * Zero-arg versions of logging and error, these are not covered by - * the variadic templates above (and don't take format arguments but - * bare strings). - */ -static inline int LogPrint(const char* category, const char* s) -{ - if(!LogAcceptCategory(category)) return 0; - return LogPrintStr(s); -} -static inline bool error(const char* s) -{ - LogPrintStr(std::string("ERROR: ") + s + "\n"); + LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\n"); return false; } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 8da0c7285..cf1d6ca08 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -48,6 +48,6 @@ void UnregisterAllValidationInterfaces() { g_signals.UpdatedBlockTip.disconnect_all_slots(); } -void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) { - g_signals.SyncTransaction(tx, pindex, pblock); +void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) { + g_signals.SyncTransaction(tx, pindex, posInBlock); } diff --git a/src/validationinterface.h b/src/validationinterface.h index 01b8e4765..094b1cfe2 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -28,12 +28,12 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock = NULL); +void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock = -1); class CValidationInterface { protected: virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} - virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {} + virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -50,7 +50,7 @@ struct CMainSignals { /** Notifies listeners of updated block chain tip */ boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip; /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, const CBlock *)> SyncTransaction; + boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, int posInBlock)> SyncTransaction; /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; /** Notifies listeners of a new active block chain. */ diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d55cc68dc..fe8b53ceb 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -309,8 +309,7 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); if (pwalletMain->IsMine(tx)) { - CWalletDB walletdb(pwalletMain->strWalletFile, "r+", false); - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx, false); return NullUniValue; } @@ -602,19 +601,42 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); file << "\n"; + + // add the base58check encoded extended master if the wallet uses HD + CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; + if (!masterKeyID.IsNull()) + { + CKey key; + if (pwalletMain->GetKey(masterKeyID, key)) + { + CExtKey masterKey; + masterKey.SetMaster(key.begin(), key.size()); + + CBitcoinExtKey b58extkey; + b58extkey.SetKey(masterKey); + + file << "# extended private masterkey: " << b58extkey.ToString() << "\n\n"; + } + } for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; std::string strTime = EncodeDumpTime(it->first); std::string strAddr = CBitcoinAddress(keyid).ToString(); CKey key; if (pwalletMain->GetKey(keyid, key)) { + file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); + file << strprintf("label=%s", EncodeDumpString(pwalletMain->mapAddressBook[keyid].name)); + } else if (keyid == masterKeyID) { + file << "hdmaster=1"; } else if (setKeyPool.count(keyid)) { - file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + file << "reserve=1"; + } else if (pwalletMain->mapKeyMetadata[keyid].hdKeypath == "m") { + file << "inactivehdmaster=1"; } else { - file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + file << "change=1"; } + file << strprintf(" # addr=%s%s\n", strAddr, (pwalletMain->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwalletMain->mapKeyMetadata[keyid].hdKeypath : "")); } } file << "\n"; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8538f880f..aa0a9374c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -10,7 +10,6 @@ #include "init.h" #include "main.h" #include "net.h" -#include "netbase.h" #include "policy/rbf.h" #include "rpc/server.h" #include "timedata.h" @@ -564,8 +563,8 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); CScript scriptPubKey = GetScriptForDestination(address.Get()); - if (!IsMine(*pwalletMain,scriptPubKey)) - return (double)0.0; + if (!IsMine(*pwalletMain, scriptPubKey)) + return ValueFromAmount(0); // Minimum confirmations int nMinDepth = 1; @@ -643,7 +642,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) } } - return (double)nAmount / (double)COIN; + return ValueFromAmount(nAmount); } @@ -2081,7 +2080,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) // slack space in .dat files; that is bad if the old data is // unencrypted private keys. So: StartShutdown(); - return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; + return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup."; } UniValue lockunspent(const UniValue& params, bool fHelp) @@ -2260,15 +2259,16 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) "Returns an object containing various wallet state info.\n" "\nResult:\n" "{\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\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 " + CURRENCY_UNIT + "/kB\n" + " \"walletversion\": xxxxx, (numeric) the wallet version\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 " + CURRENCY_UNIT + "/kB\n" + " \"hdmasterkeyid\": \"<hash160>\", (string) the Hash160 of the HD master pubkey\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") @@ -2288,6 +2288,9 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); + CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; + if (!masterKeyID.IsNull()) + obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex())); return obj; } diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index d075b2b64..a6cada46a 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) pwalletMain->AddAccountingEntry(ae, walletdb); wtx.mapValue["comment"] = "z"; - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[0]->nTimeReceived = (unsigned int)1333333335; vpwtx[0]->nOrderPos = -1; @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast<CTransaction*>(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[1]->nTimeReceived = (unsigned int)1333333336; @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast<CTransaction*>(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 0a4f06ba8..c6c505898 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -349,20 +349,6 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset) BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); - - empty_wallet(); - - // Test trimming - for (int i = 0; i < 100; i++) - add_coin(10 * COIN); - for (int i = 0; i < 100; i++) - add_coin(1000 * COIN); - - BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet)); - // We need all 100 larger coins and exactly one small coin. - // Superfluous small coins must be trimmed from the set: - BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN); - BOOST_CHECK_EQUAL(setCoinsRet.size(), 101); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 87b85eeb7..888aa029a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -126,6 +126,8 @@ CPubKey CWallet::GenerateNewKey() // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); + metadata.hdKeypath = "m/0'/0'/"+std::to_string(hdChain.nExternalChainCounter)+"'"; + metadata.hdMasterKeyID = hdChain.masterKeyID; // increment childkey index hdChain.nExternalChainCounter++; } while(HaveKey(childKey.key.GetPubKey().GetID())); @@ -624,6 +626,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) Lock(); Unlock(strWalletPassphrase); + + // if we are using HD, replace the HD master key (seed) with a new one + if (!hdChain.masterKeyID.IsNull()) { + CKey key; + CPubKey masterPubKey = GenerateNewHDMasterKey(); + if (!SetHDMasterKey(masterPubKey)) + return false; + } + NewKeyPool(); Lock(); @@ -730,138 +741,143 @@ void CWallet::MarkDirty() } } -bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb) +bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) { + LOCK(cs_wallet); + + CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); + uint256 hash = wtxIn.GetHash(); - if (fFromLoadWallet) + // Inserts only if not already there, returns tx inserted or tx found + pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); + CWalletTx& wtx = (*ret.first).second; + wtx.BindWallet(this); + bool fInsertedNew = ret.second; + if (fInsertedNew) { - mapWallet[hash] = wtxIn; - CWalletTx& wtx = mapWallet[hash]; - wtx.BindWallet(this); + wtx.nTimeReceived = GetAdjustedTime(); + wtx.nOrderPos = IncOrderPosNext(&walletdb); wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); - AddToSpends(hash); - BOOST_FOREACH(const CTxIn& txin, wtx.vin) { - if (mapWallet.count(txin.prevout.hash)) { - CWalletTx& prevtx = mapWallet[txin.prevout.hash]; - if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { - MarkConflicted(prevtx.hashBlock, wtx.GetHash()); - } - } - } - } - else - { - LOCK(cs_wallet); - // Inserts only if not already there, returns tx inserted or tx found - pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); - CWalletTx& wtx = (*ret.first).second; - wtx.BindWallet(this); - bool fInsertedNew = ret.second; - if (fInsertedNew) - { - wtx.nTimeReceived = GetAdjustedTime(); - wtx.nOrderPos = IncOrderPosNext(pwalletdb); - wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); - - wtx.nTimeSmart = wtx.nTimeReceived; - if (!wtxIn.hashUnset()) + + wtx.nTimeSmart = wtx.nTimeReceived; + if (!wtxIn.hashUnset()) + { + if (mapBlockIndex.count(wtxIn.hashBlock)) { - if (mapBlockIndex.count(wtxIn.hashBlock)) + int64_t latestNow = wtx.nTimeReceived; + int64_t latestEntry = 0; { - int64_t latestNow = wtx.nTimeReceived; - int64_t latestEntry = 0; + // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future + int64_t latestTolerated = latestNow + 300; + const TxItems & txOrdered = wtxOrdered; + for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future - int64_t latestTolerated = latestNow + 300; - const TxItems & txOrdered = wtxOrdered; - for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + CWalletTx *const pwtx = (*it).second.first; + if (pwtx == &wtx) + continue; + CAccountingEntry *const pacentry = (*it).second.second; + int64_t nSmartTime; + if (pwtx) { - CWalletTx *const pwtx = (*it).second.first; - if (pwtx == &wtx) - continue; - CAccountingEntry *const pacentry = (*it).second.second; - int64_t nSmartTime; - if (pwtx) - { - nSmartTime = pwtx->nTimeSmart; - if (!nSmartTime) - nSmartTime = pwtx->nTimeReceived; - } - else - nSmartTime = pacentry->nTime; - if (nSmartTime <= latestTolerated) - { - latestEntry = nSmartTime; - if (nSmartTime > latestNow) - latestNow = nSmartTime; - break; - } + nSmartTime = pwtx->nTimeSmart; + if (!nSmartTime) + nSmartTime = pwtx->nTimeReceived; + } + else + nSmartTime = pacentry->nTime; + if (nSmartTime <= latestTolerated) + { + latestEntry = nSmartTime; + if (nSmartTime > latestNow) + latestNow = nSmartTime; + break; } } - - int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); - wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } - else - LogPrintf("AddToWallet(): found %s in block %s not in index\n", - wtxIn.GetHash().ToString(), - wtxIn.hashBlock.ToString()); + + int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); + wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } - AddToSpends(hash); + else + LogPrintf("AddToWallet(): found %s in block %s not in index\n", + wtxIn.GetHash().ToString(), + wtxIn.hashBlock.ToString()); } + AddToSpends(hash); + } - bool fUpdated = false; - if (!fInsertedNew) + bool fUpdated = false; + if (!fInsertedNew) + { + // Merge + if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) { - // Merge - if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) - { - wtx.hashBlock = wtxIn.hashBlock; - fUpdated = true; - } - // If no longer abandoned, update - if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) - { - wtx.hashBlock = wtxIn.hashBlock; - fUpdated = true; - } - if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex)) - { - wtx.nIndex = wtxIn.nIndex; - fUpdated = true; - } - if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) - { - wtx.fFromMe = wtxIn.fFromMe; - fUpdated = true; - } + wtx.hashBlock = wtxIn.hashBlock; + fUpdated = true; + } + // If no longer abandoned, update + if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) + { + wtx.hashBlock = wtxIn.hashBlock; + fUpdated = true; + } + if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex)) + { + wtx.nIndex = wtxIn.nIndex; + fUpdated = true; } + if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) + { + wtx.fFromMe = wtxIn.fFromMe; + fUpdated = true; + } + } - //// debug print - LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); + //// debug print + LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); - // Write to disk - if (fInsertedNew || fUpdated) - if (!pwalletdb->WriteTx(wtx)) - return false; + // Write to disk + if (fInsertedNew || fUpdated) + if (!walletdb.WriteTx(wtx)) + return false; - // Break debit/credit balance caches: - wtx.MarkDirty(); + // Break debit/credit balance caches: + wtx.MarkDirty(); - // Notify UI of new or updated transaction - NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + // Notify UI of new or updated transaction + NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); - // notify an external script when a wallet transaction comes in or is updated - std::string strCmd = GetArg("-walletnotify", ""); + // notify an external script when a wallet transaction comes in or is updated + std::string strCmd = GetArg("-walletnotify", ""); - if ( !strCmd.empty()) - { - boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free - } + if ( !strCmd.empty()) + { + boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + + return true; +} + +bool CWallet::LoadToWallet(const CWalletTx& wtxIn) +{ + uint256 hash = wtxIn.GetHash(); + mapWallet[hash] = wtxIn; + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + AddToSpends(hash); + BOOST_FOREACH(const CTxIn& txin, wtx.vin) { + if (mapWallet.count(txin.prevout.hash)) { + CWalletTx& prevtx = mapWallet[txin.prevout.hash]; + if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { + MarkConflicted(prevtx.hashBlock, wtx.GetHash()); + } + } } + return true; } @@ -870,18 +886,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD * pblock is optional, but should be provided if the transaction is known to be in a block. * If fUpdate is true, existing transactions will be updated. */ -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) { { AssertLockHeld(cs_wallet); - if (pblock) { + if (posInBlock != -1) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout); while (range.first != range.second) { if (range.first->second != tx.GetHash()) { - LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pblock->GetHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); - MarkConflicted(pblock->GetHash(), range.first->second); + LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); + MarkConflicted(pIndex->GetBlockHash(), range.first->second); } range.first++; } @@ -895,14 +911,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block - if (pblock) - wtx.SetMerkleBranch(*pblock); + if (posInBlock != -1) + wtx.SetMerkleBranch(pIndex, posInBlock); - // Do not flush the wallet here for performance reasons - // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism - CWalletDB walletdb(strWalletFile, "r+", false); - - return AddToWallet(wtx, false, &walletdb); + return AddToWallet(wtx, false); } } return false; @@ -1025,11 +1037,11 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) } } -void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock) +void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) { LOCK2(cs_main, cs_wallet); - if (!AddToWalletIfInvolvingMe(tx, pblock, true)) + if (!AddToWalletIfInvolvingMe(tx, pindex, posInBlock, true)) return; // Not one of ours // If a transaction changes 'conflicted' state, that changes the balance @@ -1164,16 +1176,42 @@ CAmount CWallet::GetChange(const CTransaction& tx) const return nChange; } -bool CWallet::SetHDMasterKey(const CKey& key) +CPubKey CWallet::GenerateNewHDMasterKey() { - LOCK(cs_wallet); + CKey key; + key.MakeNewKey(true); + + int64_t nCreationTime = GetTime(); + CKeyMetadata metadata(nCreationTime); - // store the key as normal "key"/"ckey" object - // in the database - // key metadata is not required + // calculate the pubkey CPubKey pubkey = key.GetPubKey(); - if (!AddKeyPubKey(key, pubkey)) - throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed"); + assert(key.VerifyPubKey(pubkey)); + + // set the hd keypath to "m" -> Master, refers the masterkeyid to itself + metadata.hdKeypath = "m"; + metadata.hdMasterKeyID = pubkey.GetID(); + + { + LOCK(cs_wallet); + + // mem store the metadata + mapKeyMetadata[pubkey.GetID()] = metadata; + + // write the key&metadata to the database + if (!AddKeyPubKey(key, pubkey)) + throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed"); + } + + return pubkey; +} + +bool CWallet::SetHDMasterKey(const CPubKey& pubkey) +{ + LOCK(cs_wallet); + + // ensure this wallet.dat can only be opened by clients supporting HD + SetMinVersion(FEATURE_HD); // store the keyid (hash160) together with // the child index counter in the database @@ -1361,9 +1399,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlock block; ReadBlockFromDisk(block, pindex, Params().GetConsensus()); - BOOST_FOREACH(CTransaction& tx, block.vtx) + int posInBlock; + for (posInBlock = 0; posInBlock < (int)block.vtx.size(); posInBlock++) { - if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) + if (AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate)) ret++; } pindex = chainActive.Next(pindex); @@ -1879,16 +1918,6 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns } } } - - //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue. - for (unsigned int i = 0; i < vValue.size(); i++) - { - if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue ) - { - vfBest[i] = false; - nBest -= vValue[i].first; - } - } } bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, @@ -2364,7 +2393,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew); // Limit size - if (GetTransactionCost(txNew) >= MAX_STANDARD_TX_COST) + if (GetTransactionWeight(txNew) >= MAX_STANDARD_TX_WEIGHT) { strFailReason = _("Transaction too large"); return false; @@ -2419,17 +2448,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) LOCK2(cs_main, cs_wallet); LogPrintf("CommitTransaction:\n%s", wtxNew.ToString()); { - // This is only to keep the database open to defeat the auto-flush for the - // duration of this scope. This is the only place where this optimization - // maybe makes sense; please don't do it anywhere else. - CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL; - // Take key pair from key pool so it won't be used again reservekey.KeepKey(); // Add tx to wallet, because if it has change it's also ours, // otherwise just for transaction history. - AddToWallet(wtxNew, false, pwalletdb); + AddToWallet(wtxNew); // Notify that old coins are spent set<CWalletTx*> setCoins; @@ -2439,9 +2463,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) coin.BindWallet(this); NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); } - - if (fFileBacked) - delete pwalletdb; } // Track how many getdata requests our transaction gets @@ -3301,11 +3322,11 @@ bool CWallet::InitLoadWallet() if (fFirstRun) { // Create new keyUser and set as default key - if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) { + if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) { // generate a new master key CKey key; - key.MakeNewKey(true); - if (!walletInstance->SetHDMasterKey(key)) + CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); + if (!walletInstance->SetHDMasterKey(masterPubKey)) throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed"); } CPubKey newDefaultKey; @@ -3506,31 +3527,19 @@ CWalletKey::CWalletKey(int64_t nExpires) nTimeExpires = nExpires; } -int CMerkleTx::SetMerkleBranch(const CBlock& block) +int CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock) { AssertLockHeld(cs_main); CBlock blockTmp; // Update the tx's hashBlock - hashBlock = block.GetHash(); + hashBlock = pindex->GetBlockHash(); - // Locate the transaction - for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++) - if (block.vtx[nIndex] == *(CTransaction*)this) - break; - if (nIndex == (int)block.vtx.size()) - { - nIndex = -1; - LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n"); - return 0; - } + // set the position of the transaction in the block + nIndex = posInBlock; // Is the tx in a block that's in the main chain - BlockMap::iterator mi = mapBlockIndex.find(hashBlock); - if (mi == mapBlockIndex.end()) - return 0; - const CBlockIndex* pindex = (*mi).second; - if (!pindex || !chainActive.Contains(pindex)) + if (!chainActive.Contains(pindex)) return 0; return chainActive.Height() - pindex->nHeight + 1; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7fc6ce5de..952acd153 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -78,7 +78,8 @@ enum WalletFeature FEATURE_WALLETCRYPT = 40000, // wallet encryption FEATURE_COMPRPUBKEY = 60000, // compressed public keys - FEATURE_LATEST = 60000 + FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet) + FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version }; @@ -199,7 +200,7 @@ public: READWRITE(nIndex); } - int SetMerkleBranch(const CBlock& block); + int SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock); /** * Return depth of transaction in blockchain: @@ -577,9 +578,10 @@ private: void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>); - /* the hd chain data model (external chain counters) */ + /* the HD chain data model (external chain counters) */ CHDChain hdChain; + bool fFileBacked; public: /* * Main wallet lock. @@ -590,7 +592,6 @@ public: */ mutable CCriticalSection cs_wallet; - bool fFileBacked; std::string strWalletFile; std::set<int64_t> setKeyPool; @@ -728,9 +729,10 @@ public: bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false); void MarkDirty(); - bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); - void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock); - bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); + bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true); + bool LoadToWallet(const CWalletTx& wtxIn); + void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock); + bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime); @@ -896,11 +898,15 @@ public: bool BackupWallet(const std::string& strDest); - /* Set the hd chain model (chain child index counters) */ + /* Set the HD chain model (chain child index counters) */ bool SetHDChain(const CHDChain& chain, bool memonly); + const CHDChain& GetHDChain() { return hdChain; } - /* Set the current hd master key (will reset the chain child index counters) */ - bool SetHDMasterKey(const CKey& key); + /* Generates a new HD master key (will not be activated) */ + CPubKey GenerateNewHDMasterKey(); + + /* Set the current HD master key (will reset the chain child index counters) */ + bool SetHDMasterKey(const CPubKey& key); }; /** A key allocated from the key pool. */ diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7bfd49095..543522ca6 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -400,7 +400,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; - pwallet->AddToWallet(wtx, true, NULL); + pwallet->LoadToWallet(wtx); } else if (strType == "acentry") { @@ -977,7 +977,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, wss, strType, strErr); } - if (!IsKeyType(strType)) + if (!IsKeyType(strType) && strType != "hdchain") continue; if (!fReadOK) { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index d083722dd..5addd5c5c 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -41,7 +41,7 @@ enum DBErrors DB_NEED_REWRITE }; -/* simple hd chain data model */ +/* simple HD chain data model */ class CHDChain { public: @@ -73,9 +73,13 @@ public: class CKeyMetadata { public: - static const int CURRENT_VERSION=1; + static const int VERSION_BASIC=1; + static const int VERSION_WITH_HDDATA=10; + static const int CURRENT_VERSION=VERSION_WITH_HDDATA; int nVersion; int64_t nCreateTime; // 0 means unknown + std::string hdKeypath; //optional HD/bip32 keypath + CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key CKeyMetadata() { @@ -83,7 +87,7 @@ public: } CKeyMetadata(int64_t nCreateTime_) { - nVersion = CKeyMetadata::CURRENT_VERSION; + SetNull(); nCreateTime = nCreateTime_; } @@ -94,12 +98,19 @@ public: READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(nCreateTime); + if (this->nVersion >= VERSION_WITH_HDDATA) + { + READWRITE(hdKeypath); + READWRITE(hdMasterKeyID); + } } void SetNull() { nVersion = CKeyMetadata::CURRENT_VERSION; nCreateTime = 0; + hdKeypath.clear(); + hdMasterKeyID.SetNull(); } }; diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 870553242..376e7dec5 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -141,7 +141,7 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex) } } -void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, const CBlock* pblock) +void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock) { for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); ) { diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 7b52e7775..a85344726 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -24,7 +24,7 @@ protected: void Shutdown(); // CValidationInterface - void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock); + void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock); void UpdatedBlockTip(const CBlockIndex *pindex); private: |