Skip to content

Commit cd9c699

Browse files
codablockUdjinM6
authored andcommitted
Implement named devnets (dashpay#1791)
* Initial devnet * Move genesis block adding into its own method * Introduce -allowprivatenet to lift limitation on RFC1918 addresses Normally, RFC1918 (192.168.x.x/10.x.x.x/...) addresses are not allowed to be relayed. Also, masternodes won't start when the address is considered invalid. This is needed to test local devnet or regtest based networks. * Lift the requirement of minimum MN age for regtest/devnet * Implement named devnets This allows the creation of multiple independent devnets. Each one is identified by a name which is hardened into a "devnet genesis" block, which is automatically positioned at height 1. Validation rules will ensure that a node from devnet=test1 never be able to accept blocks from devnet=test2. This is done by checking the expected devnet genesis block. The genesis block of the devnet is the same as the one from regtest. This starts the devnet with a very low difficulty, allowing us to fill up needed balances for masternodes very fast. Also, the devnet name is put into the sub-version of the VERSION message. If a node connects to the wrong network, it will immediately be disconnected. * Allow to select multiple addresses from the same group in devnet/regtest The selection code normally only allows to select addresses from the same group (e.g. 192.168.x.x) once. This results in connecting to only a single node in devnet/regtest. * Show the devnet name in the title bar and on the loading screen * Add AllowMultipleAddressesFromGroup to chainparams and use it in net.cpp * Remove unused/unneeded scripts from devnet geneses creation 1. OP_RETURN not needed in input script of devnet genesis 2. genesisOutputScript was unused * Fix copy/paste error in -allowprivatenet description * Improve -devnet parameter error handling - Only allow one of -devnet, -regtest or -testnet - Only allow -devnet=name to be specified once * Use different datadir for each devnet * Fix `devnet-devnet` issue * Fix devnet splashscreen (should use testnet img) * Avoid passing devNetName around (most of the time) * Remove nMaxTipAge from CDevNetParams Not present anymore after rebase on develop
1 parent 41850d0 commit cd9c699

15 files changed

+335
-27
lines changed

src/chainparams.cpp

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "util.h"
1212
#include "utilstrencodings.h"
1313

14+
#include "arith_uint256.h"
15+
1416
#include <assert.h>
1517

1618
#include <boost/assign/list_of.hpp>
@@ -38,6 +40,29 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
3840
return genesis;
3941
}
4042

