diff options
| author | Bitflash <admin@bitflash.network> | 2026-08-20 18:30:30 -0300 |
|---|---|---|
| committer | Bitflash <admin@bitflash.network> | 2026-08-20 18:30:30 -0300 |
| commit | 17741d9cf4c762ea03dc83e8aae6a176e5f338b0 (patch) | |
| tree | c8f27697cb0aa348317788c2a60274dc611c3c41 /src | |
| parent | f4d311a2b1be7ce1eb7082109a391099564271b9 (diff) | |
| parent | 56be66dd66e64e6d21eadd80a808b4627921059f (diff) | |
Merge pull request 'chain: add isolated testnet genesis' (#68) from testnet-consensus into main
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 103 | ||||
| -rw-r--r-- | src/main.h | 2 | ||||
| -rw-r--r-- | src/main_gui.cpp | 5 | ||||
| -rw-r--r-- | src/readme.txt | 2 | ||||
| -rw-r--r-- | src/selftest.cpp | 21 |
5 files changed, 104 insertions, 29 deletions
diff --git a/src/main.cpp b/src/main.cpp index 6fd8c82..5d266ff 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -41,12 +41,30 @@ unsigned int nTransactionsUpdated = 0; | |||
| 41 | map<COutPoint, CInPoint> mapNextTx; | 41 | map<COutPoint, CInPoint> mapNextTx; |
| 42 | 42 | ||
| 43 | map<uint256, CBlockIndex*> mapBlockIndex; | 43 | map<uint256, CBlockIndex*> mapBlockIndex; |
| 44 | // Bitflash genesis -- mined under RandomX PoW on 2026-07-22 | 44 | // Bitflash mainnet genesis -- mined under RandomX PoW for the 2026 stable |
| 45 | // (nTime 1753142400, nBits 0x1f0fffff, RandomX key "Bitflash/RandomX/v1/...") | 45 | // relaunch. Testnet gets its own resettable genesis below so block indexes, |
| 46 | // Bitflash 2026 stable relaunch genesis (2-min blocks, RandomX). Mined values. | 46 | // headers, and wallet scans cannot be accidentally mixed across networks. |
| 47 | unsigned int GENESIS_NONCE = 3141; | 47 | static const unsigned int MAINNET_GENESIS_TIME = 1753315200; // 2026-07-24 00:00:00 UTC |
| 48 | uint256 hashGenesisBlock("0x5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169"); | 48 | static const unsigned int MAINNET_GENESIS_NONCE = 3141; |
| 49 | uint256 hashGenesisMerkleRoot("0x1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325"); | 49 | static const char* MAINNET_GENESIS_TIMESTAMP = |
| 50 | "Bitflash 24/Jul/2026 Fair launch: one CPU one vote, no premine"; | ||
| 51 | static const char* MAINNET_GENESIS_HASH = | ||
| 52 | "0x5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169"; | ||
| 53 | static const char* MAINNET_GENESIS_MERKLE = | ||
| 54 | "0x1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325"; | ||
| 55 | |||
| 56 | static const unsigned int TESTNET_GENESIS_TIME = 1787184000; // 2026-08-20 00:00:00 UTC | ||
| 57 | static const unsigned int TESTNET_GENESIS_NONCE = 3199; | ||
| 58 | static const char* TESTNET_GENESIS_TIMESTAMP = | ||
| 59 | "Bitflash testnet 20/Aug/2026: resettable public test chain"; | ||
| 60 | static const char* TESTNET_GENESIS_HASH = | ||
| 61 | "0xa9d11c6d697bcb7aea0653bc088b12dcf9f44e732df205162cf085fd9d9963eb"; | ||
| 62 | static const char* TESTNET_GENESIS_MERKLE = | ||
| 63 | "0x510b293105e3ff85b8d4c3920e357f85d1a86bf199eb4e7d11f04f380030ec5c"; | ||
| 64 | |||
| 65 | unsigned int GENESIS_NONCE = MAINNET_GENESIS_NONCE; | ||
| 66 | uint256 hashGenesisBlock(MAINNET_GENESIS_HASH); | ||
| 67 | uint256 hashGenesisMerkleRoot(MAINNET_GENESIS_MERKLE); | ||
| 50 | CBlockIndex* pindexGenesisBlock = NULL; | 68 | CBlockIndex* pindexGenesisBlock = NULL; |
| 51 | int nBestHeight = -1; | 69 | int nBestHeight = -1; |
| 52 | uint256 hashBestChain = 0; | 70 | uint256 hashBestChain = 0; |
| @@ -117,6 +135,63 @@ static std::atomic<uint64> gParticipantHashRateX1000{0}; | |||
| 117 | static std::mutex gParticipantStatusMutex; | 135 | static std::mutex gParticipantStatusMutex; |
| 118 | static std::string gParticipantStatus; | 136 | static std::string gParticipantStatus; |
| 119 | 137 | ||
| 138 | void SelectGenesisParams(bool fTestNetIn) | ||
| 139 | { | ||
| 140 | static bool fGenesisParamsSelected = false; | ||
| 141 | static bool fGenesisParamsTestNet = false; | ||
| 142 | if (fGenesisParamsSelected && fGenesisParamsTestNet == fTestNetIn) | ||
| 143 | return; | ||
| 144 | |||
| 145 | fGenesisParamsSelected = true; | ||
| 146 | fGenesisParamsTestNet = fTestNetIn; | ||
| 147 | |||
| 148 | if (fTestNetIn) | ||
| 149 | { | ||
| 150 | GENESIS_NONCE = TESTNET_GENESIS_NONCE; | ||
| 151 | hashGenesisBlock = uint256(TESTNET_GENESIS_HASH); | ||
| 152 | hashGenesisMerkleRoot = uint256(TESTNET_GENESIS_MERKLE); | ||
| 153 | } | ||
| 154 | else | ||
| 155 | { | ||
| 156 | GENESIS_NONCE = MAINNET_GENESIS_NONCE; | ||
| 157 | hashGenesisBlock = uint256(MAINNET_GENESIS_HASH); | ||
| 158 | hashGenesisMerkleRoot = uint256(MAINNET_GENESIS_MERKLE); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | void SelectChainParams(bool fTestNetIn) | ||
| 163 | { | ||
| 164 | SelectNetworkParams(fTestNetIn); | ||
| 165 | SelectGenesisParams(fTestNetIn); | ||
| 166 | } | ||
| 167 | |||
| 168 | static CBlock BuildGenesisBlock() | ||
| 169 | { | ||
| 170 | const char* pszTimestamp = IsTestNet() ? | ||
| 171 | TESTNET_GENESIS_TIMESTAMP : MAINNET_GENESIS_TIMESTAMP; | ||
| 172 | |||
| 173 | CTransaction txNew; | ||
| 174 | txNew.vin.resize(1); | ||
| 175 | txNew.vout.resize(1); | ||
| 176 | txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << | ||
| 177 | vector<unsigned char>((unsigned char*)pszTimestamp, | ||
| 178 | (unsigned char*)pszTimestamp + strlen(pszTimestamp)); | ||
| 179 | txNew.vout[0].nValue = 50 * COIN; | ||
| 180 | txNew.vout[0].scriptPubKey = CScript() << | ||
| 181 | CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << | ||
| 182 | OP_CHECKSIG; | ||
| 183 | |||
| 184 | CBlock block; | ||
| 185 | block.vtx.push_back(txNew); | ||
| 186 | block.hashPrevBlock = 0; | ||
| 187 | block.hashMerkleRoot = block.BuildMerkleTree(); | ||
| 188 | block.nVersion = 1; | ||
| 189 | block.nTime = IsTestNet() ? TESTNET_GENESIS_TIME : MAINNET_GENESIS_TIME; | ||
| 190 | block.nBits = 0x1f0fffff; // = bnProofOfWorkLimit (Bitflash RandomX floor) | ||
| 191 | block.nNonce = GENESIS_NONCE; | ||
| 192 | return block; | ||
| 193 | } | ||
| 194 | |||
| 120 | void SetParticipantMiningStatus(const std::string& status) | 195 | void SetParticipantMiningStatus(const std::string& status) |
| 121 | { | 196 | { |
| 122 | // Updates the GUI status string only. Logging is done at each call site | 197 | // Updates the GUI status string only. Logging is done at each call site |
| @@ -2664,21 +2739,7 @@ bool LoadBlockIndex(bool fAllowNew) | |||
| 2664 | // vMerkleTree: 4a5e1e | 2739 | // vMerkleTree: 4a5e1e |
| 2665 | 2740 | ||
| 2666 | // Bitflash genesis block -- own header (fair launch, 2026 stable relaunch) | 2741 | // Bitflash genesis block -- own header (fair launch, 2026 stable relaunch) |
| 2667 | char* pszTimestamp = "Bitflash 24/Jul/2026 Fair launch: one CPU one vote, no premine"; | 2742 | CBlock block = BuildGenesisBlock(); |
| 2668 | CTransaction txNew; | ||
| 2669 | txNew.vin.resize(1); | ||
| 2670 | txNew.vout.resize(1); | ||
| 2671 | txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((unsigned char*)pszTimestamp, (unsigned char*)pszTimestamp + strlen(pszTimestamp)); | ||
| 2672 | txNew.vout[0].nValue = 50 * COIN; | ||
| 2673 | txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; | ||
| 2674 | CBlock block; | ||
| 2675 | block.vtx.push_back(txNew); | ||
| 2676 | block.hashPrevBlock = 0; | ||
| 2677 | block.hashMerkleRoot = block.BuildMerkleTree(); | ||
| 2678 | block.nVersion = 1; | ||
| 2679 | block.nTime = 1753315200; // 2026-07-24 00:00:00 UTC (stable relaunch) | ||
| 2680 | block.nBits = 0x1f0fffff; // = bnProofOfWorkLimit (Bitflash RandomX floor) | ||
| 2681 | block.nNonce = GENESIS_NONCE; | ||
| 2682 | 2743 | ||
| 2683 | // If the nonce has not been found yet, mine the genesis once (RandomX) | 2744 | // If the nonce has not been found yet, mine the genesis once (RandomX) |
| 2684 | // and print the values to be hardcoded in the constants above. | 2745 | // and print the values to be hardcoded in the constants above. |
| @@ -59,6 +59,8 @@ extern map<uint256, CBlockIndex*> mapBlockIndex; | |||
| 59 | extern uint256 hashGenesisBlock; | 59 | extern uint256 hashGenesisBlock; |
| 60 | extern uint256 hashGenesisMerkleRoot; | 60 | extern uint256 hashGenesisMerkleRoot; |
| 61 | extern unsigned int GENESIS_NONCE; | 61 | extern unsigned int GENESIS_NONCE; |
| 62 | void SelectGenesisParams(bool fTestNetIn); | ||
| 63 | void SelectChainParams(bool fTestNetIn); | ||
| 62 | extern CBlockIndex* pindexGenesisBlock; | 64 | extern CBlockIndex* pindexGenesisBlock; |
| 63 | extern int nBestHeight; | 65 | extern int nBestHeight; |
| 64 | extern uint256 hashBestChain; | 66 | extern uint256 hashBestChain; |
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index a01bdee..a561174 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -145,7 +145,7 @@ static void PrintUsage() | |||
| 145 | printf(" /onionservice=HOST.onion:PORT (advertise this node's Tor hidden service)\n"); | 145 | printf(" /onionservice=HOST.onion:PORT (advertise this node's Tor hidden service)\n"); |
| 146 | printf("\n"); | 146 | printf("\n"); |
| 147 | printf("Network:\n"); | 147 | printf("Network:\n"); |
| 148 | printf(" /testnet (isolated test network datadir, port, and magic)\n"); | 148 | printf(" /testnet (isolated test network genesis, datadir, port, and magic)\n"); |
| 149 | printf(" /port=N (P2P listen port, default 8433; testnet 18433)\n"); | 149 | printf(" /port=N (P2P listen port, default 8433; testnet 18433)\n"); |
| 150 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); | 150 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); |
| 151 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); | 151 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); |
| @@ -208,7 +208,8 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 208 | if (arg(argc,argv,"/datadir") || arg(argc,argv,"-datadir")) | 208 | if (arg(argc,argv,"/datadir") || arg(argc,argv,"-datadir")) |
| 209 | strSetDataDir = argval2(argc, argv, "/datadir", "-datadir"); | 209 | strSetDataDir = argval2(argc, argv, "/datadir", "-datadir"); |
| 210 | 210 | ||
| 211 | SelectNetworkParams(arg(argc, argv, "/testnet") || arg(argc, argv, "-testnet")); | 211 | bool fUseTestNet = arg(argc, argv, "/testnet") || arg(argc, argv, "-testnet"); |
| 212 | SelectChainParams(fUseTestNet); | ||
| 212 | 213 | ||
| 213 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) | 214 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) |
| 214 | fDebug = true; | 215 | fDebug = true; |
diff --git a/src/readme.txt b/src/readme.txt index 5d62791..810e8b7 100644 --- a/src/readme.txt +++ b/src/readme.txt | |||
| @@ -41,7 +41,7 @@ The resulting executable is src/bitflash.exe. | |||
| 41 | 41 | ||
| 42 | Command-line options (in addition to the original ones) | 42 | Command-line options (in addition to the original ones) |
| 43 | ------------------------------------------------------- | 43 | ------------------------------------------------------- |
| 44 | /testnet use isolated test network datadir, port 18433, and message magic | 44 | /testnet use isolated test network genesis, datadir, port 18433, and message magic |
| 45 | /port=N listen on P2P port N (default 8433; testnet default 18433) | 45 | /port=N listen on P2P port N (default 8433; testnet default 18433) |
| 46 | /socks=HOST:PORT | 46 | /socks=HOST:PORT |
| 47 | route outbound Nostr, .btf rendezvous, and direct onion peer | 47 | route outbound Nostr, .btf rendezvous, and direct onion peer |
diff --git a/src/selftest.cpp b/src/selftest.cpp index 30bd28e..1a72e3a 100644 --- a/src/selftest.cpp +++ b/src/selftest.cpp | |||
| @@ -3085,7 +3085,7 @@ static int RunNetworkParamsSelfTest() | |||
| 3085 | std::string strOldDataDir = strSetDataDir; | 3085 | std::string strOldDataDir = strSetDataDir; |
| 3086 | try | 3086 | try |
| 3087 | { | 3087 | { |
| 3088 | SelectNetworkParams(false); | 3088 | SelectChainParams(false); |
| 3089 | nFail += Check(!IsTestNet(), "starts on mainnet after explicit selection") ? 0 : 1; | 3089 | nFail += Check(!IsTestNet(), "starts on mainnet after explicit selection") ? 0 : 1; |
| 3090 | nFail += Check(ntohs(GetDefaultPort()) == MAINNET_PORT, | 3090 | nFail += Check(ntohs(GetDefaultPort()) == MAINNET_PORT, |
| 3091 | "mainnet default P2P port is 8433") ? 0 : 1; | 3091 | "mainnet default P2P port is 8433") ? 0 : 1; |
| @@ -3095,8 +3095,11 @@ static int RunNetworkParamsSelfTest() | |||
| 3095 | CMessageHeader mainHeader("ping", 0); | 3095 | CMessageHeader mainHeader("ping", 0); |
| 3096 | char mainMagic[4]; | 3096 | char mainMagic[4]; |
| 3097 | memcpy(mainMagic, mainHeader.pchMessageStart, sizeof(mainMagic)); | 3097 | memcpy(mainMagic, mainHeader.pchMessageStart, sizeof(mainMagic)); |
| 3098 | uint256 mainGenesis = hashGenesisBlock; | ||
| 3099 | uint256 mainMerkle = hashGenesisMerkleRoot; | ||
| 3100 | unsigned int mainNonce = GENESIS_NONCE; | ||
| 3098 | 3101 | ||
| 3099 | SelectNetworkParams(true); | 3102 | SelectChainParams(true); |
| 3100 | nFail += Check(IsTestNet(), "testnet selection is sticky") ? 0 : 1; | 3103 | nFail += Check(IsTestNet(), "testnet selection is sticky") ? 0 : 1; |
| 3101 | nFail += Check(ntohs(GetDefaultPort()) == TESTNET_PORT, | 3104 | nFail += Check(ntohs(GetDefaultPort()) == TESTNET_PORT, |
| 3102 | "testnet default P2P port is 18433") ? 0 : 1; | 3105 | "testnet default P2P port is 18433") ? 0 : 1; |
| @@ -3106,6 +3109,14 @@ static int RunNetworkParamsSelfTest() | |||
| 3106 | CMessageHeader testHeader("ping", 0); | 3109 | CMessageHeader testHeader("ping", 0); |
| 3107 | nFail += Check(memcmp(mainMagic, testHeader.pchMessageStart, sizeof(mainMagic)) != 0, | 3110 | nFail += Check(memcmp(mainMagic, testHeader.pchMessageStart, sizeof(mainMagic)) != 0, |
| 3108 | "testnet message magic differs from mainnet") ? 0 : 1; | 3111 | "testnet message magic differs from mainnet") ? 0 : 1; |
| 3112 | nFail += Check(hashGenesisBlock != mainGenesis && | ||
| 3113 | hashGenesisMerkleRoot != mainMerkle && | ||
| 3114 | GENESIS_NONCE != mainNonce, | ||
| 3115 | "testnet genesis constants differ from mainnet") ? 0 : 1; | ||
| 3116 | nFail += Check(hashGenesisBlock == uint256("0xa9d11c6d697bcb7aea0653bc088b12dcf9f44e732df205162cf085fd9d9963eb") && | ||
| 3117 | hashGenesisMerkleRoot == uint256("0x510b293105e3ff85b8d4c3920e357f85d1a86bf199eb4e7d11f04f380030ec5c") && | ||
| 3118 | GENESIS_NONCE == 3199, | ||
| 3119 | "testnet genesis constants are pinned") ? 0 : 1; | ||
| 3109 | 3120 | ||
| 3110 | std::string tmp; | 3121 | std::string tmp; |
| 3111 | if (!MakeTempDir(tmp)) | 3122 | if (!MakeTempDir(tmp)) |
| @@ -3115,9 +3126,9 @@ static int RunNetworkParamsSelfTest() | |||
| 3115 | else | 3126 | else |
| 3116 | { | 3127 | { |
| 3117 | strSetDataDir = tmp; | 3128 | strSetDataDir = tmp; |
| 3118 | SelectNetworkParams(false); | 3129 | SelectChainParams(false); |
| 3119 | std::string mainDir = GetAppDir(); | 3130 | std::string mainDir = GetAppDir(); |
| 3120 | SelectNetworkParams(true); | 3131 | SelectChainParams(true); |
| 3121 | std::string testDir = GetAppDir(); | 3132 | std::string testDir = GetAppDir(); |
| 3122 | nFail += Check(mainDir == tmp, | 3133 | nFail += Check(mainDir == tmp, |
| 3123 | "mainnet uses the selected data directory") ? 0 : 1; | 3134 | "mainnet uses the selected data directory") ? 0 : 1; |
| @@ -3138,7 +3149,7 @@ static int RunNetworkParamsSelfTest() | |||
| 3138 | } | 3149 | } |
| 3139 | 3150 | ||
| 3140 | strSetDataDir = strOldDataDir; | 3151 | strSetDataDir = strOldDataDir; |
| 3141 | SelectNetworkParams(false); | 3152 | SelectChainParams(false); |
| 3142 | 3153 | ||
| 3143 | printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", | 3154 | printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", |
| 3144 | nFail, nFail == 1 ? "" : "s"); | 3155 | nFail, nFail == 1 ? "" : "s"); |