diff --git a/src/alert.cpp b/src/alert.cpp index 99164d63e..638f0d7a1 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -5,6 +5,7 @@ #include "alert.h" +#include "chainparams.h" #include "key.h" #include "net.h" #include "ui_interface.h" diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index ce9e7a402..29efdfa82 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -33,7 +33,7 @@ static bool AppInitRPC(int argc, char* argv[]) fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } - // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) + // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) if (!SelectParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); return false; diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 9b535c2e6..704332c39 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -77,7 +77,7 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } - // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) + // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) if (!SelectParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); return false; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f5cf846a0..3f4d7f706 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -6,8 +6,6 @@ #include "chainparams.h" #include "assert.h" -#include "core.h" -#include "protocol.h" #include "util.h" #include @@ -100,6 +98,7 @@ unsigned int pnSeed[] = class CMainParams : public CChainParams { public: CMainParams() { + networkID = CChainParams::MAIN; // 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. @@ -112,6 +111,10 @@ public: nRPCPort = 8332; bnProofOfWorkLimit = ~uint256(0) >> 32; nSubsidyHalvingInterval = 210000; + nEnforceBlockUpgradeMajority = 750; + nRejectBlockOutdatedMajority = 950; + nToCheckBlockUpgradeMajority = 1000; + nMinerThreads = 0; // Build the genesis block. Note that the output of the genesis coinbase cannot // be spent as it did not originally exist in the database. @@ -167,27 +170,25 @@ public: 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& FixedSeeds() const { - return vFixedSeeds; + fRequireRPCPassword = true; + fMiningRequiresPeers = true; + fDefaultCheckMemPool = false; + fAllowMinDifficultyBlocks = false; + fRequireStandard = true; + fRPCisTestNet = false; + fMineBlocksOnDemand = false; } -protected: - CBlock genesis; - vector vFixedSeeds; }; static CMainParams mainParams; - // // Testnet (v3) // class CTestNetParams : public CMainParams { public: CTestNetParams() { + networkID = CChainParams::TESTNET; // 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. @@ -198,6 +199,9 @@ public: vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 18333; nRPCPort = 18332; + nEnforceBlockUpgradeMajority = 51; + nRejectBlockOutdatedMajority = 75; + nToCheckBlockUpgradeMajority = 100; strDataDir = "testnet3"; // Modify the testnet genesis block so the timestamp is valid for a later start. @@ -216,23 +220,34 @@ public: base58Prefixes[SECRET_KEY] = list_of(239); base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x35)(0x87)(0xCF); base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x35)(0x83)(0x94); + + fRequireRPCPassword = true; + fMiningRequiresPeers = true; + fDefaultCheckMemPool = false; + fAllowMinDifficultyBlocks = true; + fRequireStandard = false; + fRPCisTestNet = true; + fMineBlocksOnDemand = false; } - virtual Network NetworkID() const { return CChainParams::TESTNET; } }; static CTestNetParams testNetParams; - // // Regression test // class CRegTestParams : public CTestNetParams { public: CRegTestParams() { + networkID = CChainParams::REGTEST; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; nSubsidyHalvingInterval = 150; + nEnforceBlockUpgradeMajority = 750; + nRejectBlockOutdatedMajority = 950; + nToCheckBlockUpgradeMajority = 1000; + nMinerThreads = 1; bnProofOfWorkLimit = ~uint256(0) >> 1; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; @@ -243,10 +258,15 @@ public: assert(hashGenesisBlock == uint256("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); vSeeds.clear(); // Regtest mode doesn't have any DNS seeds. - } - virtual bool RequireRPCPassword() const { return false; } - virtual Network NetworkID() const { return CChainParams::REGTEST; } + fRequireRPCPassword = false; + fMiningRequiresPeers = false; + fDefaultCheckMemPool = true; + fAllowMinDifficultyBlocks = true; + fRequireStandard = false; + fRPCisTestNet = true; + fMineBlocksOnDemand = true; + } }; static CRegTestParams regTestParams; diff --git a/src/chainparams.h b/src/chainparams.h index 5600b904c..988e3ac3a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -7,17 +7,15 @@ #define BITCOIN_CHAIN_PARAMS_H #include "uint256.h" +#include "core.h" +#include "protocol.h" #include 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) {} @@ -57,13 +55,33 @@ public: int GetDefaultPort() const { return nDefaultPort; } const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } - virtual const CBlock& GenesisBlock() const = 0; - virtual bool RequireRPCPassword() const { return true; } + /* Used to check majorities for block version upgrade */ + int EnforceBlockUpgradeMajority() const { return nEnforceBlockUpgradeMajority; } + int RejectBlockOutdatedMajority() const { return nRejectBlockOutdatedMajority; } + int ToCheckBlockUpgradeMajority() const { return nToCheckBlockUpgradeMajority; } + + /* Used if GenerateBitcoins is called with a negative number of threads */ + int DefaultMinerThreads() const { return nMinerThreads; } + const CBlock& GenesisBlock() const { return genesis; }; + bool RequireRPCPassword() const { return fRequireRPCPassword; } + /* Make miner wait to have peers to avoid wasting work */ + bool MiningRequiresPeers() const { return fMiningRequiresPeers; } + /* Default value for -checkmempool argument */ + bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; } + /* Allow mining of a min-difficulty block */ + bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; } + /* Make standard checks */ + bool RequireStandard() const { return fRequireStandard; } + /* Make standard checks */ + bool RPCisTestNet() const { return fRPCisTestNet; } const string& DataDir() const { return strDataDir; } - virtual Network NetworkID() const = 0; + /* Make miner stop after a block is found. In RPC, don't return + * until nGenProcLimit blocks are generated */ + bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } + Network NetworkID() const { return networkID; } const vector& DNSSeeds() const { return vSeeds; } - const std::vector &Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } - virtual const vector& FixedSeeds() const = 0; + const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + const vector& FixedSeeds() const { return vFixedSeeds; } int RPCPort() const { return nRPCPort; } protected: CChainParams() {} @@ -76,9 +94,23 @@ protected: int nRPCPort; uint256 bnProofOfWorkLimit; int nSubsidyHalvingInterval; + int nEnforceBlockUpgradeMajority; + int nRejectBlockOutdatedMajority; + int nToCheckBlockUpgradeMajority; string strDataDir; + int nMinerThreads; vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; + Network networkID; + CBlock genesis; + vector vFixedSeeds; + bool fRequireRPCPassword; + bool fMiningRequiresPeers; + bool fDefaultCheckMemPool; + bool fAllowMinDifficultyBlocks; + bool fRequireStandard; + bool fRPCisTestNet; + bool fMineBlocksOnDemand; }; /** @@ -96,13 +128,4 @@ void SelectParams(CChainParams::Network network); */ bool SelectParamsFromCommandLine(); -inline bool TestNet() { - // Note: it's deliberate that this returns "false" for regression test mode. - return Params().NetworkID() == CChainParams::TESTNET; -} - -inline bool RegTest() { - return Params().NetworkID() == CChainParams::REGTEST; -} - #endif diff --git a/src/init.cpp b/src/init.cpp index aca5e0c9a..ca348b614 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -526,7 +526,8 @@ bool AppInit2(boost::thread_group& threadGroup) InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net")); fBenchmark = GetBoolArg("-benchmark", false); - mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest())); + // Checkmempool defaults to true in regtest mode + mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultCheckMemPool())); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency diff --git a/src/main.cpp b/src/main.cpp index 16d1cba6e..5d1ff94f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -828,7 +828,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (Params().NetworkID() == CChainParams::MAIN && !IsStandardTx(tx, reason)) + if (Params().RequireStandard() && !IsStandardTx(tx, reason)) return state.DoS(0, error("AcceptToMemoryPool : nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); @@ -892,7 +892,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Check for non-standard pay-to-script-hash in inputs - if (Params().NetworkID() == CChainParams::MAIN && !AreInputsStandard(tx, view)) + if (Params().RequireStandard() && !AreInputsStandard(tx, view)) return error("AcceptToMemoryPool: : nonstandard transaction input"); // Note: if you modify this code to accept non-standard transactions, then @@ -1207,7 +1207,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) const uint256 &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after nTargetSpacing*2 time between blocks: - if (TestNet() && nTime > nTargetSpacing*2) + if (Params().AllowMinDifficultyBlocks() && nTime > nTargetSpacing*2) return bnLimit.GetCompact(); uint256 bnResult; @@ -1235,7 +1235,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // Only change once per interval if ((pindexLast->nHeight+1) % nInterval != 0) { - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) { // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes @@ -1465,7 +1465,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); // Updating time can change work required on testnet: - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) block.nBits = GetNextWorkRequired(pindexPrev, &block); } @@ -2482,14 +2482,11 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 2) + if (block.nVersion < 2 && + CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) { - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) - { - return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), - REJECT_OBSOLETE, "bad-version"); - } + return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), + REJECT_OBSOLETE, "bad-version"); } } @@ -2529,19 +2526,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (block.nVersion >= 2) + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if (block.nVersion >= 2 && + CBlockIndex::IsSuperMajority(2, pindex->pprev, Params().EnforceBlockUpgradeMajority())) { - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 750, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 51, 100))) - { - CScript expect = CScript() << nHeight; - if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || - !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { - pindex->nStatus |= BLOCK_FAILED_VALID; - return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), - REJECT_INVALID, "bad-cb-height"); - } + CScript expect = CScript() << nHeight; + if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + pindex->nStatus |= BLOCK_FAILED_VALID; + return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), REJECT_INVALID, "bad-cb-height"); } } @@ -2565,8 +2558,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return true; } -bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) +bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired) { + unsigned int nToCheck = Params().ToCheckBlockUpgradeMajority(); unsigned int nFound = 0; for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++) { diff --git a/src/main.h b/src/main.h index 98155989a..4ef380008 100644 --- a/src/main.h +++ b/src/main.h @@ -841,10 +841,11 @@ public: /** * Returns true if there are nRequired or more blocks of minVersion or above - * in the last nToCheck blocks, starting at pstart and going backwards. + * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart + * and going backwards. */ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, - unsigned int nRequired, unsigned int nToCheck); + unsigned int nRequired); std::string ToString() const { diff --git a/src/miner.cpp b/src/miner.cpp index baaa22c8f..68abc4a6e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -514,7 +514,7 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nExtraNonce = 0; try { while (true) { - if (Params().NetworkID() != CChainParams::REGTEST) { + if (Params().MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining // on an obsolete chain. In regtest mode we expect to fly solo. while (vNodes.empty()) @@ -582,9 +582,8 @@ void static BitcoinMiner(CWallet *pwallet) CheckWork(pblock, *pwallet, 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) + // In regression test mode, stop mining after a block is found. + if (Params().MineBlocksOnDemand()) throw boost::thread_interrupted(); break; @@ -622,7 +621,8 @@ void static BitcoinMiner(CWallet *pwallet) // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); - if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) + // Regtest mode doesn't require peers + if (vNodes.empty() && Params().MiningRequiresPeers()) break; if (nBlockNonce >= 0xffff0000) break; @@ -634,7 +634,7 @@ void static BitcoinMiner(CWallet *pwallet) // Update nTime every few seconds UpdateTime(*pblock, pindexPrev); nBlockTime = ByteReverse(pblock->nTime); - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); @@ -654,8 +654,9 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) static boost::thread_group* minerThreads = NULL; if (nThreads < 0) { - if (Params().NetworkID() == CChainParams::REGTEST) - nThreads = 1; + // In regtest threads defaults to 1 + if (Params().DefaultMinerThreads()) + nThreads = Params().DefaultMinerThreads(); else nThreads = boost::thread::hardware_concurrency(); } diff --git a/src/net.h b/src/net.h index bc1406913..9fcdbf802 100644 --- a/src/net.h +++ b/src/net.h @@ -130,7 +130,7 @@ struct LocalServiceInfo { }; extern CCriticalSection cs_mapLocalHost; -extern map mapLocalHost; +extern std::map mapLocalHost; class CNodeStats { diff --git a/src/protocol.cpp b/src/protocol.cpp index c77a92f02..87b2f2387 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -5,6 +5,7 @@ #include "protocol.h" +#include "chainparams.h" #include "util.h" #ifndef WIN32 diff --git a/src/protocol.h b/src/protocol.h index e6f105fe5..6de5d05a7 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -10,7 +10,6 @@ #ifndef __INCLUDED_PROTOCOL_H__ #define __INCLUDED_PROTOCOL_H__ -#include "chainparams.h" #include "netbase.h" #include "serialize.h" #include "uint256.h" @@ -19,6 +18,8 @@ #include #include +#define MESSAGE_START_SIZE 4 + /** Message header. * (4) message start. * (12) command. diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 6165731d2..9241f9dc3 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -490,6 +490,17 @@ bool PaymentServer::readPaymentRequest(const QString& filename, PaymentRequestPl return request.parse(data); } +std::string PaymentServer::mapNetworkIdToName(CChainParams::Network networkId) +{ + if (networkId == CChainParams::MAIN) + return "main"; + if (networkId == CChainParams::TESTNET) + return "test"; + if (networkId == CChainParams::REGTEST) + return "regtest"; + return ""; +} + bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient) { if (!optionsModel) @@ -499,8 +510,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins const payments::PaymentDetails& details = request.getDetails(); // Payment request network matches client network? - if ((details.network() == "main" && TestNet()) || - (details.network() == "test" && !TestNet())) + if (details.network() != mapNetworkIdToName(Params().NetworkID())) { emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index d84d09c57..d6949a47c 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -118,6 +118,7 @@ protected: private: static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request); + std::string mapNetworkIdToName(CChainParams::Network networkId); bool processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient); void fetchRequest(const QUrl& url); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index dd148c6af..837f5336c 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -175,7 +175,7 @@ Value setgenerate(const Array& params, bool fHelp) } // -regtest mode: don't return until nGenProcLimit blocks are generated - if (fGenerate && Params().NetworkID() == CChainParams::REGTEST) + if (fGenerate && Params().MineBlocksOnDemand()) { int nHeightStart = 0; int nHeightEnd = 0; @@ -266,7 +266,7 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", TestNet())); + obj.push_back(Pair("testnet", Params().RPCisTestNet())); #ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 9802445fc..77e0e09ec 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -73,7 +73,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", TestNet())); + obj.push_back(Pair("testnet", Params().RPCisTestNet())); #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));