43+
static CBlock CreateDevNetGenesisBlock(const uint256 &prevBlockHash, const std::string& devNetName, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
44+
{
45+
assert(!devNetName.empty());
46+
47+
CMutableTransaction txNew;
48+
txNew.nVersion = 1;
49+
txNew.vin.resize(1);
50+
txNew.vout.resize(1);
51+
txNew.vin[0].scriptSig = CScript() << std::vector<unsigned char>(devNetName.begin(), devNetName.end());
52+
txNew.vout[0].nValue = genesisReward;
53+
txNew.vout[0].scriptPubKey = CScript() << OP_RETURN;
54+
55+
CBlock genesis;
56+
genesis.nTime = nTime;
57+
genesis.nBits = nBits;
58+
genesis.nNonce = nNonce;
59+
genesis.nVersion = nVersion;
60+
genesis.vtx.push_back(txNew);
61+
genesis.hashPrevBlock = prevBlockHash;
62+
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
63+
return genesis;
64+
}
65+
4166
/**
4267
* Build the genesis block. Note that the output of its generation
4368
* transaction cannot be spent since it did not originally exist in the
@@ -56,6 +81,30 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits
5681
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
5782
}
5883

84+
static CBlock FindDevNetGenesisBlock(const Consensus::Params& params, const CBlock &prevBlock, const CAmount& reward)
85+
{
86+
std::string devNetName = GetDevNetName();
87+
assert(!devNetName.empty());
88+
89+
CBlock block = CreateDevNetGenesisBlock(prevBlock.GetHash(), devNetName.c_str(), prevBlock.nTime + 1, 0, prevBlock.nBits, prevBlock.nVersion, reward);
90+
91+
arith_uint256 bnTarget;
92+
bnTarget.SetCompact(block.nBits);
93+
94+
for (uint32_t nNonce = 0; nNonce < UINT32_MAX; nNonce++) {
95+
block.nNonce = nNonce;
96+
97+
uint256 hash = block.GetHash();
98+
if (UintToArith256(hash) <= bnTarget)
99+
return block;
100+
}
101+
102+
// This is very unlikely to happen as we start the devnet with a very low difficulty. In many cases even the first
103+
// iteration of the above loop will give a result already
104+
error("FindDevNetGenesisBlock: could not find devnet genesis block for %s", devNetName);
105+
assert(false);
106+
}
107+
59108
/**
60109
* Main network
61110
*/
@@ -168,6 +217,7 @@ class CMainParams : public CChainParams {
168217
fRequireStandard = true;
169218
fMineBlocksOnDemand = false;
170219
fTestnetToBeDeprecatedFieldRPC = false;
220+
fAllowMultipleAddressesFromGroup = false;
171221

172222
nPoolMaxTransactions = 3;
173223
nFulfilledRequestExpireTime = 60*60; // fulfilled requests expire in 1 hour
@@ -302,6 +352,7 @@ class CTestNetParams : public CChainParams {
302352
fRequireStandard = false;
303353
fMineBlocksOnDemand = false;
304354
fTestnetToBeDeprecatedFieldRPC = true;
355+
fAllowMultipleAddressesFromGroup = false;
305356

306357
nPoolMaxTransactions = 3;
307358
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes
@@ -323,6 +374,124 @@ class CTestNetParams : public CChainParams {
323374
};
324375
static CTestNetParams testNetParams;
325376

377+
/**
378+
* Devnet
379+
*/
380+
class CDevNetParams : public CChainParams {
381+
public:
382+
CDevNetParams() {
383+
strNetworkID = "dev";
384+
consensus.nSubsidyHalvingInterval = 210240;
385+
consensus.nMasternodePaymentsStartBlock = 4010; // not true, but it's ok as long as it's less then nMasternodePaymentsIncreaseBlock
386+
consensus.nMasternodePaymentsIncreaseBlock = 4030;
387+
consensus.nMasternodePaymentsIncreasePeriod = 10;
388+
consensus.nInstantSendKeepLock = 6;
389+
consensus.nBudgetPaymentsStartBlock = 4100;
390+
consensus.nBudgetPaymentsCycleBlocks = 50;
391+
consensus.nBudgetPaymentsWindowBlocks = 10;
392+
consensus.nBudgetProposalEstablishingTime = 60*20;
393+
consensus.nSuperblockStartBlock = 4200; // NOTE: Should satisfy nSuperblockStartBlock > nBudgetPeymentsStartBlock
394+
consensus.nSuperblockCycle = 24; // Superblocks can be issued hourly on devnet
395+
consensus.nGovernanceMinQuorum = 1;
396+
consensus.nGovernanceFilterElements = 500;
397+
consensus.nMasternodeMinimumConfirmations = 1;
398+
consensus.nMajorityEnforceBlockUpgrade = 51;
399+
consensus.nMajorityRejectBlockOutdated = 75;
400+
consensus.nMajorityWindow = 100;
401+
consensus.BIP34Height = 1;
402+
consensus.BIP34Hash = uint256S("0x0000047d24635e347be3aaaeb66c26be94901a2f962feccd4f95090191f208c1");
403+
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
404+
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
405+
consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes
406+
consensus.fPowAllowMinDifficultyBlocks = true;
407+
consensus.fPowNoRetargeting = false;
408+
consensus.nPowKGWHeight = 4001; // nPowKGWHeight >= nPowDGWHeight means "no KGW"
409+
consensus.nPowDGWHeight = 4001;
410+
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
411+
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
412+
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
413+
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
414+
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
415+
416+
// Deployment of BIP68, BIP112, and BIP113.
417+
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
418+
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1506556800; // September 28th, 2017
419+
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1538092800; // September 28th, 2018
420+
421+
// Deployment of DIP0001
422+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1;
423+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1505692800; // Sep 18th, 2017
424+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 1537228800; // Sep 18th, 2018
425+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nWindowSize = 100;
426+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nThreshold = 50; // 50% of 100
427+
428+
// The best chain should have at least this much work.
429+
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000000000000");
430+
431+
// By default assume that the signatures in ancestors of this block are valid.
432+
consensus.defaultAssumeValid = uint256S("0x000000000000000000000000000000000000000000000000000000000000000");
433+
434+
pchMessageStart[0] = 0xce;
435+
pchMessageStart[1] = 0xe2;
436+
pchMessageStart[2] = 0xca;
437+
pchMessageStart[3] = 0xff;
438+
vAlertPubKey = ParseHex("04517d8a699cb43d3938d7b24faaff7cda448ca4ea267723ba614784de661949bf632d6304316b244646dea079735b9a6fc4af804efb4752075b9fe2245e14e412");
439+
nDefaultPort = 19999;
440+
nDelayGetHeadersTime = 24 * 60 * 60;
441+
nPruneAfterHeight = 1000;
442+
443+
genesis = CreateGenesisBlock(1417713337, 1096447, 0x207fffff, 1, 50 * COIN);
444+
consensus.hashGenesisBlock = genesis.GetHash();
445+
assert(consensus.hashGenesisBlock == uint256S("0x000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e"));
446+
assert(genesis.hashMerkleRoot == uint256S("0xe0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7"));
447+
448+
devnetGenesis = FindDevNetGenesisBlock(consensus, genesis, 50 * COIN);
449+
450+
vFixedSeeds.clear();
451+
vSeeds.clear();
452+
//vSeeds.push_back(CDNSSeedData("dashevo.org", "devnet-seed.dashevo.org"));
453+
454+
// Testnet Dash addresses start with 'y'
455+
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,140);
456+
// Testnet Dash script addresses start with '8' or '9'
457+
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,19);
458+
// Testnet private keys start with '9' or 'c' (Bitcoin defaults)
459+
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
460+
// Testnet Dash BIP32 pubkeys start with 'tpub' (Bitcoin defaults)
461+
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
462+
// Testnet Dash BIP32 prvkeys start with 'tprv' (Bitcoin defaults)
463+
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
464+
465+
// Testnet Dash BIP44 coin type is '1' (All coin's testnet default)
466+
nExtCoinType = 1;
467+
468+
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
469+
470+
fMiningRequiresPeers = true;
471+
fDefaultConsistencyChecks = false;
472+
fRequireStandard = false;
473+
fMineBlocksOnDemand = false;
474+
fTestnetToBeDeprecatedFieldRPC = true;
475+
fAllowMultipleAddressesFromGroup = true;
476+
477+
nPoolMaxTransactions = 3;
478+
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes
479+
strSporkPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
480+
481+
checkpointData = (CCheckpointData) {
482+
boost::assign::map_list_of
483+
( 0, uint256S("0x000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e"))
484+
( 1, devnetGenesis.GetHash()),
485+
0,
486+
0,
487+
0
488+
};
489+
490+
}
491+
};
492+
static CDevNetParams *devNetParams;
493+
494+
326495
/**
327496
* Regression test
328497
*/
@@ -395,6 +564,7 @@ class CRegTestParams : public CChainParams {
395564
fRequireStandard = false;
396565
fMineBlocksOnDemand = true;
397566
fTestnetToBeDeprecatedFieldRPC = false;
567+
fAllowMultipleAddressesFromGroup = true;
398568

399569
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes
400570

@@ -435,14 +605,21 @@ CChainParams& Params(const std::string& chain)
435605
return mainParams;
436606
else if (chain == CBaseChainParams::TESTNET)
437607
return testNetParams;
438-
else if (chain == CBaseChainParams::REGTEST)
608+
else if (chain == CBaseChainParams::DEVNET) {
609+
assert(devNetParams);
610+
return *devNetParams;
611+
} else if (chain == CBaseChainParams::REGTEST)
439612
return regTestParams;
440613
else
441614
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
442615
}
443616

444617
void SelectParams(const std::string& network)
445618
{
619+
if (network == CBaseChainParams::DEVNET) {
620+
devNetParams = new CDevNetParams();
621+
}
622+
446623
SelectBaseParams(network);
447624
pCurrentParams = &Params(network);
448625
}

src/chainparams.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class CChainParams
5858
int GetDefaultPort() const { return nDefaultPort; }
5959

6060
const CBlock& GenesisBlock() const { return genesis; }
61+
const CBlock& DevNetGenesisBlock() const { return devnetGenesis; }
6162
/** Make miner wait to have peers to avoid wasting work */
6263
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
6364
/** Default value for -checkmempool and -checkblockindex argument */
@@ -70,6 +71,8 @@ class CChainParams
7071
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
7172
/** In the future use NetworkIDString() for RPC fields */
7273
bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
74+
/** Allow multiple addresses to be selected from the same network group (e.g. 192.168.x.x) */
75+
bool AllowMultipleAddressesFromGroup() const { return fAllowMultipleAddressesFromGroup; }
7376
/** Return the BIP70 network string (main, test or regtest) */
7477
std::string NetworkIDString() const { return strNetworkID; }
7578
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
@@ -95,12 +98,14 @@ class CChainParams
9598
int nExtCoinType;
9699
std::string strNetworkID;
97100
CBlock genesis;
101+
CBlock devnetGenesis;
98102
std::vector<SeedSpec6> vFixedSeeds;
99103
bool fMiningRequiresPeers;
100104
bool fDefaultConsistencyChecks;
101105
bool fRequireStandard;
102106
bool fMineBlocksOnDemand;
103107
bool fTestnetToBeDeprecatedFieldRPC;
108+
bool fAllowMultipleAddressesFromGroup;
104109
CCheckpointData checkpointData;
105110
int nPoolMaxTransactions;
106111
int nFulfilledRequestExpireTime;

src/chainparamsbase.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
const std::string CBaseChainParams::MAIN = "main";
1414
const std::string CBaseChainParams::TESTNET = "test";
15+
const std::string CBaseChainParams::DEVNET = "dev";
1516
const std::string CBaseChainParams::REGTEST = "regtest";
1617

1718
void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp)
@@ -51,6 +52,20 @@ class CBaseTestNetParams : public CBaseChainParams
5152
};
5253
static CBaseTestNetParams testNetParams;
5354

