diff options
43 files changed, 1306 insertions, 1024 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 8f49dccee3..1d62941e68 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -147,6 +147,7 @@ HEADERS += src/qt/bitcoingui.h \ src/addrman.h \ src/base58.h \ src/bignum.h \ + src/chainparams.h \ src/checkpoints.h \ src/compat.h \ src/sync.h \ @@ -227,6 +228,7 @@ SOURCES += src/qt/bitcoin.cpp \ src/qt/editaddressdialog.cpp \ src/qt/bitcoinaddressvalidator.cpp \ src/alert.cpp \ + src/chainparams.cpp \ src/version.cpp \ src/sync.cpp \ src/util.cpp \ diff --git a/contrib/homebrew/makefile.osx.patch b/contrib/homebrew/makefile.osx.patch index 340de0efdf..287db2fdf2 100644 --- a/contrib/homebrew/makefile.osx.patch +++ b/contrib/homebrew/makefile.osx.patch @@ -1,5 +1,5 @@ diff --git a/src/makefile.osx b/src/makefile.osx -index 8b7c559..8a0560c 100644 +index bef0ef3..07ef8d3 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -7,17 +7,21 @@ @@ -28,7 +28,7 @@ index 8b7c559..8a0560c 100644 USE_UPNP:=1 USE_IPV6:=1 -@@ -31,13 +35,13 @@ ifdef STATIC +@@ -31,14 +35,14 @@ ifdef STATIC TESTLIBS += \ $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a LIBS += \ @@ -38,6 +38,7 @@ index 8b7c559..8a0560c 100644 $(DEPSDIR)/lib/libboost_filesystem-mt.a \ $(DEPSDIR)/lib/libboost_program_options-mt.a \ $(DEPSDIR)/lib/libboost_thread-mt.a \ + $(DEPSDIR)/lib/libboost_chrono-mt.a \ - $(DEPSDIR)/lib/libssl.a \ - $(DEPSDIR)/lib/libcrypto.a \ + $(OPENSSLDIR)/lib/libssl.a \ diff --git a/contrib/test-patches/bitcoind-comparison.patch b/contrib/test-patches/bitcoind-comparison.patch deleted file mode 100644 index f82b102e2a..0000000000 --- a/contrib/test-patches/bitcoind-comparison.patch +++ /dev/null @@ -1,196 +0,0 @@ -diff --git a/contrib/test-patches/bitcoind-comparison.patch b/contrib/test-patches/bitcoind-comparison.patch -index 04a8618..519429a 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -31,8 +31,8 @@ CTxMemPool mempool; - - map<uint256, CBlockIndex*> mapBlockIndex; - std::vector<CBlockIndex*> vBlockIndexByHeight; --uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); --static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); -+uint256 hashGenesisBlock("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"); -+static CBigNum bnProofOfWorkLimit(~uint256(0) >> 1); - CBlockIndex* pindexGenesisBlock = NULL; - int nBestHeight = -1; - uint256 nBestChainWork = 0; -@@ -1055,7 +1055,7 @@ int64 static GetBlockValue(int nHeight, int64 nFees) - int64 nSubsidy = 50 * COIN; - - // Subsidy is cut in half every 210000 blocks, which will occur approximately every 4 years -- nSubsidy >>= (nHeight / 210000); -+ nSubsidy >>= (nHeight / 150); - - return nSubsidy + nFees; - } -@@ -2736,9 +2736,9 @@ bool InitBlockIndex() { - block.hashPrevBlock = 0; - block.hashMerkleRoot = block.BuildMerkleTree(); - block.nVersion = 1; -- block.nTime = 1231006505; -- block.nBits = 0x1d00ffff; -- block.nNonce = 2083236893; -+ block.nTime = 1296688602; -+ block.nBits = 0x207fffff; -+ block.nNonce = 2; - - if (fTestNet) - { -@@ -3024,7 +3024,7 @@ bool static AlreadyHave(const CInv& inv) - // The message start string is designed to be unlikely to occur in normal data. - // The characters are rarely used upper ASCII, not valid as UTF-8, and produce - // a large 4-byte int at any alignment. --unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; -+unsigned char pchMessageStart[4] = { 0xfa, 0xbf, 0xb5, 0xda }; - - - void static ProcessGetData(CNode* pfrom) -diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp -index af28465..ee9a4db 100644 ---- a/src/test/miner_tests.cpp -+++ b/src/test/miner_tests.cpp -@@ -15,34 +15,117 @@ struct { - unsigned char extranonce; - unsigned int nonce; - } blockinfo[] = { -- {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, -- {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, -- {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4}, -- {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa}, -- {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb}, -- {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406}, -- {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38}, -- {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9}, -- {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7}, -- {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34}, -- {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c}, -- {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f}, -- {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81}, -- {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78}, -- {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c}, -- {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049}, -- {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169}, -- {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10}, -- {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d}, -- {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323}, -- {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6}, -- {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408}, -- {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602}, -- {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459}, -- {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668}, -- {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce}, -- {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, -- {2, 0xbbbeb305}, {2, 0xfe1c810a}, -+{4, 2762203683}, -+{2, 365113248}, -+{1, 58045772}, -+{1, 1879353512}, -+{2, 3460563607}, -+{2, 1389355416}, -+{1, 2007444690}, -+{2, 3143462790}, -+{2, 2213743660}, -+{1, 1218919771}, -+{1, 4017999107}, -+{2, 1745471173}, -+{2, 142846780}, -+{1, 142326754}, -+{2, 553953301}, -+{2, 3757796778}, -+{1, 4002023946}, -+{2, 3124901826}, -+{1, 2802010589}, -+{1, 877077181}, -+{3, 3593029427}, -+{2, 3969866902}, -+{2, 3392125996}, -+{1, 1805972490}, -+{2, 22889779}, -+{1, 1846647676}, -+{2, 1139340052}, -+{2, 664153912}, -+{2, 3044128027}, -+{2, 3010194979}, -+{2, 3514377385}, -+{2, 1807880922}, -+{1, 1661815113}, -+{2, 2588692156}, -+{2, 1431037239}, -+{1, 3594379210}, -+{2, 2701839377}, -+{1, 1973060452}, -+{2, 4218620174}, -+{1, 3895224884}, -+{1, 3812528857}, -+{3, 1703867851}, -+{2, 3123904294}, -+{5, 36151564}, -+{1, 2846294357}, -+{5, 3499546633}, -+{1, 924279160}, -+{1, 2198572304}, -+{1, 3336802574}, -+{2, 2185182379}, -+{1, 2575632458}, -+{1, 1965161345}, -+{1, 2865408940}, -+{1, 3594887915}, -+{5, 2062161796}, -+{5, 2641251194}, -+{1, 1290342362}, -+{1, 2883355438}, -+{6, 1244984107}, -+{2, 4065479712}, -+{2, 465481866}, -+{1, 2907174016}, -+{1, 2667735788}, -+{1, 363417673}, -+{2, 3519780275}, -+{2, 4165713317}, -+{1, 262548689}, -+{1, 3764359529}, -+{1, 2027001003}, -+{5, 1043862655}, -+{5, 1937481940}, -+{1, 1664585233}, -+{1, 1834979792}, -+{2, 2288070330}, -+{2, 3915617412}, -+{1, 3086662813}, -+{2, 430970259}, -+{1, 1519443249}, -+{2, 1540874280}, -+{2, 2496660261}, -+{1, 2847522842}, -+{1, 977329763}, -+{1, 1458040519}, -+{5, 2241822454}, -+{1, 4253963824}, -+{1, 722247551}, -+{1, 3127905834}, -+{1, 1903207432}, -+{1, 1893631657}, -+{1, 1960201429}, -+{1, 1239890082}, -+{2, 1762702850}, -+{0, 1681675873}, -+{1, 1411795775}, -+{2, 2548720534}, -+{2, 1427588186}, -+{2, 65566621}, -+{1, 2566081936}, -+{1, 3229297415}, -+{1, 3756168812}, -+{1, 826394561}, -+{1, 3015022068}, -+{1, 1935326986}, -+{5, 1648098256}, -+{2, 3545360164}, -+{1, 4106897609}, -+{1, 1528415857}, -+{1, 2707734286}, -+{2, 3149837061}, -+{2, 4263280906}, -+ - }; - - // NOTE: These tests rely on CreateNewBlock doing its own self-validation! diff --git a/src/alert.cpp b/src/alert.cpp index 44f4d5eec6..e00847aadb 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -19,9 +19,6 @@ using namespace std; map<uint256, CAlert> mapAlerts; CCriticalSection cs_mapAlerts; -static const char* pszMainKey = "04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"; -static const char* pszTestKey = "04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"; - void CUnsignedAlert::SetNull() { nVersion = 1; @@ -144,7 +141,7 @@ bool CAlert::RelayTo(CNode* pnode) const bool CAlert::CheckSignature() const { - CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey)); + CPubKey key(Params().AlertKey()); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature() : verify signature failed"); diff --git a/src/base58.h b/src/base58.h index efe3a95ebd..630d6fe9aa 100644 --- a/src/base58.h +++ b/src/base58.h @@ -18,6 +18,7 @@ #include <string> #include <vector> +#include "chainparams.h" #include "bignum.h" #include "key.h" #include "script.h" @@ -270,21 +271,13 @@ public: class CBitcoinAddress : public CBase58Data { public: - enum - { - PUBKEY_ADDRESS = 0, - SCRIPT_ADDRESS = 5, - PUBKEY_ADDRESS_TEST = 111, - SCRIPT_ADDRESS_TEST = 196, - }; - bool Set(const CKeyID &id) { - SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20); + SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); return true; } bool Set(const CScriptID &id) { - SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20); + SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); return true; } @@ -295,32 +288,10 @@ public: bool IsValid() const { - unsigned int nExpectedSize = 20; - bool fExpectTestNet = false; - switch(nVersion) - { - case PUBKEY_ADDRESS: - nExpectedSize = 20; // Hash of public key - fExpectTestNet = false; - break; - case SCRIPT_ADDRESS: - nExpectedSize = 20; // Hash of CScript - fExpectTestNet = false; - break; - - case PUBKEY_ADDRESS_TEST: - nExpectedSize = 20; - fExpectTestNet = true; - break; - case SCRIPT_ADDRESS_TEST: - nExpectedSize = 20; - fExpectTestNet = true; - break; - - default: - return false; - } - return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; + bool fCorrectSize = vchData.size() == 20; + bool fKnownVersion = nVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || + nVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + return fCorrectSize && fKnownVersion; } CBitcoinAddress() @@ -345,48 +316,27 @@ public: CTxDestination Get() const { if (!IsValid()) return CNoDestination(); - switch (nVersion) { - case PUBKEY_ADDRESS: - case PUBKEY_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); + uint160 id; + memcpy(&id, &vchData[0], 20); + if (nVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) return CKeyID(id); - } - case SCRIPT_ADDRESS: - case SCRIPT_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); + else if (nVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) return CScriptID(id); - } - } - return CNoDestination(); + else + return CNoDestination(); } bool GetKeyID(CKeyID &keyID) const { - if (!IsValid()) + if (!IsValid() || nVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) return false; - switch (nVersion) { - case PUBKEY_ADDRESS: - case PUBKEY_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); - keyID = CKeyID(id); - return true; - } - default: return false; - } + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; } bool IsScript() const { - if (!IsValid()) - return false; - switch (nVersion) { - case SCRIPT_ADDRESS: - case SCRIPT_ADDRESS_TEST: { - return true; - } - default: return false; - } + return IsValid() && nVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); } }; @@ -401,7 +351,7 @@ public: void SetKey(const CKey& vchSecret) { assert(vchSecret.IsValid()); - SetData(fTestNet ? 239 : 128, vchSecret.begin(), vchSecret.size()); + SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); if (vchSecret.IsCompressed()) vchData.push_back(1); } @@ -415,20 +365,9 @@ public: bool IsValid() const { - bool fExpectTestNet = false; - switch(nVersion) - { - case 128: - break; - - case 239: - fExpectTestNet = true; - break; - - default: - return false; - } - return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1)); + bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); + bool fCorrectVersion = nVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); + return fExpectedFormat && fCorrectVersion; } bool SetString(const char* pszSecret) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 682a214fb2..bc23cf5507 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -67,6 +67,10 @@ bool AppInit(int argc, char* argv[]) if (fCommandLine) { + if (!SelectParamsFromCommandLine()) { + fprintf(stderr, "Error: invalid combination of -regtest and -testnet.\n"); + return false; + } int ret = CommandLineRPC(argc, argv); exit(ret); } diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 285a88c8d8..5908126200 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "init.h" #include "util.h" #include "sync.h" @@ -38,11 +39,6 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; -static inline unsigned short GetDefaultRPCPort() -{ - return GetBoolArg("-testnet", false) ? 18332 : 8332; -} - Object JSONRPCError(int code, const string& message) { Object error; @@ -247,7 +243,9 @@ static const CRPCCommand vRPCCommands[] = { "submitblock", &submitblock, false, false }, { "listsinceblock", &listsinceblock, false, false }, { "dumpprivkey", &dumpprivkey, true, false }, + { "dumpwallet", &dumpwallet, true, false }, { "importprivkey", &importprivkey, false, false }, + { "importwallet", &importwallet, false, false }, { "listunspent", &listunspent, false, false }, { "getrawtransaction", &getrawtransaction, false, false }, { "createrawtransaction", &createrawtransaction, false, false }, @@ -258,6 +256,7 @@ static const CRPCCommand vRPCCommands[] = { "gettxout", &gettxout, true, false }, { "lockunspent", &lockunspent, false, false }, { "listlockunspent", &listlockunspent, false, false }, + { "verifychain", &verifychain, true, false }, }; CRPCTable::CRPCTable() @@ -724,8 +723,8 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, void StartRPCThreads() { strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - if ((mapArgs["-rpcpassword"] == "") || - (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) + if (((mapArgs["-rpcpassword"] == "") || + (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword()) { unsigned char rand_pwd[32]; RAND_bytes(rand_pwd, 32); @@ -780,7 +779,7 @@ void StartRPCThreads() // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets const bool loopback = !mapArgs.count("-rpcallowip"); asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); - ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", GetDefaultRPCPort())); + ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort())); boost::system::error_code v6_only_error; boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service)); @@ -1078,7 +1077,7 @@ Object CallRPC(const string& strMethod, const Array& params) asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context); SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL); iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d); - if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(GetDefaultRPCPort())))) + if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())))) throw runtime_error("couldn't connect to server"); // HTTP basic authentication @@ -1198,6 +1197,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]); + if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 44c657f8dc..247c47adf9 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -145,8 +145,11 @@ extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, b extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp); + extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); @@ -205,5 +208,6 @@ extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fH extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp); #endif diff --git a/src/chainparams.cpp b/src/chainparams.cpp new file mode 100644 index 0000000000..8859424d20 --- /dev/null +++ b/src/chainparams.cpp @@ -0,0 +1,286 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "assert.h" + +#include "chainparams.h" +#include "main.h" +#include "util.h" + +// +// Main network +// + +unsigned int pnSeed[] = +{ + 0xe473042e, 0xb177f2ad, 0xd63f3fb2, 0xf864f736, 0x44a23ac7, 0xcf6d9650, 0xd648042e, 0x0536f447, + 0x3c654ed0, 0x3e16a5bc, 0xa38e09b0, 0xdfae795b, 0xabfeca5b, 0x94ad7840, 0xf3b9f1c7, 0xbe70e0ad, + 0x3bbd09b0, 0x8d0c7dd5, 0x3b2a7332, 0x1a06175e, 0x581f175e, 0xca0d2dcc, 0x0fdbc658, 0xcf591ec7, + 0x295a12b2, 0xb4707bce, 0x68bb09b0, 0x4e735747, 0x89709553, 0x05a7814e, 0x5b8ec658, 0x402c5512, + 0xe80d0905, 0x17681a5e, 0xc02aa748, 0x9f811741, 0x5f321cb0, 0x23e1ee47, 0xaf7f170c, 0xaa240ab0, + 0xedea6257, 0x76106bc1, 0x2cf310cc, 0x08612acb, 0x9c682e4e, 0x8e963c6c, 0x443c795b, 0x22e246b8, + 0xfa1f2dcc, 0x90118140, 0x3821042e, 0x33c3fd2e, 0x10046d5b, 0x40d14b3e, 0x7fb8f8ce, 0x67696550, + 0xeeecbe58, 0x4f341745, 0x46b8fbd5, 0xc8463932, 0x6b73e862, 0x4c715932, 0x4a6785d5, 0xce3a64c2, + 0xde9604c7, 0x9b06884f, 0x18002a45, 0xea9bc345, 0xc4f1c658, 0xe475c1c7, 0xdd3e795b, 0x9722175e, + 0x34562f4e, 0x66c46e4e, 0x40bb1243, 0x7d9171d0, 0x17b8dbd5, 0x63cbfd2e, 0x1a08b8d8, 0x6175a73b, + 0x228d2660, 0x8627c658, 0x9c566644, 0x38cca5bc, 0x3089de5b, 0x92e25f5d, 0xa393f73f, 0xcc92dc3e, + 0x27487446, 0x62cbfd2e, 0x9d983b45, 0xf72a09b0, 0xf75f042e, 0x6434bb6a, 0xb29e77d8, 0x19be4fd9, + 0x76443243, 0x9dd72645, 0x694cef43, 0x89c2efd5, 0x5f1c5058, 0x46c6e45b, 0xe1391b40, 0x77ccefd5, + 0x472e5a6d, 0x85709553, 0xdd4f5d4c, 0x64ef5a46, 0x7f0ae502, 0xcf08d850, 0x3460042e, 0xeafa2d42, + 0x793c9044, 0x9d094746, 0x1ab9b153, 0xbfe9a5bc, 0x34771fb0, 0xb7722e32, 0x1168964b, 0x19b06ab8, + 0x19243b25, 0x13188045, 0xb4070905, 0x728ebb5d, 0x44f24ac8, 0xa317fead, 0x642f6a57, 0x3d951f32, + 0x3d312e4e, 0xfac4d048, 0xefc4dd50, 0x52b9f1c7, 0xc14d3cc3, 0x0219ea44, 0x3b79d058, 0xfa217242, + 0x39c80647, 0xfb697252, 0x1d495a42, 0x0aa81f4e, 0x58249ab8, 0xe6a8e6c3, 0x2bc4dad8, 0x85963c6c, + 0xa4ce09b0, 0x2005f536, 0x5cc2703e, 0x1992de43, 0x74e86b4c, 0xe7085653, 0xf5e15a51, 0xb4872b60, + 0x29e2b162, 0xa07ea053, 0x8229fd18, 0x4562ec4d, 0x8dec814e, 0x36cfa4cf, 0x96461032, 0x3c8770de, + 0xd10a1f5f, 0x95934641, 0x97cd65d0, 0x2e35324a, 0x2566ba1f, 0x1ca1a9d1, 0xb808b8d5, 0xf9a24a5d, + 0xafc8d431, 0xe4b8d9b2, 0x0f5321b2, 0x330bc658, 0x74b347ce, 0x972babd5, 0x044f7d4f, 0x06562f4e, + 0x8b8d3c6c, 0x3507c658, 0xe4174e4d, 0xf1c009b0, 0x52249ab8, 0x27211772, 0xf6a9ba59, 0x7a391b40, + 0x855dc6c0, 0x291f20b2, 0xe29bc345, 0x90963c6c, 0x0af70732, 0x4242a91f, 0x4c531d48, 0xa32df948, + 0x627e3044, 0x65be1f54, 0x1a0cbf83, 0x6a443532, 0x8d5f1955, 0xbafa8132, 0x3534bdd5, 0xca019dd9, + 0x8a0d9332, 0x5584e7d8, 0x7cd1f25e, 0xeabe3fb2, 0x2945d0d1, 0x46415718, 0x70d6042e, 0x99eb76d0, + 0x9ece09b0, 0xb3777418, 0x5e5e91d9, 0x237a3ab0, 0xf512b62e, 0x45dec347, 0x59b7f862, 0x4c443b25, + 0x3cc6484b, 0x9a8ec6d1, 0x021eea44, 0xc9483944, 0xfd567e32, 0xfd204bb2, 0xc5330bcc, 0x5202894e, + 0xf9e309b0, 0x4cc17557, 0xdb9064ae, 0xe19e77d8, 0x25857f60, 0xeb4a15ad, 0x1f47f554, 0xea4472d9, + 0xd20de593, 0xf5733b25, 0x11892b54, 0x5729d35f, 0xe6188cd1, 0x488b132e, 0x541c534a, 0xa8e854ae, + 0xa255a66c, 0x33688763, 0xc6629ac6, 0xc20a6265, 0xcd92a059, 0x72029d3b, 0x4c298f5e, 0x51452e4e, + 0xbb065058, 0x15fd2dcc, 0xf40c135e, 0x615a0bad, 0x0c6a6805, 0x4971a7ad, 0x17f2a5d5, 0xf8babf47, + 0xb61f50ad, 0x4e1451b1, 0xf72d9252, 0x5c2abe58, 0xbd987c61, 0x084ae5cf, 0x20781fb0, 0x38b0f160, + 0x18aac705, 0x14f86dc1, 0x5556f481, 0x0a36c144, 0xeb446e4c, 0x2c1c0d6c, 0xbd0ff860, 0x869f92db, + 0x36c94f4c, 0x05502444, 0x148fe55b, 0xd5301e59, 0xd57a8f45, 0x110dc04a, 0x8670fc36, 0xee733b25, + 0xca56f481, 0x2a5c3bae, 0x844b0905, 0x1e51fe53, 0x0241c244, 0x59c0614e, 0x94e70a55, 0x7312fead, + 0xb735be44, 0xa55d0905, 0x2f63962e, 0x14a4e15b, 0x63f8f05c, 0x62d0d262, 0x3cab41ad, 0x87f1b1cb, + 0x018da6b8, 0xb3967dd5, 0xcb56f481, 0x685ad718, 0x3b4aeeca, 0x8d106bc1, 0x51180905, 0x72660f48, + 0x1521a243, 0x5b56f481, 0x6390e560, 0xdd61464e, 0x58353b25, 0x553fc062, 0x27c45d59, 0xacc62e4e, + 0x0d5a1cd9, 0x7f65f442, 0xbdeef660, 0xf1bd1855, 0xf8473cae, 0x13b120b2, 0x442440d0, 0x53fd4352, + 0xa305fc57, 0x458be84d, 0x639ce1c3, 0xebaaee47, 0x95e2c247, 0xf056f481, 0x6256f481, 0x1d87c65e, + 0x0a453418, 0x5beb175e, 0xd64f1618, 0xc360795b, 0x2fbf5753, 0xa8c58e53, 0x651cec52, 0x9d37b043, + 0x124a9758, 0x5242e4a9, 0x89913c6c, 0x880efe2e, 0x2f2f2f0c, 0x72b26751, 0x2896e46d, 0x80f4166c, + 0x320d59ad, 0xc50151d0, 0x11a8aa43, 0xccf56057, 0x5fbad118, 0x4719b151, 0x2b5f4bc0, 0x4d7a4a50, + 0xad06e047, 0x62ef5a46, 0x5aebde58, 0xdf7aa66c, 0x851acb50, 0x66b9a559, 0x3e9bb153, 0xcc512f2e, + 0xc073b08e, 0xd519be58, 0xe981ea4d, 0x12fd50cb, 0x378739ad, 0x06683cae, 0xa22310b2, 0xc185c705, + 0x8741b545, 0xa26c8318, 0x22d5bc43, 0x39201ec0, 0x68581e3e, 0xdc9bcf62, 0xd508cc82, 0xb149675b, + 0x4c9609b0, 0x84feb84c, 0x08291e2e, 0xfd2253b2, 0x1fd269c1, 0xc9483932, 0x4d641fb0, 0x7d37c918, + 0xa9de20ad, 0x77e2d655, 0x6d421b59, 0xd7668f80, 0xced09b62, 0xa9e5a5bc, 0xa4074e18, 0x60fc5ecc, + 0x01300148, 0x68062444, 0xb4224847, 0xed3aa443, 0xb772fb43, 0x9f56f481, 0x220dfd18, 0x8e1c3d6c, + 0xc44f09b0, 0x7df2bb73, 0xe22fb844, 0xea534242, 0xb6a755d4, 0xa036654b, 0x138ece5b, 0xda65d3c3, + 0x955871bc, 0x792124b0, 0xfc82594c, 0x851d494b, 0x2c7aee47, 0x26af46b8, 0x1416252e, 0xa8abb944, + 0x36c49d25, 0x674f645d, 0x363646b8, 0x9e1a2942, 0x66d0c154, 0xc6c2a545, 0x3570f2ad, 0xe7d547c7, + 0x7d104932, 0x18cb9c18, 0x1dcfa4cf, 0xd156f481, 0x2a02b91f, 0x3eeb3fa8, 0xcac4175e, 0x34146d42, + 0x994c4d46, 0x5666f440, 0x85d6713e, 0x5ecb296c, 0x0ea0ae46, 0x87e69f42, 0xc58409b0, 0x1f3436ae, + 0x21dc6a57, 0x4ad1cd42, 0xfb8c1a4c, 0x52d3dab2, 0x3769894b, 0xb52f1c62, 0x3677916d, 0x82b3fe57, + 0x493d4ac6, 0x9f963c6c, 0x5d91ff60, 0x458e0dad, 0xa49d0947, 0x491a3e18, 0x4aadcd5b, 0x0e46494b, + 0x1d1610ad, 0x1a10af5d, 0x4956f481, 0x207a3eae, 0x77e73244, 0xfa3b8742, 0x3261fc36, 0xfcebf536, + 0x1662e836, 0xf655f636, 0xa2dbd0ad, 0x23036693, 0x30448432, 0xa2b03463, 0x30730344, 0x8e4a6882, + 0x0c50a1cb, 0xc8d8c06b, 0xc9cd6191, 0xf443db50, 0xa9553c50, 0x23145847, 0xc35da66c, 0x29c12a60, + 0x55c2b447, 0x7434f75c, 0x61660640, 0xde2a7018, 0xc639494c, 0x1c306fce, 0x19b89244, 0xd29a6462, + 0x462cd1b2, 0x29902f44, 0x2817fa53, 0x21a30905, 0x7777ae46, 0x288443a1, 0x7bee5148, 0xc2a8b043, + 0xf5c3d35f, 0x2311ef84, 0x57de08a4, 0x6b221bb2, 0xf2625846, 0x4b9e09b0, 0xa24f880e, 0x22b11447, + 0xb3a0c744, 0x919e77d8, 0xec8b64ae, 0xff5c8d45, 0x7b15b484, 0x32679a5f, 0xba80b62e, 0x05c25c61, + 0x60014746, 0x5e8fb04c, 0xe67c0905, 0x4329c658, 0xac8fe555, 0xf875e647, 0x67406386, 0x35ceea18, + 0xbb79484b, 0xd7b9fa62, 0x238209b0, 0x208a1d32, 0x9630995e, 0x039c1318, 0x6e48006c, 0x60582344, + 0xadbb0150, 0x853fd462, 0x03772e4e, 0x652ce960, 0x49b630ad, 0x9993af43, 0x3735b34b, 0x548a07d9, + 0x55a44aad, 0xa23d1bcc, 0xfdbb2f4e, 0x530b24a0, 0x0a44b451, 0x6827c657, 0x1f66494b, 0x4e680a47, + 0x77e7b747, 0xa5eb3fa8, 0x6649764a, 0xd4e76c4b, 0x2c691fb0, 0xf1292e44, 0xc6d6c774, 0x85d23775, + 0x28275f4d, 0x259ae46d, 0x02424e81, 0x5f16be58, 0xe707c658, 0x49eae5c7, 0xd5d147ad, 0x9a7abdc3, + 0xe8ac7fc7, 0x84ec3aae, 0xc24942d0, 0x294aa318, 0x08ac3d18, 0x8894042e, 0xb24609b0, 0x9bcaab58, + 0xc400f712, 0xd5c512b8, 0x2c02cc62, 0x25080fd8, 0xed74a847, 0x18a5ec5e, 0x9850ec6d, 0xf8909758, + 0x7f56f481, 0x4496f23c, 0xae27784f, 0xcb7cd93e, 0x06e32860, 0x50b9a84f, 0x3660434a, 0x09161f5f, + 0x900486bc, 0x08055459, 0xe7ec1017, 0x7e39494c, 0x4f443b25, 0x14751a8a, 0x717d03d4, 0xbd0e24d8, + 0x054b6f56, 0x854c496c, 0xd92a454a, 0xc39bd054, 0x6093614b, 0x9dbad754, 0x5bf0604a, 0x99f22305 +}; + +class CMainParams : public CChainParams { +public: + CMainParams() { + // The message start string is designed to be unlikely to occur in normal data. + // The characters are rarely used upper ASCII, not valid as UTF-8, and produce + // a large 4-byte int at any alignment. + pchMessageStart[0] = 0xf9; + pchMessageStart[1] = 0xbe; + pchMessageStart[2] = 0xb4; + pchMessageStart[3] = 0xd9; + vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); + nDefaultPort = 8333; + nRPCPort = 8332; + bnProofOfWorkLimit = CBigNum(~uint256(0) >> 32); + nSubsidyHalvingInterval = 210000; + + // Build the genesis block. Note that the output of the genesis coinbase cannot + // be spent as it did not originally exist in the database. + // + // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) + // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) + // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) + // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) + // vMerkleTree: 4a5e1e + const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; + CTransaction txNew; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].nValue = 50 * COIN; + txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + genesis.vtx.push_back(txNew); + genesis.hashPrevBlock = 0; + genesis.hashMerkleRoot = genesis.BuildMerkleTree(); + genesis.nVersion = 1; + genesis.nTime = 1231006505; + genesis.nBits = 0x1d00ffff; + genesis.nNonce = 2083236893; + + hashGenesisBlock = genesis.GetHash(); + assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); + assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + + vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be")); + vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); + vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); + vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); + + base58Prefixes[PUBKEY_ADDRESS] = 0; + base58Prefixes[SCRIPT_ADDRESS] = 5; + base58Prefixes[SECRET_KEY] = 128; + + // Convert the pnSeeds array into usable address objects. + for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) + { + // It'll only connect to one or two seed nodes because once it connects, + // it'll get a pile of addresses with newer timestamps. + // Seed nodes are given a random 'last seen time' of between one and two + // weeks ago. + const int64 nOneWeek = 7*24*60*60; + struct in_addr ip; + memcpy(&ip, &pnSeed[i], sizeof(ip)); + CAddress addr(CService(ip, GetDefaultPort())); + addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; + vFixedSeeds.push_back(addr); + } + } + + virtual const CBlock& GenesisBlock() const { return genesis; } + virtual Network NetworkID() const { return CChainParams::MAIN; } + + virtual const vector<CAddress>& FixedSeeds() const { + return vFixedSeeds; + } +protected: + CBlock genesis; + vector<CAddress> vFixedSeeds; +}; +static CMainParams mainParams; + + +// +// Testnet (v3) +// +class CTestNetParams : public CMainParams { +public: + CTestNetParams() { + // The message start string is designed to be unlikely to occur in normal data. + // The characters are rarely used upper ASCII, not valid as UTF-8, and produce + // a large 4-byte int at any alignment. + pchMessageStart[0] = 0x0b; + pchMessageStart[1] = 0x11; + pchMessageStart[2] = 0x09; + pchMessageStart[3] = 0x07; + vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); + nDefaultPort = 18333; + nRPCPort = 18332; + strDataDir = "testnet3"; + + // Modify the testnet genesis block so the timestamp is valid for a later start. + genesis.nTime = 1296688602; + genesis.nNonce = 414098458; + hashGenesisBlock = genesis.GetHash(); + assert(hashGenesisBlock == uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); + + vFixedSeeds.clear(); + vSeeds.clear(); + vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org")); + vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me")); + + base58Prefixes[PUBKEY_ADDRESS] = 111; + base58Prefixes[SCRIPT_ADDRESS] = 196; + base58Prefixes[SECRET_KEY] = 239; + + } + virtual Network NetworkID() const { return CChainParams::TESTNET; } +}; +static CTestNetParams testNetParams; + + +// +// Regression test +// +class CRegTestParams : public CTestNetParams { +public: + CRegTestParams() { + pchMessageStart[0] = 0xfa; + pchMessageStart[1] = 0xbf; + pchMessageStart[2] = 0xb5; + pchMessageStart[3] = 0xda; + nSubsidyHalvingInterval = 150; + bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1); + genesis.nTime = 1296688602; + genesis.nBits = 0x207fffff; + genesis.nNonce = 2; + hashGenesisBlock = genesis.GetHash(); + nDefaultPort = 18444; + strDataDir = "regtest"; + assert(hashGenesisBlock == uint256("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); + + vSeeds.clear(); // Regtest mode doesn't have any DNS seeds. + + base58Prefixes[PUBKEY_ADDRESS] = 0; + base58Prefixes[SCRIPT_ADDRESS] = 5; + base58Prefixes[SECRET_KEY] = 128; + } + + virtual bool RequireRPCPassword() const { return false; } + virtual Network NetworkID() const { return CChainParams::REGTEST; } +}; +static CRegTestParams regTestParams; + +static CChainParams *pCurrentParams = &mainParams; + +const CChainParams &Params() { + return *pCurrentParams; +} + +void SelectParams(CChainParams::Network network) { + switch (network) { + case CChainParams::MAIN: + pCurrentParams = &mainParams; + break; + case CChainParams::TESTNET: + pCurrentParams = &testNetParams; + break; + case CChainParams::REGTEST: + pCurrentParams = ®TestParams; + break; + default: + assert(false && "Unimplemented network"); + return; + } +} + +bool SelectParamsFromCommandLine() { + bool fRegTest = GetBoolArg("-regtest", false); + bool fTestNet = GetBoolArg("-testnet", false); + + if (fTestNet && fRegTest) { + return false; + } + + if (fRegTest) { + SelectParams(CChainParams::REGTEST); + } else if (fTestNet) { + SelectParams(CChainParams::TESTNET); + } else { + SelectParams(CChainParams::MAIN); + } + return true; +} diff --git a/src/chainparams.h b/src/chainparams.h new file mode 100644 index 0000000000..572712b589 --- /dev/null +++ b/src/chainparams.h @@ -0,0 +1,102 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CHAIN_PARAMS_H +#define BITCOIN_CHAIN_PARAMS_H + +#include "bignum.h" +#include "uint256.h" +#include "util.h" + +#include <vector> + +using namespace std; + +#define MESSAGE_START_SIZE 4 +typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; + +class CAddress; +class CBlock; + +struct CDNSSeedData { + string name, host; + CDNSSeedData(const string &strName, const string &strHost) : name(strName), host(strHost) {} +}; + +/** + * CChainParams defines various tweakable parameters of a given instance of the + * Bitcoin system. There are three: the main network on which people trade goods + * and services, the public test network which gets reset from time to time and + * a regression test mode which is intended for private networks only. It has + * minimal difficulty to ensure that blocks can be found instantly. + */ +class CChainParams +{ +public: + enum Network { + MAIN, + TESTNET, + REGTEST, + }; + + enum Base58Type { + PUBKEY_ADDRESS, + SCRIPT_ADDRESS, + SECRET_KEY, + + MAX_BASE58_TYPES + }; + + const uint256& HashGenesisBlock() const { return hashGenesisBlock; } + const MessageStartChars& MessageStart() const { return pchMessageStart; } + const vector<unsigned char>& AlertKey() const { return vAlertPubKey; } + int GetDefaultPort() const { return nDefaultPort; } + const CBigNum& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } + int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } + virtual const CBlock& GenesisBlock() const = 0; + virtual bool RequireRPCPassword() const { return true; } + const string& DataDir() const { return strDataDir; } + virtual Network NetworkID() const = 0; + const vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; } + int Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + virtual const vector<CAddress>& FixedSeeds() const = 0; + int RPCPort() const { return nRPCPort; } +protected: + CChainParams() {}; + + uint256 hashGenesisBlock; + MessageStartChars pchMessageStart; + // Raw pub key bytes for the broadcast alert signing key. + vector<unsigned char> vAlertPubKey; + int nDefaultPort; + int nRPCPort; + CBigNum bnProofOfWorkLimit; + int nSubsidyHalvingInterval; + string strDataDir; + vector<CDNSSeedData> vSeeds; + int base58Prefixes[MAX_BASE58_TYPES]; +}; + +/** + * Return the currently selected parameters. This won't change after app startup + * outside of the unit tests. + */ +const CChainParams &Params(); + +/** Sets the params returned by Params() to those for the given network. */ +void SelectParams(CChainParams::Network network); + +/** + * Looks for -regtest or -testnet and then calls SelectParams as appropriate. + * Returns false if an invalid combination is given. + */ +bool SelectParamsFromCommandLine(); + +inline bool TestNet() { + // Note: it's deliberate that this returns "false" for regression test mode. + return Params().NetworkID() == CChainParams::TESTNET; +} + +#endif diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 7643ec5df8..ba29e2463e 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -56,7 +56,7 @@ namespace Checkpoints 60000.0 // * estimated number of transactions per day after checkpoint }; - static MapCheckpoints mapCheckpointsTestnet = + static MapCheckpoints mapCheckpointsTestnet = boost::assign::map_list_of ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")) ; @@ -68,7 +68,7 @@ namespace Checkpoints }; const CCheckpointData &Checkpoints() { - if (fTestNet) + if (TestNet()) return dataTestnet; else return data; diff --git a/src/core.h b/src/core.h index cba3ab233f..fce9ccc162 100644 --- a/src/core.h +++ b/src/core.h @@ -192,10 +192,10 @@ public: // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. - // A typical txout is 33 bytes big, and will + // A typical txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend, // so dust is a txout less than 54 uBTC - // (5430 satoshis) with default nMinRelayTxFee + // (5460 satoshis) with default nMinRelayTxFee return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < nMinRelayTxFee); } @@ -733,4 +733,127 @@ public: } }; + +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector<CTransaction> vtx; + + // memory only + mutable std::vector<uint256> vMerkleTree; + + CBlock() + { + SetNull(); + } + + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + ) + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + vMerkleTree.clear(); + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrevBlock; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 BuildMerkleTree() const + { + vMerkleTree.clear(); + BOOST_FOREACH(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); + } + + const uint256 &GetTxHash(unsigned int nIndex) const { + assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first + assert(nIndex < vtx.size()); + return vMerkleTree[nIndex]; + } + + std::vector<uint256> GetMerkleBranch(int nIndex) const + { + if (vMerkleTree.empty()) + BuildMerkleTree(); + std::vector<uint256> vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; + } + + static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) + { + if (nIndex == -1) + return 0; + BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; + } + + void print() const + { + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + GetHash().ToString().c_str(), + nVersion, + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), + nTime, nBits, nNonce, + vtx.size()); + for (unsigned int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (unsigned int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().c_str()); + printf("\n"); + } +}; + #endif diff --git a/src/db.cpp b/src/db.cpp index 1f53917602..93f3f5d8c4 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "db.h" #include "util.h" #include "hash.h" @@ -488,8 +489,6 @@ void CDBEnv::Flush(bool fShutdown) // CAddrDB // -unsigned char CAddrDB::pchMessageStart[4] = { 0x00, 0x00, 0x00, 0x00 }; - CAddrDB::CAddrDB() { pathAddr = GetDataDir() / "peers.dat"; @@ -504,7 +503,7 @@ bool CAddrDB::Write(const CAddrMan& addr) // serialize addresses, checksum data up to that point, then append csum CDataStream ssPeers(SER_DISK, CLIENT_VERSION); - ssPeers << FLATDATA(CAddrDB::pchMessageStart); + ssPeers << FLATDATA(Params().MessageStart()); ssPeers << addr; uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); ssPeers << hash; @@ -569,11 +568,11 @@ bool CAddrDB::Read(CAddrMan& addr) unsigned char pchMsgTmp[4]; try { - // de-serialize file header (CAddrDB::pchMessageStart magic number) and + // de-serialize file header (network specific magic number) and .. ssPeers >> FLATDATA(pchMsgTmp); - // verify the network matches ours - if (memcmp(pchMsgTmp, CAddrDB::pchMessageStart, sizeof(pchMsgTmp))) + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) return error("CAddrman::Read() : invalid network magic number"); // de-serialize address data into one CAddrMan object @@ -318,14 +318,10 @@ class CAddrDB { private: boost::filesystem::path pathAddr; - static unsigned char pchMessageStart[4]; - public: CAddrDB(); bool Write(const CAddrMan& addr); bool Read(CAddrMan& addr); - - static void SetMessageStart(unsigned char _pchMessageStart[]) { memcpy(CAddrDB::pchMessageStart, _pchMessageStart, sizeof(CAddrDB::pchMessageStart)); } }; #endif // BITCOIN_DB_H diff --git a/src/init.cpp b/src/init.cpp index fe74cd6963..e88055bdea 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -6,6 +6,7 @@ #include "init.h" #include "main.h" #include "core.h" +#include "chainparams.h" #include "txdb.h" #include "walletdb.h" #include "bitcoinrpc.h" @@ -210,6 +211,8 @@ std::string HelpMessage() strUsage += " -logtimestamps " + _("Prepend debug output with timestamp") + "\n"; strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; + strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be " + "solved instantly. This is intended for regression testing tools and app development.") + "\n"; #ifdef WIN32 strUsage += " -printtodebugger " + _("Send trace/debug info to debugger") + "\n"; #endif @@ -366,8 +369,10 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 2: parameter interactions - fTestNet = GetBoolArg("-testnet", false); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); + if (!SelectParamsFromCommandLine()) { + return InitError("Invalid combination of -testnet and -regtest."); + } if (mapArgs.count("-bind")) { // when specifying an explicit binding address, you want to listen on it @@ -572,7 +577,7 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 6: network initialization RegisterNodeSignals(GetNodeSignals()); - + int nSocksVersion = GetArg("-socks", 5); if (nSocksVersion != 4 && nSocksVersion != 5) return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion)); @@ -744,20 +749,21 @@ bool AppInit2(boost::thread_group& threadGroup) if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); - // Check for changed -txindex state (only necessary if we are not reindexing anyway) - if (!fReindex && fTxIndex != GetBoolArg("-txindex", false)) { - strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); - break; - } - // Initialize the block index (no-op if non-empty database was already loaded) if (!InitBlockIndex()) { strLoadError = _("Error initializing block database"); break; } + // Check for changed -txindex state + if (fTxIndex != GetBoolArg("-txindex", false)) { + strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); + break; + } + uiInterface.InitMessage(_("Verifying blocks...")); - if (!VerifyDB()) { + if (!VerifyDB(GetArg("-checklevel", 3), + GetArg( "-checkblocks", 288))) { strLoadError = _("Corrupted block database detected"); break; } @@ -814,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup) { CBlockIndex* pindex = (*mi).second; CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); block.BuildMerkleTree(); block.print(); printf("\n"); @@ -937,7 +943,6 @@ bool AppInit2(boost::thread_group& threadGroup) nStart = GetTimeMillis(); { - CAddrDB::SetMessageStart(pchMessageStart); CAddrDB adb; if (!adb.Read(addrman)) printf("Invalid or missing peers.dat; recreating\n"); diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index 609cb51224..a3ad057eee 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -94,6 +94,12 @@ case "$TARGET_OS" in PLATFORM_LIBS="-lpthread" PORT_FILE=port/port_posix.cc ;; + GNU/kFreeBSD) + PLATFORM=OS_KFREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_KFREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; NetBSD) PLATFORM=OS_NETBSD COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" diff --git a/src/main.cpp b/src/main.cpp index f0c08d273f..da928a4b90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "init.h" #include "ui_interface.h" #include "checkqueue.h" +#include "chainparams.h" #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -32,8 +33,6 @@ unsigned int nTransactionsUpdated = 0; map<uint256, CBlockIndex*> mapBlockIndex; std::vector<CBlockIndex*> vBlockIndexByHeight; -uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); -static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; uint256 nBestChainWork = 0; @@ -158,8 +157,6 @@ void static ResendWalletTransactions() pwallet->ResendWalletTransactions(); } - - ////////////////////////////////////////////////////////////////////////////// // // Registration of network node signals. @@ -177,7 +174,95 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) nodeSignals.SendMessages.disconnect(&SendMessages); } +////////////////////////////////////////////////////////////////////////////// +// +// CBlockLocator implementation +// + +CBlockLocator::CBlockLocator(uint256 hashBlock) +{ + std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end()) + Set((*mi).second); +} + +void CBlockLocator::Set(const CBlockIndex* pindex) +{ + vHave.clear(); + int nStep = 1; + while (pindex) + { + vHave.push_back(pindex->GetBlockHash()); + + // Exponentially larger steps back + for (int i = 0; pindex && i < nStep; i++) + pindex = pindex->pprev; + if (vHave.size() > 10) + nStep *= 2; + } + vHave.push_back(Params().HashGenesisBlock()); +} + +int CBlockLocator::GetDistanceBack() +{ + // Retrace how far back it was in the sender's branch + int nDistance = 0; + int nStep = 1; + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return nDistance; + } + nDistance += nStep; + if (nDistance > 10) + nStep *= 2; + } + return nDistance; +} + +CBlockIndex *CBlockLocator::GetBlockIndex() +{ + // Find the first block the caller has in the main chain + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return pindex; + } + } + return pindexGenesisBlock; +} + +uint256 CBlockLocator::GetBlockHash() +{ + // Find the first block the caller has in the main chain + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return hash; + } + } + return Params().HashGenesisBlock(); +} +int CBlockLocator::GetHeight() +{ + CBlockIndex* pindex = GetBlockIndex(); + if (!pindex) + return 0; + return pindex->nHeight; +} ////////////////////////////////////////////////////////////////////////////// // @@ -542,7 +627,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) if (pcoinsTip->GetCoins(GetHash(), coins)) { CBlockIndex *pindex = FindBlockByHeight(coins.nHeight); if (pindex) { - if (!blockTmp.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(blockTmp, pindex)) return 0; pblock = &blockTmp; } @@ -634,30 +719,23 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) return true; } -int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree, enum GetMinFee_mode mode) +int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode) { // Base fee is either nMinTxFee or nMinRelayTxFee int64 nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee; unsigned int nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - unsigned int nNewBlockSize = nBlockSize + nBytes; int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; if (fAllowFree) { - if (nBlockSize == 1) - { - // Transactions under 10K are free - // (about 4500 BTC if made of 50 BTC inputs) - if (nBytes < 10000) - nMinFee = 0; - } - else - { - // Free transaction area - if (nNewBlockSize < 27000) - nMinFee = 0; - } + // There is a free transaction area in blocks created by most miners, + // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 + // to be considered to fall into this category + // * If we are creating a transaction we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 17000 + // (= 10000) to be considered safe and assume they can likely make it into this section + if (nBytes < (mode == GMF_SEND ? (DEFAULT_BLOCK_PRIORITY_SIZE - 17000) : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) + nMinFee = 0; } // To limit dust spam, require base fee if any output is less than 0.01 @@ -668,14 +746,6 @@ int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree nMinFee = nBaseFee; } - // Raise the price as the block approaches full - if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) - { - if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) - return MAX_MONEY; - nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); - } - if (!MoneyRange(nMinFee)) nMinFee = MAX_MONEY; return nMinFee; @@ -712,7 +782,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); // Rather not work on nonstandard transactions (unless -testnet) - if (!fTestNet && !IsStandardTx(tx)) + if (!TestNet() && !IsStandardTx(tx)) return error("CTxMemPool::accept() : nonstandard transaction type"); // is it already in the memory pool? @@ -787,7 +857,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr } // Check for non-standard pay-to-script-hash in inputs - if (!AreInputsStandard(tx, view) && !fTestNet) + if (!TestNet() && !AreInputsStandard(tx, view)) return error("CTxMemPool::accept() : nonstandard transaction input"); // Note: if you modify this code to accept non-standard transactions, then @@ -798,7 +868,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Don't accept it if it can't get into a block - int64 txMinFee = GetMinFee(tx, 1000, true, GMF_RELAY); + int64 txMinFee = GetMinFee(tx, true, GMF_RELAY); if (fLimitFree && nFees < txMinFee) return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, hash.ToString().c_str(), @@ -1044,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (pindexSlow) { CBlock block; - if (block.ReadFromDisk(pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1076,12 +1146,62 @@ CBlockIndex* FindBlockByHeight(int nHeight) return vBlockIndexByHeight[nHeight]; } -bool CBlock::ReadFromDisk(const CBlockIndex* pindex) +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("WriteBlockToDisk() : OpenBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(block); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write block + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("WriteBlockToDisk() : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +{ + block.SetNull(); + + // Open history file to read + CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed"); + + // Read block + try { + filein >> block; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Check the header + if (!CheckProofOfWork(block.GetHash(), block.nBits)) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header"); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) { - if (!ReadFromDisk(pindex->GetBlockPos())) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) return false; - if (GetHash() != pindex->GetBlockHash()) - return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); + if (block.GetHash() != pindex->GetBlockHash()) + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index"); return true; } @@ -1097,8 +1217,8 @@ int64 static GetBlockValue(int nHeight, int64 nFees) { int64 nSubsidy = 50 * COIN; - // Subsidy is cut in half every 210000 blocks, which will occur approximately every 4 years - nSubsidy >>= (nHeight / 210000); + // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. + nSubsidy >>= (nHeight / Params().SubsidyHalvingInterval()); return nSubsidy + nFees; } @@ -1113,28 +1233,29 @@ static const int64 nInterval = nTargetTimespan / nTargetSpacing; // unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) { + const CBigNum &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after nTargetSpacing*2 time between blocks: - if (fTestNet && nTime > nTargetSpacing*2) - return bnProofOfWorkLimit.GetCompact(); + if (TestNet() && nTime > nTargetSpacing*2) + return bnLimit.GetCompact(); CBigNum bnResult; bnResult.SetCompact(nBase); - while (nTime > 0 && bnResult < bnProofOfWorkLimit) + while (nTime > 0 && bnResult < bnLimit) { // Maximum 400% adjustment... bnResult *= 4; // ... in best-case exactly 4-times-normal target time nTime -= nTargetTimespan*4; } - if (bnResult > bnProofOfWorkLimit) - bnResult = bnProofOfWorkLimit; + if (bnResult > bnLimit) + bnResult = bnLimit; return bnResult.GetCompact(); } unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { - unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact(); + unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact(); // Genesis block if (pindexLast == NULL) @@ -1143,9 +1264,9 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl // Only change once per interval if ((pindexLast->nHeight+1) % nInterval != 0) { - // Special difficulty rule for testnet: - if (fTestNet) + if (TestNet()) { + // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes // then allow mining of a min-difficulty block. if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2) @@ -1159,7 +1280,6 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl return pindex->nBits; } } - return pindexLast->nBits; } @@ -1183,8 +1303,8 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl bnNew *= nActualTimespan; bnNew /= nTargetTimespan; - if (bnNew > bnProofOfWorkLimit) - bnNew = bnProofOfWorkLimit; + if (bnNew > Params().ProofOfWorkLimit()) + bnNew = Params().ProofOfWorkLimit(); /// debug print printf("GetNextWorkRequired RETARGET\n"); @@ -1201,7 +1321,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) bnTarget.SetCompact(nBits); // Check range - if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit) + if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit()) return error("CheckProofOfWork() : nBits below minimum work"); // Check proof of work matches claimed amount @@ -1319,7 +1439,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); // Updating time can change work required on testnet: - if (fTestNet) + if (TestNet()) block.nBits = GetNextWorkRequired(pindexPrev, &block); } @@ -1483,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach -bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean) +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { assert(pindex == view.GetBestBlock()); @@ -1499,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) return error("DisconnectBlock() : failure reading undo data"); - if (blockUndo.vtxundo.size() + 1 != vtx.size()) + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) return error("DisconnectBlock() : block and undo data inconsistent"); // undo transactions in reverse order - for (int i = vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = vtx[i]; + for (int i = block.vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); // check that all outputs are available @@ -1597,10 +1717,10 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } -bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck) +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock(state, !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -1608,7 +1728,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (GetHash() == hashGenesisBlock) { + if (block.GetHash() == Params().HashGenesisBlock()) { view.SetBestBlock(pindex); pindexGenesisBlock = pindex; return true; @@ -1632,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); if (fEnforceBIP30) { - for (unsigned int i=0; i<vtx.size(); i++) { - uint256 hash = GetTxHash(i); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + uint256 hash = block.GetTxHash(i); if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction")); } @@ -1654,12 +1774,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi int64 nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; - CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size())); + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector<std::pair<uint256, CDiskTxPos> > vPos; - vPos.reserve(vtx.size()); - for (unsigned int i=0; i<vtx.size(); i++) + vPos.reserve(block.vtx.size()); + for (unsigned int i = 0; i < block.vtx.size(); i++) { - const CTransaction &tx = vtx[i]; + const CTransaction &tx = block.vtx[i]; nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); @@ -1690,19 +1810,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi } CTxUndo txundo; - UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i)); + UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i)); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); - vPos.push_back(std::make_pair(GetTxHash(i), pos)); + vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } int64 nTime = GetTimeMicros() - nStart; if (fBenchmark) - printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); - if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) - return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees))); + if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) + return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees))); if (!control.Wait()) return state.DoS(100, false); @@ -1743,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi assert(view.SetBestBlock(pindex)); // Watch for transactions paying to me - for (unsigned int i=0; i<vtx.size(); i++) - SyncWithWallets(GetTxHash(i), vtx[i], this, true); + for (unsigned int i = 0; i < block.vtx.size(); i++) + SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true); return true; } @@ -1790,10 +1910,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector<CTransaction> vResurrect; BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); - if (!block.DisconnectBlock(state, pindex, view)) + if (!DisconnectBlock(block, state, pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); if (fBenchmark) printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); @@ -1810,10 +1930,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector<CTransaction> vDelete; BOOST_FOREACH(CBlockIndex *pindex, vConnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); - if (!block.ConnectBlock(state, pindex, view)) { + if (!ConnectBlock(block, state, pindex, view)) { if (state.IsInvalid()) { InvalidChainFound(pindexNew); InvalidBlockFound(pindex); @@ -1923,25 +2043,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) } -bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str())); // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(*this); + CBlockIndex* pindexNew = new CBlockIndex(block); assert(pindexNew); map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); - map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock); + map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->nTx = vtx.size(); + pindexNew->nTx = block.vtx.size(); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; pindexNew->nFile = pos.nFile; @@ -1962,7 +2082,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = GetTxHash(0); + hashPrevBestCoinBase = block.GetTxHash(0); } if (!pblocktree->Flush()) @@ -2068,51 +2188,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne } -bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) return state.DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp - if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return state.Invalid(error("CheckBlock() : block timestamp too far in the future")); // First transaction must be coinbase, the rest must not be - if (vtx.empty() || !vtx[0].IsCoinBase()) + if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase")); - for (unsigned int i = 1; i < vtx.size(); i++) - if (vtx[i].IsCoinBase()) + for (unsigned int i = 1; i < block.vtx.size(); i++) + if (block.vtx[i].IsCoinBase()) return state.DoS(100, error("CheckBlock() : more than one coinbase")); // Check transactions - BOOST_FOREACH(const CTransaction& tx, vtx) + BOOST_FOREACH(const CTransaction& tx, block.vtx) if (!CheckTransaction(tx, state)) return error("CheckBlock() : CheckTransaction failed"); // Build the merkle tree already. We need it anyway later, and it makes the // block cache the transaction hashes, which means they don't need to be // recalculated many times during this block's validation. - BuildMerkleTree(); + block.BuildMerkleTree(); // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: set<uint256> uniqueTx; - for (unsigned int i=0; i<vtx.size(); i++) { - uniqueTx.insert(GetTxHash(i)); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + uniqueTx.insert(block.GetTxHash(i)); } - if (uniqueTx.size() != vtx.size()) + if (uniqueTx.size() != block.vtx.size()) return state.DoS(100, error("CheckBlock() : duplicate transaction")); unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, vtx) + BOOST_FOREACH(const CTransaction& tx, block.vtx) { nSigOps += GetLegacySigOpCount(tx); } @@ -2120,40 +2240,40 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); // Check merkle root - if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) + if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree()) return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return true; } -bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex")); // Get prev block index CBlockIndex* pindexPrev = NULL; int nHeight = 0; - if (hash != hashGenesisBlock) { - map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); + if (hash != Params().HashGenesisBlock()) { + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) return state.DoS(10, error("AcceptBlock() : prev block not found")); pindexPrev = (*mi).second; nHeight = pindexPrev->nHeight+1; // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev, this)) + if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) return state.DoS(100, error("AcceptBlock() : incorrect proof of work")); // Check timestamp against prev - if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) + if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, vtx) - if (!IsFinalTx(tx, nHeight, GetBlockTime())) + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); // Check that the block chain matches the known block chain up to a checkpoint @@ -2161,23 +2281,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (nVersion < 2) + if (block.nVersion < 2) { - if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || - (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) + if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || + (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) { return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block")); } } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (nVersion >= 2) + if (block.nVersion >= 2) { // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || - (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) + if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || + (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) { CScript expect = CScript() << nHeight; - if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } @@ -2185,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) // Write block to history file try { - unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; if (dbp != NULL) blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) - if (!WriteToDisk(blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); } catch(std::runtime_error &e) { return state.Abort(_("System error: ") + e.what()); @@ -2246,7 +2366,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str())); // Preliminary checks - if (!pblock->CheckBlock(state)) + if (!CheckBlock(*pblock, state)) return error("ProcessBlock() : CheckBlock FAILED"); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); @@ -2287,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } // Store to disk - if (!pblock->AcceptBlock(state, dbp)) + if (!AcceptBlock(*pblock, state, dbp)) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2303,7 +2423,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl CBlock* pblockOrphan = (*mi).second; // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) CValidationState stateDummy; - if (pblockOrphan->AcceptBlock(stateDummy)) + if (AcceptBlock(*pblockOrphan, stateDummy)) vWorkQueue.push_back(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash()); delete pblockOrphan; @@ -2616,14 +2736,13 @@ bool static LoadBlockIndexDB() return true; } -bool VerifyDB() { +bool VerifyDB(int nCheckLevel, int nCheckDepth) +{ if (pindexBest == NULL || pindexBest->pprev == NULL) return true; // Verify blocks in the best chain - int nCheckLevel = GetArg("-checklevel", 3); - int nCheckDepth = GetArg( "-checkblocks", 288); - if (nCheckDepth == 0) + if (nCheckDepth <= 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; @@ -2641,10 +2760,10 @@ bool VerifyDB() { break; CBlock block; // check level 0: read from disk - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 1: verify block validity - if (nCheckLevel >= 1 && !block.CheckBlock(state)) + if (nCheckLevel >= 1 && !CheckBlock(block, state)) return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { @@ -2658,7 +2777,7 @@ bool VerifyDB() { // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) { bool fClean = true; - if (!block.DisconnectBlock(state, pindex, coins, &fClean)) + if (!DisconnectBlock(block, state, pindex, coins, &fClean)) return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexState = pindex->pprev; if (!fClean) { @@ -2678,9 +2797,9 @@ bool VerifyDB() { boost::this_thread::interruption_point(); pindex = pindex->GetNextInMainChain(); CBlock block; - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); - if (!block.ConnectBlock(state, pindex, coins)) + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ConnectBlock(block, state, pindex, coins)) return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); } } @@ -2704,21 +2823,9 @@ void UnloadBlockIndex() bool LoadBlockIndex() { - if (fTestNet) - { - pchMessageStart[0] = 0x0b; - pchMessageStart[1] = 0x11; - pchMessageStart[2] = 0x09; - pchMessageStart[3] = 0x07; - hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); - } - - // // Load block index from databases - // if (!fReindex && !LoadBlockIndexDB()) return false; - return true; } @@ -2735,55 +2842,17 @@ bool InitBlockIndex() { // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) if (!fReindex) { - // Genesis Block: - // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) - // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) - // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) - // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) - // vMerkleTree: 4a5e1e - - // Genesis block - const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; - CTransaction txNew; - txNew.vin.resize(1); - txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].nValue = 50 * COIN; - txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; - CBlock block; - block.vtx.push_back(txNew); - block.hashPrevBlock = 0; - block.hashMerkleRoot = block.BuildMerkleTree(); - block.nVersion = 1; - block.nTime = 1231006505; - block.nBits = 0x1d00ffff; - block.nNonce = 2083236893; - - if (fTestNet) - { - block.nTime = 1296688602; - block.nNonce = 414098458; - } - - //// debug print - uint256 hash = block.GetHash(); - printf("%s\n", hash.ToString().c_str()); - printf("%s\n", hashGenesisBlock.ToString().c_str()); - printf("%s\n", block.hashMerkleRoot.ToString().c_str()); - assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); - block.print(); - assert(hash == hashGenesisBlock); - - // Start new block file try { + CBlock &block = const_cast<CBlock&>(Params().GenesisBlock()); + // Start new block file unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; CValidationState state; if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) return error("LoadBlockIndex() : FindBlockPos failed"); - if (!block.WriteToDisk(blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); @@ -2839,7 +2908,7 @@ void PrintBlockTree() // print item CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", pindex->nHeight, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, @@ -2892,10 +2961,10 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) try { // locate a header unsigned char buf[4]; - blkdat.FindByte(pchMessageStart[0]); + blkdat.FindByte(Params().MessageStart()[0]); nRewind = blkdat.GetPos()+1; blkdat >> FLATDATA(buf); - if (memcmp(buf, pchMessageStart, 4)) + if (memcmp(buf, Params().MessageStart(), 4)) continue; // read size blkdat >> nSize; @@ -3040,12 +3109,6 @@ bool static AlreadyHave(const CInv& inv) -// The message start string is designed to be unlikely to occur in normal data. -// The characters are rarely used upper ASCII, not valid as UTF-8, and produce -// a large 4-byte int at any alignment. -unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; - - void static ProcessGetData(CNode* pfrom) { std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); @@ -3069,7 +3132,7 @@ void static ProcessGetData(CNode* pfrom) if (mi != mapBlockIndex.end()) { CBlock block; - block.ReadFromDisk((*mi).second); + ReadBlockFromDisk(block, (*mi).second); if (inv.type == MSG_BLOCK) pfrom->PushMessage("block", block); else // MSG_FILTERED_BLOCK) @@ -3768,7 +3831,7 @@ bool ProcessMessages(CNode* pfrom) it++; // Scan for message start - if (memcmp(msg.hdr.pchMessageStart, pchMessageStart, sizeof(pchMessageStart)) != 0) { + if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) { printf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n"); fOk = false; break; @@ -4186,7 +4249,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); + unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions @@ -4314,7 +4377,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) // Prioritize by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && - ((nBlockSize + nTxSize >= nBlockPrioritySize) || (dPriority < COIN * 144 / 250))) + ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) { fSortedByFee = true; comparer = TxPriorityCompare(fSortedByFee); @@ -4391,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) indexDummy.nHeight = pindexPrev->nHeight + 1; CCoinsViewCache viewNew(*pcoinsTip, true); CValidationState state; - if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true)) + if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); } @@ -4512,8 +4575,12 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nExtraNonce = 0; try { loop { - while (vNodes.empty()) - MilliSleep(1000); + if (Params().NetworkID() != CChainParams::REGTEST) { + // Busy-wait for the network to come online so we don't waste time mining + // on an obsolete chain. In regtest mode we expect to fly solo. + while (vNodes.empty()) + MilliSleep(1000); + } // // Create new block @@ -4575,6 +4642,12 @@ void static BitcoinMiner(CWallet *pwallet) SetThreadPriority(THREAD_PRIORITY_NORMAL); CheckWork(pblock, *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); + + // In regression test mode, stop mining after a block is found. This + // allows developers to controllably generate a block on demand. + if (Params().NetworkID() == CChainParams::REGTEST) + throw boost::thread_interrupted(); + break; } } @@ -4610,7 +4683,7 @@ void static BitcoinMiner(CWallet *pwallet) // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); - if (vNodes.empty()) + if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) break; if (nBlockNonce >= 0xffff0000) break; @@ -4622,7 +4695,7 @@ void static BitcoinMiner(CWallet *pwallet) // Update nTime every few seconds UpdateTime(*pblock, pindexPrev); nBlockTime = ByteReverse(pblock->nTime); - if (fTestNet) + if (TestNet()) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); @@ -4642,8 +4715,12 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet) static boost::thread_group* minerThreads = NULL; int nThreads = GetArg("-genproclimit", -1); - if (nThreads < 0) - nThreads = boost::thread::hardware_concurrency(); + if (nThreads < 0) { + if (Params().NetworkID() == CChainParams::REGTEST) + nThreads = 1; + else + nThreads = boost::thread::hardware_concurrency(); + } if (minerThreads != NULL) { diff --git a/src/main.h b/src/main.h index 87f1dbfa8f..9e0235fa57 100644 --- a/src/main.h +++ b/src/main.h @@ -52,6 +52,8 @@ static const int COINBASE_MATURITY = 100; static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC /** Maximum number of script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 16; +/** Default amount of block size reserved for high-priority transactions (in bytes) */ +static const int DEFAULT_BLOCK_PRIORITY_SIZE = 27000; #ifdef USE_UPNP static const int fHaveUPnP = true; #else @@ -70,7 +72,6 @@ extern CCriticalSection cs_main; extern std::map<uint256, CBlockIndex*> mapBlockIndex; extern std::vector<CBlockIndex*> vBlockIndexByHeight; extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; -extern uint256 hashGenesisBlock; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; extern uint256 nBestChainWork; @@ -86,7 +87,6 @@ extern int64 nHPSTimerStart; extern int64 nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; extern std::set<CWallet*> setpwalletRegistered; -extern unsigned char pchMessageStart[4]; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; @@ -146,7 +146,7 @@ bool LoadBlockIndex(); /** Unload database information */ void UnloadBlockIndex(); /** Verify consistency of the block and coin databases */ -bool VerifyDB(); +bool VerifyDB(int nCheckLevel, int nCheckDepth); /** Print the loaded block tree */ void PrintBlockTree(); /** Find a block by height in the currently-connected chain */ @@ -262,12 +262,11 @@ struct CDiskTxPos : public CDiskBlockPos enum GetMinFee_mode { - GMF_BLOCK, GMF_RELAY, GMF_SEND, }; -int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK); +int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode); // // Check transaction inputs, and make sure any @@ -353,7 +352,7 @@ public: // Write index header unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(pchMessageStart) << nSize; + fileout << FLATDATA(Params().MessageStart()) << nSize; // Write undo data long fileOutPos = ftell(fileout); @@ -582,204 +581,33 @@ public: }; -class CBlock : public CBlockHeader -{ -public: - // network and disk - std::vector<CTransaction> vtx; - // memory only - mutable std::vector<uint256> vMerkleTree; +/** Functions for disk access for blocks */ +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); - CBlock() - { - SetNull(); - } - CBlock(const CBlockHeader &header) - { - SetNull(); - *((CBlockHeader*)this) = header; - } +/** Functions for validating blocks and updating the block tree */ - IMPLEMENT_SERIALIZE - ( - READWRITE(*(CBlockHeader*)this); - READWRITE(vtx); - ) +/** Undo the effects of this block (with given index) on the UTXO set represented by coins. + * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean + * will be true if no problems were found. Otherwise, the return value will be false in case + * of problems. Note that in any case, coins may be modified. */ +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); - void SetNull() - { - CBlockHeader::SetNull(); - vtx.clear(); - vMerkleTree.clear(); - } +// Apply the effects of this block (with given index) on the UTXO set represented by coins +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrevBlock; - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - uint256 BuildMerkleTree() const - { - vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) - vMerkleTree.push_back(tx.GetHash()); - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - for (int i = 0; i < nSize; i += 2) - { - int i2 = std::min(i+1, nSize-1); - vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), - BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); - } - j += nSize; - } - return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); - } - - const uint256 &GetTxHash(unsigned int nIndex) const { - assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first - assert(nIndex < vtx.size()); - return vMerkleTree[nIndex]; - } - - std::vector<uint256> GetMerkleBranch(int nIndex) const - { - if (vMerkleTree.empty()) - BuildMerkleTree(); - std::vector<uint256> vMerkleBranch; - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - int i = std::min(nIndex^1, nSize-1); - vMerkleBranch.push_back(vMerkleTree[j+i]); - nIndex >>= 1; - j += nSize; - } - return vMerkleBranch; - } - - static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) - { - if (nIndex == -1) - return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) - { - if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); - else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); - nIndex >>= 1; - } - return hash; - } - - bool WriteToDisk(CDiskBlockPos &pos) - { - // Open history file to append - CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CBlock::WriteToDisk() : OpenBlockFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(pchMessageStart) << nSize; - - // Write block - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlock::WriteToDisk() : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; - } - - bool ReadFromDisk(const CDiskBlockPos &pos) - { - SetNull(); - - // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); - - // Read block - try { - filein >> *this; - } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); - } - - // Check the header - if (!CheckProofOfWork(GetHash(), nBits)) - return error("CBlock::ReadFromDisk() : errors in block header"); - - return true; - } - - - - void print() const - { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", - GetHash().ToString().c_str(), - nVersion, - hashPrevBlock.ToString().c_str(), - hashMerkleRoot.ToString().c_str(), - nTime, nBits, nNonce, - vtx.size()); - for (unsigned int i = 0; i < vtx.size(); i++) - { - printf(" "); - vtx[i].print(); - } - printf(" vMerkleTree: "); - for (unsigned int i = 0; i < vMerkleTree.size(); i++) - printf("%s ", vMerkleTree[i].ToString().c_str()); - printf("\n"); - } - - - /** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ - bool DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL); - - // Apply the effects of this block (with given index) on the UTXO set represented by coins - bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); - - // Read a block from disk - bool ReadFromDisk(const CBlockIndex* pindex); - - // Add this block to the block index, and if necessary, switch the active block chain to this - bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); - - // Context-independent validity checks - bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; - - // Store block on disk - // if dbp is provided, the file is known to already reside on disk - bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL); -}; +// Add this block to the block index, and if necessary, switch the active block chain to this +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos); +// Context-independent validity checks +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +// Store block on disk +// if dbp is provided, the file is known to already reside on disk +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL); @@ -1202,22 +1030,14 @@ class CBlockLocator protected: std::vector<uint256> vHave; public: - - CBlockLocator() - { - } + CBlockLocator() {} explicit CBlockLocator(const CBlockIndex* pindex) { Set(pindex); } - explicit CBlockLocator(uint256 hashBlock) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end()) - Set((*mi).second); - } + explicit CBlockLocator(uint256 hashBlock); CBlockLocator(const std::vector<uint256>& vHaveIn) { @@ -1241,83 +1061,16 @@ public: return vHave.empty(); } - void Set(const CBlockIndex* pindex) - { - vHave.clear(); - int nStep = 1; - while (pindex) - { - vHave.push_back(pindex->GetBlockHash()); - - // Exponentially larger steps back - for (int i = 0; pindex && i < nStep; i++) - pindex = pindex->pprev; - if (vHave.size() > 10) - nStep *= 2; - } - vHave.push_back(hashGenesisBlock); - } - - int GetDistanceBack() - { - // Retrace how far back it was in the sender's branch - int nDistance = 0; - int nStep = 1; - BOOST_FOREACH(const uint256& hash, vHave) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (pindex->IsInMainChain()) - return nDistance; - } - nDistance += nStep; - if (nDistance > 10) - nStep *= 2; - } - return nDistance; - } - - CBlockIndex* GetBlockIndex() - { - // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (pindex->IsInMainChain()) - return pindex; - } - } - return pindexGenesisBlock; - } - - uint256 GetBlockHash() - { - // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (pindex->IsInMainChain()) - return hash; - } - } - return hashGenesisBlock; - } - - int GetHeight() - { - CBlockIndex* pindex = GetBlockIndex(); - if (!pindex) - return 0; - return pindex->nHeight; - } + /** Given a block initialises the locator to that point in the chain. */ + void Set(const CBlockIndex* pindex); + /** Returns the distance in blocks this locator is from our chain head. */ + int GetDistanceBack(); + /** Returns the first best-chain block the locator contains. */ + CBlockIndex* GetBlockIndex(); + /** Returns the hash of the first best chain block the locator contains. */ + uint256 GetBlockHash(); + /** Returns the height of the first best chain block the locator has. */ + int GetHeight(); }; diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 9cfab5942a..26d541664e 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -93,7 +93,8 @@ OBJS= \ obj/hash.o \ obj/bloom.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o all: bitcoind.exe diff --git a/src/makefile.mingw b/src/makefile.mingw index 33cc7e6b4a..3659f52040 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -101,7 +101,8 @@ OBJS= \ obj/bloom.o \ obj/noui.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o all: bitcoind.exe diff --git a/src/makefile.osx b/src/makefile.osx index bef0ef3518..269460c1ba 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -104,7 +104,8 @@ OBJS= \ obj/bloom.o \ obj/noui.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o ifndef USE_UPNP override USE_UPNP = - diff --git a/src/makefile.unix b/src/makefile.unix index a83bab1047..f17de05cb9 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -143,7 +143,8 @@ OBJS= \ obj/bloom.o \ obj/noui.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o all: bitcoind diff --git a/src/net.cpp b/src/net.cpp index 1f8b39ac98..0adf26ef0d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "db.h" #include "net.h" #include "core.h" @@ -80,7 +81,7 @@ void AddOneShot(string strDest) unsigned short GetListenPort() { - return (unsigned short)(GetArg("-port", GetDefaultPort())); + return (unsigned short)(GetArg("-port", Params().GetDefaultPort())); } // find 'best' local address for a particular peer @@ -464,7 +465,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) // Connect SOCKET hSocket; - if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket)) + if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort()) : ConnectSocket(addrConnect, hSocket)) { addrman.Attempt(addrConnect); @@ -533,7 +534,7 @@ void CNode::PushVersion() RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str()); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight); + nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true); } @@ -1170,53 +1171,31 @@ void MapPort(bool) - - - -// DNS seeds -// Each pair gives a source name and a seed name. -// The first name is used as information source for addrman. -// The second name should resolve to a list of seed addresses. -static const char *strMainNetDNSSeed[][2] = { - {"bitcoin.sipa.be", "seed.bitcoin.sipa.be"}, - {"bluematt.me", "dnsseed.bluematt.me"}, - {"dashjr.org", "dnsseed.bitcoin.dashjr.org"}, - {"xf2.org", "bitseed.xf2.org"}, - {NULL, NULL} -}; - -static const char *strTestNetDNSSeed[][2] = { - {"bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"}, - {"bluematt.me", "testnet-seed.bluematt.me"}, - {NULL, NULL} -}; - void ThreadDNSAddressSeed() { - static const char *(*strDNSSeed)[2] = fTestNet ? strTestNetDNSSeed : strMainNetDNSSeed; - + const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds(); int found = 0; printf("Loading addresses from DNS seeds (could take a while)\n"); - for (unsigned int seed_idx = 0; strDNSSeed[seed_idx][0] != NULL; seed_idx++) { + BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) { if (HaveNameProxy()) { - AddOneShot(strDNSSeed[seed_idx][1]); + AddOneShot(seed.host); } else { - vector<CNetAddr> vaddr; + vector<CNetAddr> vIPs; vector<CAddress> vAdd; - if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) + if (LookupHost(seed.host.c_str(), vIPs)) { - BOOST_FOREACH(CNetAddr& ip, vaddr) + BOOST_FOREACH(CNetAddr& ip, vIPs) { int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, GetDefaultPort())); + CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); found++; } } - addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); + addrman.Add(vAdd, CNetAddr(seed.name, true)); } } @@ -1234,85 +1213,6 @@ void ThreadDNSAddressSeed() -unsigned int pnSeed[] = -{ - 0xe473042e, 0xb177f2ad, 0xd63f3fb2, 0xf864f736, 0x44a23ac7, 0xcf6d9650, 0xd648042e, 0x0536f447, - 0x3c654ed0, 0x3e16a5bc, 0xa38e09b0, 0xdfae795b, 0xabfeca5b, 0x94ad7840, 0xf3b9f1c7, 0xbe70e0ad, - 0x3bbd09b0, 0x8d0c7dd5, 0x3b2a7332, 0x1a06175e, 0x581f175e, 0xca0d2dcc, 0x0fdbc658, 0xcf591ec7, - 0x295a12b2, 0xb4707bce, 0x68bb09b0, 0x4e735747, 0x89709553, 0x05a7814e, 0x5b8ec658, 0x402c5512, - 0xe80d0905, 0x17681a5e, 0xc02aa748, 0x9f811741, 0x5f321cb0, 0x23e1ee47, 0xaf7f170c, 0xaa240ab0, - 0xedea6257, 0x76106bc1, 0x2cf310cc, 0x08612acb, 0x9c682e4e, 0x8e963c6c, 0x443c795b, 0x22e246b8, - 0xfa1f2dcc, 0x90118140, 0x3821042e, 0x33c3fd2e, 0x10046d5b, 0x40d14b3e, 0x7fb8f8ce, 0x67696550, - 0xeeecbe58, 0x4f341745, 0x46b8fbd5, 0xc8463932, 0x6b73e862, 0x4c715932, 0x4a6785d5, 0xce3a64c2, - 0xde9604c7, 0x9b06884f, 0x18002a45, 0xea9bc345, 0xc4f1c658, 0xe475c1c7, 0xdd3e795b, 0x9722175e, - 0x34562f4e, 0x66c46e4e, 0x40bb1243, 0x7d9171d0, 0x17b8dbd5, 0x63cbfd2e, 0x1a08b8d8, 0x6175a73b, - 0x228d2660, 0x8627c658, 0x9c566644, 0x38cca5bc, 0x3089de5b, 0x92e25f5d, 0xa393f73f, 0xcc92dc3e, - 0x27487446, 0x62cbfd2e, 0x9d983b45, 0xf72a09b0, 0xf75f042e, 0x6434bb6a, 0xb29e77d8, 0x19be4fd9, - 0x76443243, 0x9dd72645, 0x694cef43, 0x89c2efd5, 0x5f1c5058, 0x46c6e45b, 0xe1391b40, 0x77ccefd5, - 0x472e5a6d, 0x85709553, 0xdd4f5d4c, 0x64ef5a46, 0x7f0ae502, 0xcf08d850, 0x3460042e, 0xeafa2d42, - 0x793c9044, 0x9d094746, 0x1ab9b153, 0xbfe9a5bc, 0x34771fb0, 0xb7722e32, 0x1168964b, 0x19b06ab8, - 0x19243b25, 0x13188045, 0xb4070905, 0x728ebb5d, 0x44f24ac8, 0xa317fead, 0x642f6a57, 0x3d951f32, - 0x3d312e4e, 0xfac4d048, 0xefc4dd50, 0x52b9f1c7, 0xc14d3cc3, 0x0219ea44, 0x3b79d058, 0xfa217242, - 0x39c80647, 0xfb697252, 0x1d495a42, 0x0aa81f4e, 0x58249ab8, 0xe6a8e6c3, 0x2bc4dad8, 0x85963c6c, - 0xa4ce09b0, 0x2005f536, 0x5cc2703e, 0x1992de43, 0x74e86b4c, 0xe7085653, 0xf5e15a51, 0xb4872b60, - 0x29e2b162, 0xa07ea053, 0x8229fd18, 0x4562ec4d, 0x8dec814e, 0x36cfa4cf, 0x96461032, 0x3c8770de, - 0xd10a1f5f, 0x95934641, 0x97cd65d0, 0x2e35324a, 0x2566ba1f, 0x1ca1a9d1, 0xb808b8d5, 0xf9a24a5d, - 0xafc8d431, 0xe4b8d9b2, 0x0f5321b2, 0x330bc658, 0x74b347ce, 0x972babd5, 0x044f7d4f, 0x06562f4e, - 0x8b8d3c6c, 0x3507c658, 0xe4174e4d, 0xf1c009b0, 0x52249ab8, 0x27211772, 0xf6a9ba59, 0x7a391b40, - 0x855dc6c0, 0x291f20b2, 0xe29bc345, 0x90963c6c, 0x0af70732, 0x4242a91f, 0x4c531d48, 0xa32df948, - 0x627e3044, 0x65be1f54, 0x1a0cbf83, 0x6a443532, 0x8d5f1955, 0xbafa8132, 0x3534bdd5, 0xca019dd9, - 0x8a0d9332, 0x5584e7d8, 0x7cd1f25e, 0xeabe3fb2, 0x2945d0d1, 0x46415718, 0x70d6042e, 0x99eb76d0, - 0x9ece09b0, 0xb3777418, 0x5e5e91d9, 0x237a3ab0, 0xf512b62e, 0x45dec347, 0x59b7f862, 0x4c443b25, - 0x3cc6484b, 0x9a8ec6d1, 0x021eea44, 0xc9483944, 0xfd567e32, 0xfd204bb2, 0xc5330bcc, 0x5202894e, - 0xf9e309b0, 0x4cc17557, 0xdb9064ae, 0xe19e77d8, 0x25857f60, 0xeb4a15ad, 0x1f47f554, 0xea4472d9, - 0xd20de593, 0xf5733b25, 0x11892b54, 0x5729d35f, 0xe6188cd1, 0x488b132e, 0x541c534a, 0xa8e854ae, - 0xa255a66c, 0x33688763, 0xc6629ac6, 0xc20a6265, 0xcd92a059, 0x72029d3b, 0x4c298f5e, 0x51452e4e, - 0xbb065058, 0x15fd2dcc, 0xf40c135e, 0x615a0bad, 0x0c6a6805, 0x4971a7ad, 0x17f2a5d5, 0xf8babf47, - 0xb61f50ad, 0x4e1451b1, 0xf72d9252, 0x5c2abe58, 0xbd987c61, 0x084ae5cf, 0x20781fb0, 0x38b0f160, - 0x18aac705, 0x14f86dc1, 0x5556f481, 0x0a36c144, 0xeb446e4c, 0x2c1c0d6c, 0xbd0ff860, 0x869f92db, - 0x36c94f4c, 0x05502444, 0x148fe55b, 0xd5301e59, 0xd57a8f45, 0x110dc04a, 0x8670fc36, 0xee733b25, - 0xca56f481, 0x2a5c3bae, 0x844b0905, 0x1e51fe53, 0x0241c244, 0x59c0614e, 0x94e70a55, 0x7312fead, - 0xb735be44, 0xa55d0905, 0x2f63962e, 0x14a4e15b, 0x63f8f05c, 0x62d0d262, 0x3cab41ad, 0x87f1b1cb, - 0x018da6b8, 0xb3967dd5, 0xcb56f481, 0x685ad718, 0x3b4aeeca, 0x8d106bc1, 0x51180905, 0x72660f48, - 0x1521a243, 0x5b56f481, 0x6390e560, 0xdd61464e, 0x58353b25, 0x553fc062, 0x27c45d59, 0xacc62e4e, - 0x0d5a1cd9, 0x7f65f442, 0xbdeef660, 0xf1bd1855, 0xf8473cae, 0x13b120b2, 0x442440d0, 0x53fd4352, - 0xa305fc57, 0x458be84d, 0x639ce1c3, 0xebaaee47, 0x95e2c247, 0xf056f481, 0x6256f481, 0x1d87c65e, - 0x0a453418, 0x5beb175e, 0xd64f1618, 0xc360795b, 0x2fbf5753, 0xa8c58e53, 0x651cec52, 0x9d37b043, - 0x124a9758, 0x5242e4a9, 0x89913c6c, 0x880efe2e, 0x2f2f2f0c, 0x72b26751, 0x2896e46d, 0x80f4166c, - 0x320d59ad, 0xc50151d0, 0x11a8aa43, 0xccf56057, 0x5fbad118, 0x4719b151, 0x2b5f4bc0, 0x4d7a4a50, - 0xad06e047, 0x62ef5a46, 0x5aebde58, 0xdf7aa66c, 0x851acb50, 0x66b9a559, 0x3e9bb153, 0xcc512f2e, - 0xc073b08e, 0xd519be58, 0xe981ea4d, 0x12fd50cb, 0x378739ad, 0x06683cae, 0xa22310b2, 0xc185c705, - 0x8741b545, 0xa26c8318, 0x22d5bc43, 0x39201ec0, 0x68581e3e, 0xdc9bcf62, 0xd508cc82, 0xb149675b, - 0x4c9609b0, 0x84feb84c, 0x08291e2e, 0xfd2253b2, 0x1fd269c1, 0xc9483932, 0x4d641fb0, 0x7d37c918, - 0xa9de20ad, 0x77e2d655, 0x6d421b59, 0xd7668f80, 0xced09b62, 0xa9e5a5bc, 0xa4074e18, 0x60fc5ecc, - 0x01300148, 0x68062444, 0xb4224847, 0xed3aa443, 0xb772fb43, 0x9f56f481, 0x220dfd18, 0x8e1c3d6c, - 0xc44f09b0, 0x7df2bb73, 0xe22fb844, 0xea534242, 0xb6a755d4, 0xa036654b, 0x138ece5b, 0xda65d3c3, - 0x955871bc, 0x792124b0, 0xfc82594c, 0x851d494b, 0x2c7aee47, 0x26af46b8, 0x1416252e, 0xa8abb944, - 0x36c49d25, 0x674f645d, 0x363646b8, 0x9e1a2942, 0x66d0c154, 0xc6c2a545, 0x3570f2ad, 0xe7d547c7, - 0x7d104932, 0x18cb9c18, 0x1dcfa4cf, 0xd156f481, 0x2a02b91f, 0x3eeb3fa8, 0xcac4175e, 0x34146d42, - 0x994c4d46, 0x5666f440, 0x85d6713e, 0x5ecb296c, 0x0ea0ae46, 0x87e69f42, 0xc58409b0, 0x1f3436ae, - 0x21dc6a57, 0x4ad1cd42, 0xfb8c1a4c, 0x52d3dab2, 0x3769894b, 0xb52f1c62, 0x3677916d, 0x82b3fe57, - 0x493d4ac6, 0x9f963c6c, 0x5d91ff60, 0x458e0dad, 0xa49d0947, 0x491a3e18, 0x4aadcd5b, 0x0e46494b, - 0x1d1610ad, 0x1a10af5d, 0x4956f481, 0x207a3eae, 0x77e73244, 0xfa3b8742, 0x3261fc36, 0xfcebf536, - 0x1662e836, 0xf655f636, 0xa2dbd0ad, 0x23036693, 0x30448432, 0xa2b03463, 0x30730344, 0x8e4a6882, - 0x0c50a1cb, 0xc8d8c06b, 0xc9cd6191, 0xf443db50, 0xa9553c50, 0x23145847, 0xc35da66c, 0x29c12a60, - 0x55c2b447, 0x7434f75c, 0x61660640, 0xde2a7018, 0xc639494c, 0x1c306fce, 0x19b89244, 0xd29a6462, - 0x462cd1b2, 0x29902f44, 0x2817fa53, 0x21a30905, 0x7777ae46, 0x288443a1, 0x7bee5148, 0xc2a8b043, - 0xf5c3d35f, 0x2311ef84, 0x57de08a4, 0x6b221bb2, 0xf2625846, 0x4b9e09b0, 0xa24f880e, 0x22b11447, - 0xb3a0c744, 0x919e77d8, 0xec8b64ae, 0xff5c8d45, 0x7b15b484, 0x32679a5f, 0xba80b62e, 0x05c25c61, - 0x60014746, 0x5e8fb04c, 0xe67c0905, 0x4329c658, 0xac8fe555, 0xf875e647, 0x67406386, 0x35ceea18, - 0xbb79484b, 0xd7b9fa62, 0x238209b0, 0x208a1d32, 0x9630995e, 0x039c1318, 0x6e48006c, 0x60582344, - 0xadbb0150, 0x853fd462, 0x03772e4e, 0x652ce960, 0x49b630ad, 0x9993af43, 0x3735b34b, 0x548a07d9, - 0x55a44aad, 0xa23d1bcc, 0xfdbb2f4e, 0x530b24a0, 0x0a44b451, 0x6827c657, 0x1f66494b, 0x4e680a47, - 0x77e7b747, 0xa5eb3fa8, 0x6649764a, 0xd4e76c4b, 0x2c691fb0, 0xf1292e44, 0xc6d6c774, 0x85d23775, - 0x28275f4d, 0x259ae46d, 0x02424e81, 0x5f16be58, 0xe707c658, 0x49eae5c7, 0xd5d147ad, 0x9a7abdc3, - 0xe8ac7fc7, 0x84ec3aae, 0xc24942d0, 0x294aa318, 0x08ac3d18, 0x8894042e, 0xb24609b0, 0x9bcaab58, - 0xc400f712, 0xd5c512b8, 0x2c02cc62, 0x25080fd8, 0xed74a847, 0x18a5ec5e, 0x9850ec6d, 0xf8909758, - 0x7f56f481, 0x4496f23c, 0xae27784f, 0xcb7cd93e, 0x06e32860, 0x50b9a84f, 0x3660434a, 0x09161f5f, - 0x900486bc, 0x08055459, 0xe7ec1017, 0x7e39494c, 0x4f443b25, 0x14751a8a, 0x717d03d4, 0xbd0e24d8, - 0x054b6f56, 0x854c496c, 0xd92a454a, 0xc39bd054, 0x6093614b, 0x9dbad754, 0x5bf0604a, 0x99f22305 -}; - void DumpAddresses() { int64 nStart = GetTimeMillis(); @@ -1374,24 +1274,14 @@ void ThreadOpenConnections() CSemaphoreGrant grant(*semOutbound); boost::this_thread::interruption_point(); - // Add seed nodes if IRC isn't working - if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) - { - std::vector<CAddress> vAdd; - for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) - { - // It'll only connect to one or two seed nodes because once it connects, - // it'll get a pile of addresses with newer timestamps. - // Seed nodes are given a random 'last seen time' of between one and two - // weeks ago. - const int64 nOneWeek = 7*24*60*60; - struct in_addr ip; - memcpy(&ip, &pnSeed[i], sizeof(ip)); - CAddress addr(CService(ip, GetDefaultPort())); - addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; - vAdd.push_back(addr); + // Add seed nodes if DNS seeds are all down (an infrastructure attack?). + if (addrman.size() == 0 && (GetTime() - nStart > 60)) { + static bool done = false; + if (!done) { + printf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); + addrman.Add(Params().FixedSeeds(), CNetAddr("127.0.0.1")); + done = true; } - addrman.Add(vAdd, CNetAddr("127.0.0.1")); } // @@ -1440,7 +1330,7 @@ void ThreadOpenConnections() continue; // do not allow non-default ports, unless after 50 invalid addresses selected already - if (addr.GetPort() != GetDefaultPort() && nTries < 50) + if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) continue; addrConnect = addr; @@ -1490,7 +1380,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(string& strAddNode, lAddresses) { vector<CService> vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) + if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { diff --git a/src/protocol.cpp b/src/protocol.cpp index 1e22467a33..745b4338e4 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -21,7 +21,7 @@ static const char* ppszTypeName[] = CMessageHeader::CMessageHeader() { - memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); memset(pchCommand, 0, sizeof(pchCommand)); pchCommand[1] = 1; nMessageSize = -1; @@ -30,7 +30,7 @@ CMessageHeader::CMessageHeader() CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) { - memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); strncpy(pchCommand, pszCommand, COMMAND_SIZE); nMessageSize = nMessageSizeIn; nChecksum = 0; @@ -47,7 +47,7 @@ std::string CMessageHeader::GetCommand() const bool CMessageHeader::IsValid() const { // Check start string - if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) + if (memcmp(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) return false; // Check the command string for errors diff --git a/src/protocol.h b/src/protocol.h index 4998425070..ae541dfdba 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -10,20 +10,12 @@ #ifndef __INCLUDED_PROTOCOL_H__ #define __INCLUDED_PROTOCOL_H__ +#include "chainparams.h" #include "serialize.h" #include "netbase.h" #include <string> #include "uint256.h" -extern bool fTestNet; -static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) -{ - return testnet ? 18333 : 8333; -} - - -extern unsigned char pchMessageStart[4]; - /** Message header. * (4) message start. * (12) command. @@ -50,7 +42,6 @@ class CMessageHeader // TODO: make private (improves encapsulation) public: enum { - MESSAGE_START_SIZE=sizeof(::pchMessageStart), COMMAND_SIZE=12, MESSAGE_SIZE_SIZE=sizeof(int), CHECKSUM_SIZE=sizeof(int), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index e8d99a8d45..5cf4dd8111 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -5,6 +5,7 @@ #include "addresstablemodel.h" #include "transactiontablemodel.h" +#include "chainparams.h" #include "alert.h" #include "main.h" #include "checkpoints.h" @@ -110,7 +111,7 @@ void ClientModel::updateAlert(const QString &hash, int status) bool ClientModel::isTestNet() const { - return fTestNet; + return TestNet(); } bool ClientModel::inInitialBlockDownload() const diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index a0ddc4d9ee..3c24016fe3 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -163,7 +163,7 @@ Value getblock(const Array& params, bool fHelp) CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; - block.ReadFromDisk(pblockindex); + ReadBlockFromDisk(block, pblockindex); if (!fVerbose) { @@ -243,4 +243,20 @@ Value gettxout(const Array& params, bool fHelp) return ret; } +Value verifychain(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "verifychain [check level] [num blocks]\n" + "Verifies blockchain database."); + + int nCheckLevel = GetArg("-checklevel", 3); + int nCheckDepth = GetArg("-checkblocks", 288); + if (params.size() > 0) + nCheckLevel = params[0].get_int(); + if (params.size() > 1) + nCheckDepth = params[1].get_int(); + + return VerifyDB(nCheckLevel, nCheckDepth); +} diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index d46309eaa4..dcfb023f35 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -2,35 +2,68 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <iostream> +#include <fstream> + #include "init.h" // for pwalletMain #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/lexical_cast.hpp> +#include <boost/variant/get.hpp> +#include <boost/algorithm/string.hpp> #define printf OutputDebugStringF using namespace json_spirit; using namespace std; -class CTxDump -{ -public: - CBlockIndex *pindex; - int64 nValue; - bool fSpent; - CWalletTx* ptx; - int nOut; - CTxDump(CWalletTx* ptx = NULL, int nOut = -1) - { - pindex = NULL; - nValue = 0; - fSpent = false; - this->ptx = ptx; - this->nOut = nOut; +void EnsureWalletIsUnlocked(); + +std::string static EncodeDumpTime(int64 nTime) { + return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); +} + +int64 static DecodeDumpTime(const std::string &str) { + static const boost::posix_time::time_input_facet facet("%Y-%m-%dT%H:%M:%SZ"); + static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0); + const std::locale loc(std::locale::classic(), &facet); + std::istringstream iss(str); + iss.imbue(loc); + boost::posix_time::ptime ptime(boost::date_time::not_a_date_time); + iss >> ptime; + if (ptime.is_not_a_date_time()) + return 0; + return (ptime - epoch).total_seconds(); +} + +std::string static EncodeDumpString(const std::string &str) { + std::stringstream ret; + BOOST_FOREACH(unsigned char c, str) { + if (c <= 32 || c >= 128 || c == '%') { + ret << '%' << HexStr(&c, &c + 1); + } else { + ret << c; + } + } + return ret.str(); +} + +std::string DecodeDumpString(const std::string &str) { + std::stringstream ret; + for (unsigned int pos = 0; pos < str.length(); pos++) { + unsigned char c = str[pos]; + if (c == '%' && pos+2 < str.length()) { + c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | + ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15)); + pos += 2; + } + ret << c; } -}; + return ret.str(); +} Value importprivkey(const Array& params, bool fHelp) { @@ -63,6 +96,10 @@ Value importprivkey(const Array& params, bool fHelp) pwalletMain->MarkDirty(); pwalletMain->SetAddressBookName(vchAddress, strLabel); + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(vchAddress)) + return Value::null; + if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); @@ -75,6 +112,86 @@ Value importprivkey(const Array& params, bool fHelp) return Value::null; } +Value importwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "importwallet <filename>\n" + "Imports keys from a wallet dump file (see dumpwallet)."); + + EnsureWalletIsUnlocked(); + + ifstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + int64 nTimeBegin = pindexBest->nTime; + + bool fGood = true; + + while (file.good()) { + std::string line; + std::getline(file, line); + if (line.empty() || line[0] == '#') + continue; + + std::vector<std::string> vstr; + boost::split(vstr, line, boost::is_any_of(" ")); + if (vstr.size() < 2) + continue; + CBitcoinSecret vchSecret; + if (!vchSecret.SetString(vstr[0])) + continue; + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + CKeyID keyid = pubkey.GetID(); + if (pwalletMain->HaveKey(keyid)) { + printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str()); + continue; + } + int64 nTime = DecodeDumpTime(vstr[1]); + std::string strLabel; + bool fLabel = true; + for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { + if (boost::algorithm::starts_with(vstr[nStr], "#")) + break; + if (vstr[nStr] == "change=1") + fLabel = false; + if (vstr[nStr] == "reserve=1") + fLabel = false; + if (boost::algorithm::starts_with(vstr[nStr], "label=")) { + strLabel = DecodeDumpString(vstr[nStr].substr(6)); + fLabel = true; + } + } + printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str()); + if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; + if (fLabel) + pwalletMain->SetAddressBookName(keyid, strLabel); + nTimeBegin = std::min(nTimeBegin, nTime); + } + file.close(); + + CBlockIndex *pindex = pindexBest; + while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) + pindex = pindex->pprev; + + printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1); + pwalletMain->ScanForWalletTransactions(pindex); + pwalletMain->ReacceptWalletTransactions(); + pwalletMain->MarkDirty(); + + if (!fGood) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + + return Value::null; +} + Value dumpprivkey(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -82,6 +199,8 @@ Value dumpprivkey(const Array& params, bool fHelp) "dumpprivkey <bitcoinaddress>\n" "Reveals the private key corresponding to <bitcoinaddress>."); + EnsureWalletIsUnlocked(); + string strAddress = params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) @@ -94,3 +213,58 @@ Value dumpprivkey(const Array& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); return CBitcoinSecret(vchSecret).ToString(); } + + +Value dumpwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpwallet <filename>\n" + "Dumps all wallet keys in a human-readable format."); + + EnsureWalletIsUnlocked(); + + ofstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + std::map<CKeyID, int64> mapKeyBirth; + std::set<CKeyID> setKeyPool; + pwalletMain->GetKeyBirthTimes(mapKeyBirth); + pwalletMain->GetAllReserveKeys(setKeyPool); + + // sort time/key pairs + std::vector<std::pair<int64, CKeyID> > vKeyBirth; + for (std::map<CKeyID, int64>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { + vKeyBirth.push_back(std::make_pair(it->second, it->first)); + } + mapKeyBirth.clear(); + std::sort(vKeyBirth.begin(), vKeyBirth.end()); + + // produce output + file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str()); + file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str()); + file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str()); + file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str()); + file << "\n"; + for (std::vector<std::pair<int64, 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)) { + if (pwalletMain->mapAddressBook.count(keyid)) { + file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), EncodeDumpString(pwalletMain->mapAddressBook[keyid]).c_str(), strAddr.c_str()); + } else if (setKeyPool.count(keyid)) { + file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str()); + } else { + file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str()); + } + } + } + file << "\n"; + file << "# End of dump\n"; + file.close(); + return Value::null; +} diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6f8ac7a112..d0b0a70be4 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "main.h" #include "db.h" #include "init.h" @@ -93,7 +94,7 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", fTestNet)); + obj.push_back(Pair("testnet", TestNet())); return obj; } diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 644c2675ae..bd7bc0ba10 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -157,7 +157,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp) BOOST_FOREACH(string& strAddNode, laddedNodes) { vector<CService> vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) + if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); else { diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 585bdb2bfb..5388bd4d84 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -79,7 +79,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", fTestNet)); + obj.push_back(Pair("testnet", TestNet())); obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); diff --git a/src/script.cpp b/src/script.cpp index cf6eeaf392..14fe80e207 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1474,6 +1474,42 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto return true; } +class CAffectedKeysVisitor : public boost::static_visitor<void> { +private: + const CKeyStore &keystore; + std::vector<CKeyID> &vKeys; + +public: + CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} + + void Process(const CScript &script) { + txnouttype type; + std::vector<CTxDestination> vDest; + int nRequired; + if (ExtractDestinations(script, type, vDest, nRequired)) { + BOOST_FOREACH(const CTxDestination &dest, vDest) + boost::apply_visitor(*this, dest); + } + } + + void operator()(const CKeyID &keyId) { + if (keystore.HaveKey(keyId)) + vKeys.push_back(keyId); + } + + void operator()(const CScriptID &scriptId) { + CScript script; + if (keystore.GetCScript(scriptId, script)) + Process(script); + } + + void operator()(const CNoDestination &none) {} +}; + +void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) { + CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); +} + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { diff --git a/src/script.h b/src/script.h index f963467c94..03afe8b652 100644 --- a/src/script.h +++ b/src/script.h @@ -674,6 +674,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c bool IsStandard(const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); +void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index b1e98f65ed..ea0cc1bcef 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -8,6 +8,7 @@ #include <boost/test/unit_test.hpp> #include <boost/foreach.hpp> +#include "chainparams.h" #include "main.h" #include "wallet.h" #include "net.h" @@ -25,7 +26,7 @@ CService ip(uint32_t i) { struct in_addr s; s.s_addr = i; - return CService(CNetAddr(s), GetDefaultPort()); + return CService(CNetAddr(s), Params().GetDefaultPort()); } BOOST_AUTO_TEST_SUITE(DoS_tests) diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 2741672a88..af65416485 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -108,8 +108,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) std::vector<unsigned char> result; CBitcoinSecret secret; CBitcoinAddress addr; - // Save global state - bool fTestNet_stored = fTestNet; BOOST_FOREACH(Value& tv, tests) { @@ -125,7 +123,10 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) const Object &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); - fTestNet = isTestnet; // Override testnet flag + if (isTestnet) + SelectParams(CChainParams::TESTNET); + else + SelectParams(CChainParams::MAIN); if(isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); @@ -156,8 +157,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); } } - // Restore global state - fTestNet = fTestNet_stored; + SelectParams(CChainParams::MAIN); } // Goal: check that generated keys match test vectors @@ -165,9 +165,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) { Array tests = read_json("base58_keys_valid.json"); std::vector<unsigned char> result; - // Save global state - bool fTestNet_stored = fTestNet; - BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); @@ -182,7 +179,10 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) const Object &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); - fTestNet = isTestnet; // Override testnet flag + if (isTestnet) + SelectParams(CChainParams::TESTNET); + else + SelectParams(CChainParams::MAIN); if(isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); @@ -225,8 +225,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) CTxDestination nodest = CNoDestination(); BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest)); - // Restore global state - fTestNet = fTestNet_stored; + SelectParams(CChainParams::MAIN); } // Goal: check that base58 parsing code is robust against a variety of corrupted data diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index d626f9a6f4..5675c40e76 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15) // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW - BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); + BOOST_CHECK(CheckBlock(forkingBlock, state, false, false)); } SetMockTime(0); diff --git a/src/txdb.cpp b/src/txdb.cpp index 3d34710d22..34836eaa97 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -6,6 +6,7 @@ #include "txdb.h" #include "main.h" #include "hash.h" +#include "chainparams.h" using namespace std; @@ -223,7 +224,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nTx = diskindex.nTx; // Watch for genesis block - if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) + if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == Params().HashGenesisBlock()) pindexGenesisBlock = pindexNew; if (!pindexNew->CheckIndex()) diff --git a/src/util.cpp b/src/util.cpp index f4892a2387..bfb6d75838 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -13,6 +13,7 @@ #include <sys/resource.h> #endif +#include "chainparams.h" #include "util.h" #include "sync.h" #include "version.h" @@ -78,7 +79,6 @@ bool fDaemon = false; bool fServer = false; bool fCommandLine = false; string strMiscWarning; -bool fTestNet = false; bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter<int64> vTimeOffsets(200,0); @@ -1068,8 +1068,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) } else { path = GetDefaultDataDir(); } - if (fNetSpecific && GetBoolArg("-testnet", false)) - path /= "testnet3"; + if (fNetSpecific) + path /= Params().DataDir(); fs::create_directories(path); diff --git a/src/util.h b/src/util.h index 9173b5bb58..86a38ad331 100644 --- a/src/util.h +++ b/src/util.h @@ -143,7 +143,6 @@ extern bool fDaemon; extern bool fServer; extern bool fCommandLine; extern std::string strMiscWarning; -extern bool fTestNet; extern bool fNoListen; extern bool fLogTimestamps; extern volatile bool fReopenDebugLog; diff --git a/src/wallet.cpp b/src/wallet.cpp index 4cd04bb6e2..488787f967 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -40,18 +40,20 @@ CPubKey CWallet::GenerateNewKey() SetMinVersion(FEATURE_COMPRPUBKEY); CPubKey pubkey = secret.GetPubKey(); + + // Create new metadata + int64 nCreationTime = GetTime(); + mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime); + if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) + nTimeFirstKey = nCreationTime; + if (!AddKeyPubKey(secret, pubkey)) throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); return pubkey; } -bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey, - int64 nCreateTime) +bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) { - if (!nCreateTime) - nCreateTime = GetTime(); - if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey)) - nTimeFirstKey = nCreateTime; if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; if (!fFileBacked) @@ -59,19 +61,14 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey, if (!IsCrypted()) { return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey(), - nCreateTime); + mapKeyMetadata[pubkey.GetID()]); } return true; } bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, - const vector<unsigned char> &vchCryptedSecret, - int64 nCreateTime) + const vector<unsigned char> &vchCryptedSecret) { - if (!nCreateTime) - nCreateTime = GetTime(); - if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey)) - nTimeFirstKey = nCreateTime; if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; if (!fFileBacked) @@ -81,15 +78,24 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, if (pwalletdbEncryption) return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, - nCreateTime); + mapKeyMetadata[vchPubKey.GetID()]); else return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, - nCreateTime); + mapKeyMetadata[vchPubKey.GetID()]); } return false; } +bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) +{ + if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey)) + nTimeFirstKey = meta.nCreateTime; + + mapKeyMetadata[pubkey.GetID()] = meta; + return true; +} + bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); @@ -798,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) } CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) @@ -1301,7 +1307,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, // Check that enough fee is included int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); bool fAllowFree = AllowFree(dPriority); - int64 nMinFee = GetMinFee(wtxNew, 1, fAllowFree, GMF_SEND); + int64 nMinFee = GetMinFee(wtxNew, fAllowFree, GMF_SEND); if (nFeeRet < max(nPayFee, nMinFee)) { nFeeRet = max(nPayFee, nMinFee); @@ -1840,7 +1846,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) +void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const { setAddress.clear(); @@ -1902,3 +1908,53 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) } } +void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const { + mapKeyBirth.clear(); + + // get birth times for keys with metadata + for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) + if (it->second.nCreateTime) + mapKeyBirth[it->first] = it->second.nCreateTime; + + // map in which we'll infer heights of other keys + CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin + std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock; + std::set<CKeyID> setKeys; + GetKeys(setKeys); + BOOST_FOREACH(const CKeyID &keyid, setKeys) { + if (mapKeyBirth.count(keyid) == 0) + mapKeyFirstBlock[keyid] = pindexMax; + } + setKeys.clear(); + + // if there are no such keys, we're done + if (mapKeyFirstBlock.empty()) + return; + + // find first block that affects those keys, if there are any left + std::vector<CKeyID> vAffected; + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { + // iterate over all wallet transactions... + const CWalletTx &wtx = (*it).second; + std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); + if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) { + // ... which are already in a block + int nHeight = blit->second->nHeight; + BOOST_FOREACH(const CTxOut &txout, wtx.vout) { + // iterate over all their outputs + ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected); + BOOST_FOREACH(const CKeyID &keyid, vAffected) { + // ... and all their affected keys + std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid); + if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) + rit->second = blit->second; + } + vAffected.clear(); + } + } + } + + // Extract block timestamps for those keys + for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) + mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off +} diff --git a/src/wallet.h b/src/wallet.h index 2b3131261c..36b3608fb0 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -87,7 +87,7 @@ public: std::string strWalletFile; std::set<int64> setKeyPool; - + std::map<CKeyID, CKeyMetadata> mapKeyMetadata; typedef std::map<unsigned int, CMasterKey> MasterKeyMap; MasterKeyMap mapMasterKeys; @@ -140,14 +140,16 @@ public: // Generate a new key CPubKey GenerateNewKey(); // Adds a key to the store, and saves it to disk. - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int64 nCreateTime = 0); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); // Adds a key to the store, without saving it to disk (used by LoadWallet) bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } + // Load metadata (used by LoadWallet) + bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } // Adds an encrypted key to the store, and saves it to disk. - bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, int64 nCreateTime = 0); + bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool AddCScript(const CScript& redeemScript); @@ -157,6 +159,8 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + void GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const; + /** Increment the next transaction order id @return next transaction order id */ @@ -198,7 +202,7 @@ public: void ReturnKey(int64 nIndex); bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true); int64 GetOldestKeyPoolTime(); - void GetAllReserveKeys(std::set<CKeyID>& setAddress); + void GetAllReserveKeys(std::set<CKeyID>& setAddress) const; std::set< std::set<CTxDestination> > GetAddressGroupings(); std::map<CTxDestination, int64> GetAddressBalances(); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 96fd4a5fc1..702e219a5b 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -344,12 +344,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "keymeta") { - vector<unsigned char> vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nKeyMeta++; + pwallet->LoadKeyMetadata(vchPubKey, keyMeta); + // find earliest key creation time, as wallet birthday if (!pwallet->nTimeFirstKey || (keyMeta.nCreateTime < pwallet->nTimeFirstKey)) @@ -363,7 +365,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { int64 nIndex; ssKey >> nIndex; + CKeyPool keypool; + ssValue >> keypool; pwallet->setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (pwallet->mapKeyMetadata.count(keyid) == 0) + pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); } else if (strType == "version") { @@ -483,7 +494,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) // nTimeFirstKey is only reliable if all keys have metadata if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) - pwallet->nTimeFirstKey = 0; + pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade) WriteTx(hash, pwallet->mapWallet[hash]); diff --git a/src/walletdb.h b/src/walletdb.h index 287361b33d..4dfa35d82a 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -30,7 +30,7 @@ class CKeyMetadata public: static const int CURRENT_VERSION=1; int nVersion; - int64 nCreateTime; + int64 nCreateTime; // 0 means unknown CKeyMetadata() { @@ -52,7 +52,7 @@ public: void SetNull() { nVersion = CKeyMetadata::CURRENT_VERSION; - nCreateTime = GetTime(); + nCreateTime = 0; } }; @@ -84,13 +84,12 @@ public: } bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, - int64 nCreateTime) + const CKeyMetadata &keyMeta) { nWalletDBUpdated++; - CKeyMetadata keyMeta(nCreateTime); if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), - keyMeta, false)) + keyMeta)) return false; return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); @@ -98,14 +97,13 @@ public: bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, - int64 nCreateTime) + const CKeyMetadata &keyMeta) { const bool fEraseUnencryptedKey = true; nWalletDBUpdated++; - CKeyMetadata keyMeta(nCreateTime); if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), - keyMeta, false)) + keyMeta)) return false; if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) |