55+
/**
56+
* Devnet
57+
*/
58+
class CBaseDevNetParams : public CBaseChainParams
59+
{
60+
public:
61+
CBaseDevNetParams(const std::string &dataDir)
62+
{
63+
nRPCPort = 19998;
64+
strDataDir = dataDir;
65+
}
66+
};
67+
static CBaseDevNetParams *devNetParams;
68+
5469
/*
5570
* Regression test
5671
*/
@@ -79,31 +94,53 @@ CBaseChainParams& BaseParams(const std::string& chain)
7994
return mainParams;
8095
else if (chain == CBaseChainParams::TESTNET)
8196
return testNetParams;
82-
else if (chain == CBaseChainParams::REGTEST)
97+
else if (chain == CBaseChainParams::DEVNET) {
98+
assert(devNetParams);
99+
return *devNetParams;
100+
} else if (chain == CBaseChainParams::REGTEST)
83101
return regTestParams;
84102
else
85103
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
86104
}
87105

88106
void SelectBaseParams(const std::string& chain)
89107
{
108+
if (chain == CBaseChainParams::DEVNET) {
109+
std::string devNetName = GetDevNetName();
110+
assert(!devNetName.empty());
111+
devNetParams = new CBaseDevNetParams(devNetName);
112+
}
113+
90114
pCurrentBaseParams = &BaseParams(chain);
91115
}
92116

93117
std::string ChainNameFromCommandLine()
94118
{
95119
bool fRegTest = GetBoolArg("-regtest", false);
120+
bool fDevNet = mapArgs.count("-devnet") != 0;
96121
bool fTestNet = GetBoolArg("-testnet", false);
97122

98-
if (fTestNet && fRegTest)
99-
throw std::runtime_error("Invalid combination of -regtest and -testnet.");
123+
int nameParamsCount = (fRegTest ? 1 : 0) + (fDevNet ? 1 : 0) + (fTestNet ? 1 : 0);
124+
if (nameParamsCount > 1)
125+
throw std::runtime_error("Only one of -regtest, -testnet or -devnet can be used.");
126+
127+
if (fDevNet)
128+
return CBaseChainParams::DEVNET;
100129
if (fRegTest)
101130
return CBaseChainParams::REGTEST;
102131
if (fTestNet)
103132
return CBaseChainParams::TESTNET;
104133
return CBaseChainParams::MAIN;
105134
}
106135

136+
std::string GetDevNetName()
137+
{
138+
// This function should never be called for non-devnets
139+
assert(mapArgs.count("-devnet"));
140+
std::string devNetName = GetArg("-devnet", "");
141+
return "devnet" + (devNetName.empty() ? "" : "-" + devNetName);
142+
}
143+
107144
bool AreBaseParamsConfigured()
108145
{
109146
return pCurrentBaseParams != NULL;

src/chainparamsbase.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class CBaseChainParams
1818
/** BIP70 chain name strings (main, test or regtest) */
1919
static const std::string MAIN;
2020
static const std::string TESTNET;
21+
static const std::string DEVNET;
2122
static const std::string REGTEST;
2223

2324
const std::string& DataDir() const { return strDataDir; }
@@ -53,6 +54,8 @@ void SelectBaseParams(const std::string& chain);
5354
*/
5455
std::string ChainNameFromCommandLine();
5556

57+
std::string GetDevNetName();
58+
5659
/**
5760
* Return true if SelectBaseParamsFromCommandLine() has been called to select
5861
* a network.

0 commit comments

Comments
 (0)