diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 1 | ||||
| -rw-r--r-- | src/main.cpp | 163 | ||||
| -rw-r--r-- | src/main.h | 2 | ||||
| -rw-r--r-- | src/main_gui.cpp | 15 | ||||
| -rw-r--r-- | src/makefile.mingw | 1 | ||||
| -rw-r--r-- | src/net.cpp | 33 | ||||
| -rw-r--r-- | src/net.h | 25 | ||||
| -rw-r--r-- | src/randomx_pow.cpp | 117 | ||||
| -rw-r--r-- | src/randomx_pow.h | 7 | ||||
| -rw-r--r-- | src/readme.txt | 3 | ||||
| -rw-r--r-- | src/selftest.cpp | 85 |
11 files changed, 387 insertions, 65 deletions
diff --git a/src/Makefile b/src/Makefile index 888110f..c997ae3 100644 --- a/src/Makefile +++ b/src/Makefile | |||
| @@ -225,6 +225,7 @@ tests: test_bip32 test_compactblock bitflash-node | |||
| 225 | ./bitflash-node -selftest=wallet-crypto | 225 | ./bitflash-node -selftest=wallet-crypto |
| 226 | ./bitflash-node -selftest=wallet-encrypt | 226 | ./bitflash-node -selftest=wallet-encrypt |
| 227 | ./bitflash-node -selftest=net-message | 227 | ./bitflash-node -selftest=net-message |
| 228 | ./bitflash-node -selftest=network-params | ||
| 228 | ./bitflash-node -selftest=consensus-limits | 229 | ./bitflash-node -selftest=consensus-limits |
| 229 | ./bitflash-node -selftest=pool-stratum | 230 | ./bitflash-node -selftest=pool-stratum |
| 230 | ./bitflash-node -selftest=payout-ledger | 231 | ./bitflash-node -selftest=payout-ledger |
diff --git a/src/main.cpp b/src/main.cpp index 7398064..0fa6b89 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -42,12 +42,30 @@ unsigned int nTransactionsUpdated = 0; | |||
| 42 | map<COutPoint, CInPoint> mapNextTx; | 42 | map<COutPoint, CInPoint> mapNextTx; |
| 43 | 43 | ||
| 44 | map<uint256, CBlockIndex*> mapBlockIndex; | 44 | map<uint256, CBlockIndex*> mapBlockIndex; |
| 45 | // Bitflash genesis -- mined under RandomX PoW on 2026-07-22 | 45 | // Bitflash mainnet genesis -- mined under RandomX PoW for the 2026 stable |
| 46 | // (nTime 1753142400, nBits 0x1f0fffff, RandomX key "Bitflash/RandomX/v1/...") | 46 | // relaunch. Testnet gets its own resettable genesis below so block indexes, |
| 47 | // Bitflash 2026 stable relaunch genesis (2-min blocks, RandomX). Mined values. | 47 | // headers, and wallet scans cannot be accidentally mixed across networks. |
| 48 | unsigned int GENESIS_NONCE = 3141; | 48 | static const unsigned int MAINNET_GENESIS_TIME = 1753315200; // 2026-07-24 00:00:00 UTC |
| 49 | uint256 hashGenesisBlock("0x5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169"); | 49 | static const unsigned int MAINNET_GENESIS_NONCE = 3141; |
| 50 | uint256 hashGenesisMerkleRoot("0x1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325"); | 50 | static const char* MAINNET_GENESIS_TIMESTAMP = |
| 51 | "Bitflash 24/Jul/2026 Fair launch: one CPU one vote, no premine"; | ||
| 52 | static const char* MAINNET_GENESIS_HASH = | ||
| 53 | "0x5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169"; | ||
| 54 | static const char* MAINNET_GENESIS_MERKLE = | ||
| 55 | "0x1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325"; | ||
| 56 | |||
| 57 | static const unsigned int TESTNET_GENESIS_TIME = 1787184000; // 2026-08-20 00:00:00 UTC | ||
| 58 | static const unsigned int TESTNET_GENESIS_NONCE = 3199; | ||
| 59 | static const char* TESTNET_GENESIS_TIMESTAMP = | ||
| 60 | "Bitflash testnet 20/Aug/2026: resettable public test chain"; | ||
| 61 | static const char* TESTNET_GENESIS_HASH = | ||
| 62 | "0xa9d11c6d697bcb7aea0653bc088b12dcf9f44e732df205162cf085fd9d9963eb"; | ||
| 63 | static const char* TESTNET_GENESIS_MERKLE = | ||
| 64 | "0x510b293105e3ff85b8d4c3920e357f85d1a86bf199eb4e7d11f04f380030ec5c"; | ||
| 65 | |||
| 66 | unsigned int GENESIS_NONCE = MAINNET_GENESIS_NONCE; | ||
| 67 | uint256 hashGenesisBlock(MAINNET_GENESIS_HASH); | ||
| 68 | uint256 hashGenesisMerkleRoot(MAINNET_GENESIS_MERKLE); | ||
| 51 | CBlockIndex* pindexGenesisBlock = NULL; | 69 | CBlockIndex* pindexGenesisBlock = NULL; |
| 52 | int nBestHeight = -1; | 70 | int nBestHeight = -1; |
| 53 | uint256 hashBestChain = 0; | 71 | uint256 hashBestChain = 0; |
| @@ -254,6 +272,63 @@ static std::atomic<uint64> gParticipantHashRateX1000{0}; | |||
| 254 | static std::mutex gParticipantStatusMutex; | 272 | static std::mutex gParticipantStatusMutex; |
| 255 | static std::string gParticipantStatus; | 273 | static std::string gParticipantStatus; |
| 256 | 274 | ||
| 275 | void SelectGenesisParams(bool fTestNetIn) | ||
| 276 | { | ||
| 277 | static bool fGenesisParamsSelected = false; | ||
| 278 | static bool fGenesisParamsTestNet = false; | ||
| 279 | if (fGenesisParamsSelected && fGenesisParamsTestNet == fTestNetIn) | ||
| 280 | return; | ||
| 281 | |||
| 282 | fGenesisParamsSelected = true; | ||
| 283 | fGenesisParamsTestNet = fTestNetIn; | ||
| 284 | |||
| 285 | if (fTestNetIn) | ||
| 286 | { | ||
| 287 | GENESIS_NONCE = TESTNET_GENESIS_NONCE; | ||
| 288 | hashGenesisBlock = uint256(TESTNET_GENESIS_HASH); | ||
| 289 | hashGenesisMerkleRoot = uint256(TESTNET_GENESIS_MERKLE); | ||
| 290 | } | ||
| 291 | else | ||
| 292 | { | ||
| 293 | GENESIS_NONCE = MAINNET_GENESIS_NONCE; | ||
| 294 | hashGenesisBlock = uint256(MAINNET_GENESIS_HASH); | ||
| 295 | hashGenesisMerkleRoot = uint256(MAINNET_GENESIS_MERKLE); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | void SelectChainParams(bool fTestNetIn) | ||
| 300 | { | ||
| 301 | SelectNetworkParams(fTestNetIn); | ||
| 302 | SelectGenesisParams(fTestNetIn); | ||
| 303 | } | ||
| 304 | |||
| 305 | static CBlock BuildGenesisBlock() | ||
| 306 | { | ||
| 307 | const char* pszTimestamp = IsTestNet() ? | ||
| 308 | TESTNET_GENESIS_TIMESTAMP : MAINNET_GENESIS_TIMESTAMP; | ||
| 309 | |||
| 310 | CTransaction txNew; | ||
| 311 | txNew.vin.resize(1); | ||
| 312 | txNew.vout.resize(1); | ||
| 313 | txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << | ||
| 314 | vector<unsigned char>((unsigned char*)pszTimestamp, | ||
| 315 | (unsigned char*)pszTimestamp + strlen(pszTimestamp)); | ||
| 316 | txNew.vout[0].nValue = 50 * COIN; | ||
| 317 | txNew.vout[0].scriptPubKey = CScript() << | ||
| 318 | CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << | ||
| 319 | OP_CHECKSIG; | ||
| 320 | |||
| 321 | CBlock block; | ||
| 322 | block.vtx.push_back(txNew); | ||
| 323 | block.hashPrevBlock = 0; | ||
| 324 | block.hashMerkleRoot = block.BuildMerkleTree(); | ||
| 325 | block.nVersion = 1; | ||
| 326 | block.nTime = IsTestNet() ? TESTNET_GENESIS_TIME : MAINNET_GENESIS_TIME; | ||
| 327 | block.nBits = 0x1f0fffff; // = bnProofOfWorkLimit (Bitflash RandomX floor) | ||
| 328 | block.nNonce = GENESIS_NONCE; | ||
| 329 | return block; | ||
| 330 | } | ||
| 331 | |||
| 257 | void SetParticipantMiningStatus(const std::string& status) | 332 | void SetParticipantMiningStatus(const std::string& status) |
| 258 | { | 333 | { |
| 259 | // Updates the GUI status string only. Logging is done at each call site | 334 | // Updates the GUI status string only. Logging is done at each call site |
| @@ -2654,11 +2729,21 @@ string GetAppDir() | |||
| 2654 | { | 2729 | { |
| 2655 | return "."; | 2730 | return "."; |
| 2656 | } | 2731 | } |
| 2657 | static bool fMkdirDone; | 2732 | static string strCreatedBaseDir; |
| 2658 | if (!fMkdirDone) | 2733 | if (strCreatedBaseDir != strDir) |
| 2659 | { | 2734 | { |
| 2660 | fMkdirDone = true; | ||
| 2661 | _mkdir(strDir.c_str()); | 2735 | _mkdir(strDir.c_str()); |
| 2736 | strCreatedBaseDir = strDir; | ||
| 2737 | } | ||
| 2738 | if (IsTestNet()) | ||
| 2739 | { | ||
| 2740 | strDir += "/testnet"; | ||
| 2741 | static string strCreatedTestnetDir; | ||
| 2742 | if (strCreatedTestnetDir != strDir) | ||
| 2743 | { | ||
| 2744 | _mkdir(strDir.c_str()); | ||
| 2745 | strCreatedTestnetDir = strDir; | ||
| 2746 | } | ||
| 2662 | } | 2747 | } |
| 2663 | return strDir; | 2748 | return strDir; |
| 2664 | } | 2749 | } |
| @@ -2812,38 +2897,34 @@ bool LoadBlockIndex(bool fAllowNew) | |||
| 2812 | 2897 | ||
| 2813 | // Bitflash genesis block -- own header (fair launch) | 2898 | // Bitflash genesis block -- own header (fair launch) |
| 2814 | // | 2899 | // |
| 2815 | // Do not change pszTimestamp, the scriptPubKey, nTime or nNonce. They | 2900 | // Upstream moved the construction into BuildGenesisBlock() so mainnet |
| 2816 | // are the inputs to the genesis hash, and the genesis hash is | 2901 | // and the isolated testnet can share it. The mainnet inputs it uses are |
| 2817 | // consensus. Changing one on its own trips the assert below, which is | 2902 | // byte-identical to what this block built inline before the merge -- |
| 2818 | // loud and reverts cleanly; changing one and regenerating | 2903 | // timestamp string, nTime, nNonce, scriptPubKey, nBits and nVersion all |
| 2819 | // GENESIS_NONCE and hashGenesisBlock to match -- which is exactly what | 2904 | // verified equal against MAINNET_GENESIS_* -- so the mainnet genesis |
| 2820 | // the re-mining branch below prints out and invites -- gives a node | 2905 | // hash is unchanged. The warning below is why that was checked rather |
| 2821 | // that starts without complaint, builds its own chain from height 0, | 2906 | // than assumed, and it still applies to those constants: |
| 2822 | // and rejects every real peer as being on a different chain. That one | 2907 | // |
| 2823 | // fails silently, and the damage scales with how many people run the | 2908 | // Do not change MAINNET_GENESIS_TIMESTAMP, the scriptPubKey, |
| 2824 | // "fixed" build. | 2909 | // MAINNET_GENESIS_TIME or MAINNET_GENESIS_NONCE. They are the inputs to |
| 2825 | char* pszTimestamp = "Bitflash 24/Jul/2026 Fair launch: one CPU one vote, no premine"; | 2910 | // the genesis hash, and the genesis hash is consensus. Changing one on |
| 2826 | CTransaction txNew; | 2911 | // its own trips the assert below, which is loud and reverts cleanly; |
| 2827 | txNew.vin.resize(1); | 2912 | // changing one and regenerating GENESIS_NONCE and hashGenesisBlock to |
| 2828 | txNew.vout.resize(1); | 2913 | // match -- which is exactly what the re-mining branch below prints out |
| 2829 | txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((unsigned char*)pszTimestamp, (unsigned char*)pszTimestamp + strlen(pszTimestamp)); | 2914 | // and invites -- gives a node that starts without complaint, builds its |
| 2830 | txNew.vout[0].nValue = 50 * COIN; | 2915 | // own chain from height 0, and rejects every real peer as being on a |
| 2831 | txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; | 2916 | // different chain. That one fails silently, and the damage scales with |
| 2832 | CBlock block; | 2917 | // how many people run the "fixed" build. |
| 2833 | block.vtx.push_back(txNew); | 2918 | // |
| 2834 | block.hashPrevBlock = 0; | 2919 | // MAINNET_GENESIS_TIME is 1753315200, which is 2025-07-24T00:00:00Z, |
| 2835 | block.hashMerkleRoot = block.BuildMerkleTree(); | 2920 | // while the headline in MAINNET_GENESIS_TIMESTAMP reads 2026 -- as does |
| 2836 | block.nVersion = 1; | 2921 | // the comment upstream put on that constant, which is wrong about the |
| 2837 | // 1753315200 is 2025-07-24T00:00:00Z. The headline in pszTimestamp | 2922 | // year. This is a known discrepancy and not a typo in the value: it is |
| 2838 | // above reads 2026 and does not match it. This is a known discrepancy | 2923 | // only consensus-critical as an input to the genesis hash, the block |
| 2839 | // and not a typo in the constant: the value is only consensus-critical | 2924 | // hashes to hashGenesisBlock with it, and every node on the network |
| 2840 | // as an input to the genesis hash, the block hashes to | 2925 | // agrees. The mismatch is in the launched chain and cannot be corrected |
| 2841 | // hashGenesisBlock with it, and every node on the network agrees. The | 2926 | // -- see the warning above before deciding otherwise. |
| 2842 | // mismatch is in the launched chain and cannot be corrected -- see the | 2927 | CBlock block = BuildGenesisBlock(); |
| 2843 | // warning above before deciding otherwise. | ||
| 2844 | block.nTime = 1753315200; | ||
| 2845 | block.nBits = 0x1f0fffff; // = bnProofOfWorkLimit (Bitflash RandomX floor) | ||
| 2846 | block.nNonce = GENESIS_NONCE; | ||
| 2847 | 2928 | ||
| 2848 | // If the nonce has not been found yet, mine the genesis once (RandomX) | 2929 | // If the nonce has not been found yet, mine the genesis once (RandomX) |
| 2849 | // and print the values to be hardcoded in the constants above. | 2930 | // and print the values to be hardcoded in the constants above. |
| @@ -94,6 +94,8 @@ extern map<uint256, CBlockIndex*> mapBlockIndex; | |||
| 94 | extern uint256 hashGenesisBlock; | 94 | extern uint256 hashGenesisBlock; |
| 95 | extern uint256 hashGenesisMerkleRoot; | 95 | extern uint256 hashGenesisMerkleRoot; |
| 96 | extern unsigned int GENESIS_NONCE; | 96 | extern unsigned int GENESIS_NONCE; |
| 97 | void SelectGenesisParams(bool fTestNetIn); | ||
| 98 | void SelectChainParams(bool fTestNetIn); | ||
| 97 | extern CBlockIndex* pindexGenesisBlock; | 99 | extern CBlockIndex* pindexGenesisBlock; |
| 98 | extern int nBestHeight; | 100 | extern int nBestHeight; |
| 99 | extern uint256 hashBestChain; | 101 | extern uint256 hashBestChain; |
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index dd001c8..2e4eb91 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -120,7 +120,7 @@ static void PrintUsage() | |||
| 120 | printf(" wallet-crypto, wallet-encrypt, wallet-portability,\n"); | 120 | printf(" wallet-crypto, wallet-encrypt, wallet-portability,\n"); |
| 121 | printf(" net-message,\n"); | 121 | printf(" net-message,\n"); |
| 122 | printf(" consensus-limits, pool-stratum,\n"); | 122 | printf(" consensus-limits, pool-stratum,\n"); |
| 123 | printf(" parse-money, socks5-proxy, or managed-tor\n"); | 123 | printf(" parse-money, network-params, socks5-proxy, or managed-tor\n"); |
| 124 | printf("\n"); | 124 | printf("\n"); |
| 125 | printf("Mining mode:\n"); | 125 | printf("Mining mode:\n"); |
| 126 | printf(" /operator\n"); | 126 | printf(" /operator\n"); |
| @@ -132,6 +132,8 @@ static void PrintUsage() | |||
| 132 | printf(" /stratumbridgeport=N (default 3333; listen on 127.0.0.1)\n"); | 132 | printf(" /stratumbridgeport=N (default 3333; listen on 127.0.0.1)\n"); |
| 133 | printf(" /solomine\n"); | 133 | printf(" /solomine\n"); |
| 134 | printf(" /genproclimit=N (mining threads; 0 or absent = every core but one)\n"); | 134 | printf(" /genproclimit=N (mining threads; 0 or absent = every core but one)\n"); |
| 135 | printf(" /nolargepages (do not ask for 2 MB pages for the RandomX\n"); | ||
| 136 | printf(" cache, dataset and scratchpads)\n"); | ||
| 135 | printf(" /checkblocks=N (blocks re-verified at startup, default 288, 0 = all)\n"); | 137 | printf(" /checkblocks=N (blocks re-verified at startup, default 288, 0 = all)\n"); |
| 136 | printf("\n"); | 138 | printf("\n"); |
| 137 | printf("Pool operator announcement:\n"); | 139 | printf("Pool operator announcement:\n"); |
| @@ -148,7 +150,8 @@ static void PrintUsage() | |||
| 148 | printf(" /onionservice=HOST.onion:PORT (advertise this node's Tor hidden service)\n"); | 150 | printf(" /onionservice=HOST.onion:PORT (advertise this node's Tor hidden service)\n"); |
| 149 | printf("\n"); | 151 | printf("\n"); |
| 150 | printf("Network:\n"); | 152 | printf("Network:\n"); |
| 151 | printf(" /port=N (P2P listen port, default 8433)\n"); | 153 | printf(" /testnet (isolated test network genesis, datadir, port, and magic)\n"); |
| 154 | printf(" /port=N (P2P listen port, default 8433; testnet 18433)\n"); | ||
| 152 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); | 155 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); |
| 153 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); | 156 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); |
| 154 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); | 157 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); |
| @@ -214,6 +217,9 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 214 | if (arg(argc,argv,"/datadir") || arg(argc,argv,"-datadir")) | 217 | if (arg(argc,argv,"/datadir") || arg(argc,argv,"-datadir")) |
| 215 | strSetDataDir = argval2(argc, argv, "/datadir", "-datadir"); | 218 | strSetDataDir = argval2(argc, argv, "/datadir", "-datadir"); |
| 216 | 219 | ||
| 220 | bool fUseTestNet = arg(argc, argv, "/testnet") || arg(argc, argv, "-testnet"); | ||
| 221 | SelectChainParams(fUseTestNet); | ||
| 222 | |||
| 217 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) | 223 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) |
| 218 | fDebug = true; | 224 | fDebug = true; |
| 219 | 225 | ||
| @@ -284,6 +290,11 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 284 | if (!strCheckBlocks.empty()) | 290 | if (!strCheckBlocks.empty()) |
| 285 | nCheckBlocksOnLoad = atoi(strCheckBlocks.c_str()); | 291 | nCheckBlocksOnLoad = atoi(strCheckBlocks.c_str()); |
| 286 | 292 | ||
| 293 | // Must be read before LoadBlockIndex(), which is what first calls | ||
| 294 | // RandomXInit() and fixes how the cache is allocated. | ||
| 295 | if (arg(argc,argv,"/nolargepages") || arg(argc,argv,"-nolargepages")) | ||
| 296 | fRandomXLargePages = false; | ||
| 297 | |||
| 287 | // /genproclimit=N -- threads to hash with. 0 or absent means automatic, | 298 | // /genproclimit=N -- threads to hash with. 0 or absent means automatic, |
| 288 | // which is every core but one. Named after Bitcoin's own option so it reads | 299 | // which is every core but one. Named after Bitcoin's own option so it reads |
| 289 | // familiarly to anyone who has run one of these before. | 300 | // familiarly to anyone who has run one of these before. |
diff --git a/src/makefile.mingw b/src/makefile.mingw index 740bba6..362794a 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw | |||
| @@ -116,6 +116,7 @@ tests: test_bip32.exe bitflash.exe | |||
| 116 | ./bitflash.exe -selftest=wallet-backend-default | 116 | ./bitflash.exe -selftest=wallet-backend-default |
| 117 | ./bitflash.exe -selftest=wallet-convert | 117 | ./bitflash.exe -selftest=wallet-convert |
| 118 | ./bitflash.exe -selftest=net-message | 118 | ./bitflash.exe -selftest=net-message |
| 119 | ./bitflash.exe -selftest=network-params | ||
| 119 | ./bitflash.exe -selftest=consensus-limits | 120 | ./bitflash.exe -selftest=consensus-limits |
| 120 | ./bitflash.exe -selftest=pool-stratum | 121 | ./bitflash.exe -selftest=pool-stratum |
| 121 | ./bitflash.exe -selftest=socks5-proxy | 122 | ./bitflash.exe -selftest=socks5-proxy |
diff --git a/src/net.cpp b/src/net.cpp index bb05259..0576402 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -50,10 +50,14 @@ static int BtfPoll(BtfPollFd* pfd, unsigned int nfd, int nTimeoutMs) | |||
| 50 | // | 50 | // |
| 51 | // Global state variables | 51 | // Global state variables |
| 52 | // | 52 | // |
| 53 | static const char pchMainnetMessageStart[4] = { 0xbf, 0x20, 0x5c, 0xfd }; | ||
| 54 | static const char pchTestnetMessageStart[4] = { (char)0xce, (char)0xe2, (char)0xc0, (char)0xff }; | ||
| 55 | static bool fTestNet = false; | ||
| 56 | char pchMessageStart[4] = { 0xbf, 0x20, 0x5c, 0xfd }; | ||
| 53 | bool fClient = false; | 57 | bool fClient = false; |
| 54 | uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); | 58 | uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); |
| 55 | CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices); | 59 | CAddress addrLocalHost(0, GetDefaultPort(), nLocalServices); |
| 56 | unsigned short nListenPort = DEFAULT_PORT; // local P2P port (tunable via /port) | 60 | unsigned short nListenPort = GetDefaultPort(); // local P2P port (tunable via /port) |
| 57 | CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); | 61 | CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); |
| 58 | CNode* pnodeLocalHost = &nodeLocalHost; | 62 | CNode* pnodeLocalHost = &nodeLocalHost; |
| 59 | bool fShutdown = false; | 63 | bool fShutdown = false; |
| @@ -90,6 +94,29 @@ static int64 nBtfHandshakeSilent = 0; | |||
| 90 | static string strBtfLastDialFail; | 94 | static string strBtfLastDialFail; |
| 91 | static string strBtfLastHandshakeTimeout; | 95 | static string strBtfLastHandshakeTimeout; |
| 92 | 96 | ||
| 97 | bool IsTestNet() | ||
| 98 | { | ||
| 99 | return fTestNet; | ||
| 100 | } | ||
| 101 | |||
| 102 | unsigned short GetDefaultPort() | ||
| 103 | { | ||
| 104 | return htons(fTestNet ? TESTNET_PORT : MAINNET_PORT); | ||
| 105 | } | ||
| 106 | |||
| 107 | void SelectNetworkParams(bool fTestNetIn) | ||
| 108 | { | ||
| 109 | if (fTestNet == fTestNetIn) | ||
| 110 | return; | ||
| 111 | |||
| 112 | fTestNet = fTestNetIn; | ||
| 113 | memcpy(pchMessageStart, | ||
| 114 | fTestNet ? pchTestnetMessageStart : pchMainnetMessageStart, | ||
| 115 | sizeof(pchMessageStart)); | ||
| 116 | nListenPort = GetDefaultPort(); | ||
| 117 | addrLocalHost.port = nListenPort; | ||
| 118 | } | ||
| 119 | |||
| 93 | void BtfChurnNoteResolveAttempt() | 120 | void BtfChurnNoteResolveAttempt() |
| 94 | { | 121 | { |
| 95 | CRITICAL_BLOCK(cs_btfChurn) | 122 | CRITICAL_BLOCK(cs_btfChurn) |
| @@ -288,6 +315,7 @@ string GetDiagnosticsText() | |||
| 288 | int nMedian = GetPeerMedianHeight(); | 315 | int nMedian = GetPeerMedianHeight(); |
| 289 | 316 | ||
| 290 | str += "Bitflash node diagnostics\n"; | 317 | str += "Bitflash node diagnostics\n"; |
| 318 | str += strprintf(" network %s\n", IsTestNet() ? "testnet" : "mainnet"); | ||
| 291 | str += strprintf(" uptime %s\n", | 319 | str += strprintf(" uptime %s\n", |
| 292 | FormatAge(nNodeStartTime ? nNow - nNodeStartTime : -1).c_str()); | 320 | FormatAge(nNodeStartTime ? nNow - nNodeStartTime : -1).c_str()); |
| 293 | if (nMedian < 0) | 321 | if (nMedian < 0) |
| @@ -338,6 +366,7 @@ string GetDiagnosticsText() | |||
| 338 | nMining, | 366 | nMining, |
| 339 | (RandomXFastReady() ? 2080 : 256) + 2 * nMining).c_str() | 367 | (RandomXFastReady() ? 2080 : 256) + 2 * nMining).c_str() |
| 340 | : ", not mining"); | 368 | : ", not mining"); |
| 369 | str += strprintf(" large pages %s\n", RandomXLargePagesStatus()); | ||
| 341 | 370 | ||
| 342 | str += SockAccountingText(); | 371 | str += SockAccountingText(); |
| 343 | 372 | ||
| @@ -12,7 +12,13 @@ class CBlockIndex; | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | static const unsigned short DEFAULT_PORT = htons(8433); | 15 | // Held in host byte order, unlike the DEFAULT_PORT constant these replace, |
| 16 | // which was htons(8433). Nothing is lost: net.cpp's GetDefaultPort() applies | ||
| 17 | // htons() itself and is what every caller now uses, so the value that reaches | ||
| 18 | // a sockaddr is byte-for-byte what it was. Mainnet stays on 8433. | ||
| 19 | static const unsigned short MAINNET_PORT = 8433; | ||
| 20 | static const unsigned short TESTNET_PORT = 18433; | ||
| 21 | static const unsigned int PUBLISH_HOPS = 5; | ||
| 16 | enum | 22 | enum |
| 17 | { | 23 | { |
| 18 | NODE_NETWORK = (1 << 0), | 24 | NODE_NETWORK = (1 << 0), |
| @@ -30,6 +36,9 @@ enum | |||
| 30 | bool IsBlockFetchNearTip(); | 36 | bool IsBlockFetchNearTip(); |
| 31 | 37 | ||
| 32 | bool GetMyExternalIP(unsigned int& ipRet); | 38 | bool GetMyExternalIP(unsigned int& ipRet); |
| 39 | bool IsTestNet(); | ||
| 40 | unsigned short GetDefaultPort(); | ||
| 41 | void SelectNetworkParams(bool fTestNetIn); | ||
| 33 | CNode* ConnectNodeBtf(const string& strBtfAddr); | 42 | CNode* ConnectNodeBtf(const string& strBtfAddr); |
| 34 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, | 43 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, |
| 35 | const string& strOnion, const unsigned char enc_pub[32], | 44 | const string& strOnion, const unsigned char enc_pub[32], |
| @@ -266,15 +275,17 @@ void CheckForShutdown(int n); | |||
| 266 | // The message start string is designed to be unlikely to occur in normal data. | 275 | // The message start string is designed to be unlikely to occur in normal data. |
| 267 | // The characters are rarely used upper ascii, not valid as UTF-8, and produce | 276 | // The characters are rarely used upper ascii, not valid as UTF-8, and produce |
| 268 | // a large 4-byte int at any alignment. | 277 | // a large 4-byte int at any alignment. |
| 269 | // Magic bytes unique to the Bitflash network (0xbf = "BF"). Second byte bumped | 278 | // Magic bytes unique to the selected Bitflash network. Mainnet uses 0xbf = |
| 270 | // to 0x20 for the 2026 stable relaunch so the old test chain can't interfere. | 279 | // "BF"; testnet swaps the whole sequence so a test node cannot handshake with |
| 271 | static const char pchMessageStart[4] = { 0xbf, 0x20, 0x5c, 0xfd }; | 280 | // mainnet before consensus-level testnet activation exists. |
| 281 | extern char pchMessageStart[4]; | ||
| 272 | 282 | ||
| 273 | class CMessageHeader | 283 | class CMessageHeader |
| 274 | { | 284 | { |
| 275 | public: | 285 | public: |
| 276 | enum { COMMAND_SIZE=12 }; | 286 | enum { COMMAND_SIZE=12 }; |
| 277 | char pchMessageStart[sizeof(::pchMessageStart)]; | 287 | enum { MESSAGE_START_SIZE=4 }; |
| 288 | char pchMessageStart[MESSAGE_START_SIZE]; | ||
| 278 | char pchCommand[COMMAND_SIZE]; | 289 | char pchCommand[COMMAND_SIZE]; |
| 279 | unsigned int nMessageSize; | 290 | unsigned int nMessageSize; |
| 280 | 291 | ||
| @@ -365,7 +376,7 @@ public: | |||
| 365 | nServices = 0; | 376 | nServices = 0; |
| 366 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | 377 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); |
| 367 | ip = 0; | 378 | ip = 0; |
| 368 | port = DEFAULT_PORT; | 379 | port = GetDefaultPort(); |
| 369 | nTime = GetAdjustedTime(); | 380 | nTime = GetAdjustedTime(); |
| 370 | nLastFailed = 0; | 381 | nLastFailed = 0; |
| 371 | } | 382 | } |
| @@ -395,7 +406,7 @@ public: | |||
| 395 | nServices = nServicesIn; | 406 | nServices = nServicesIn; |
| 396 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | 407 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); |
| 397 | ip = 0; | 408 | ip = 0; |
| 398 | port = DEFAULT_PORT; | 409 | port = GetDefaultPort(); |
| 399 | nTime = GetAdjustedTime(); | 410 | nTime = GetAdjustedTime(); |
| 400 | nLastFailed = 0; | 411 | nLastFailed = 0; |
| 401 | 412 | ||
diff --git a/src/randomx_pow.cpp b/src/randomx_pow.cpp index 9c59364..a509543 100644 --- a/src/randomx_pow.cpp +++ b/src/randomx_pow.cpp | |||
| @@ -24,6 +24,50 @@ static std::mutex g_csInit; | |||
| 24 | static bool g_fInit = false; | 24 | static bool g_fInit = false; |
| 25 | static bool g_fFast = false; | 25 | static bool g_fFast = false; |
| 26 | 26 | ||
| 27 | // RandomX reads a 256 MB cache, a 2 GB dataset and a 2 MB scratchpad per VM | ||
| 28 | // at random, so most reads miss the TLB on 4 KB pages. 2 MB pages recover | ||
| 29 | // roughly a tenth of the hash rate. | ||
| 30 | // | ||
| 31 | // The pool must be reserved first (vm.nr_hugepages), and RandomX returns NULL | ||
| 32 | // instead of falling back, so each allocation below retries without the flag. | ||
| 33 | bool fRandomXLargePages = true; // cleared by -nolargepages | ||
| 34 | static bool g_fLargeCache = false; | ||
| 35 | static bool g_fLargeDataset = false; | ||
| 36 | static bool g_fLargeAny = false; | ||
| 37 | |||
| 38 | // How to reserve the large-page pool, for the hint printed when a large-page | ||
| 39 | // allocation falls back to normal pages. The mechanism is OS-specific. | ||
| 40 | static const char* LargePagesHint() | ||
| 41 | { | ||
| 42 | #ifdef _WIN32 | ||
| 43 | return "enable the \"Lock pages in memory\" privilege and run elevated"; | ||
| 44 | #else | ||
| 45 | return "reserve them with: sysctl vm.nr_hugepages=1280"; | ||
| 46 | #endif | ||
| 47 | } | ||
| 48 | |||
| 49 | static randomx_flags WithLargePages(randomx_flags f) | ||
| 50 | { | ||
| 51 | return (randomx_flags)(f | RANDOMX_FLAG_LARGE_PAGES); | ||
| 52 | } | ||
| 53 | |||
| 54 | // Ask for a cache in large pages, then plain pages. Sets fLargeOut to say | ||
| 55 | // which one answered. | ||
| 56 | static randomx_cache* AllocCache(randomx_flags flags, bool& fLargeOut) | ||
| 57 | { | ||
| 58 | fLargeOut = false; | ||
| 59 | if (fRandomXLargePages) | ||
| 60 | { | ||
| 61 | randomx_cache* c = randomx_alloc_cache(WithLargePages(flags)); | ||
| 62 | if (c) | ||
| 63 | { | ||
| 64 | fLargeOut = true; | ||
| 65 | return c; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | return randomx_alloc_cache(flags); | ||
| 69 | } | ||
| 70 | |||
| 27 | 71 | ||
| 28 | bool RandomXInit() | 72 | bool RandomXInit() |
| 29 | { | 73 | { |
| @@ -37,28 +81,56 @@ bool RandomXInit() | |||
| 37 | // Detect the best flags for this CPU (JIT, hardware AES, Argon2). | 81 | // Detect the best flags for this CPU (JIT, hardware AES, Argon2). |
| 38 | g_flags = randomx_get_flags(); | 82 | g_flags = randomx_get_flags(); |
| 39 | 83 | ||
| 40 | g_cache = randomx_alloc_cache(g_flags); | 84 | g_cache = AllocCache(g_flags, g_fLargeCache); |
| 41 | if (!g_cache) | 85 | if (!g_cache) |
| 42 | { | 86 | { |
| 43 | // Try without JIT as a fallback | 87 | // Try without JIT as a fallback |
| 44 | g_flags = RANDOMX_FLAG_DEFAULT; | 88 | g_flags = RANDOMX_FLAG_DEFAULT; |
| 45 | g_cache = randomx_alloc_cache(g_flags); | 89 | g_cache = AllocCache(g_flags, g_fLargeCache); |
| 46 | if (!g_cache) | 90 | if (!g_cache) |
| 47 | return error("RandomX: failed to allocate cache (256 MB)"); | 91 | return error("RandomX: failed to allocate cache (256 MB)"); |
| 48 | } | 92 | } |
| 49 | randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY)); | 93 | randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY)); |
| 50 | 94 | ||
| 51 | // Verification VM in light mode (cache only) | 95 | // Verification VM in light mode (cache only). The scratchpad is only 2 MB |
| 52 | g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL); | 96 | // and this VM is created once, but it hashes every block the node ever |
| 97 | // validates, so it gets the same treatment. | ||
| 98 | bool fLargeVerify = false; | ||
| 99 | if (fRandomXLargePages) | ||
| 100 | { | ||
| 101 | g_vmVerify = randomx_create_vm(WithLargePages(g_flags), g_cache, NULL); | ||
| 102 | fLargeVerify = (g_vmVerify != NULL); | ||
| 103 | } | ||
| 104 | if (!g_vmVerify) | ||
| 105 | g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL); | ||
| 53 | if (!g_vmVerify) | 106 | if (!g_vmVerify) |
| 54 | return error("RandomX: failed to create verification VM"); | 107 | return error("RandomX: failed to create verification VM"); |
| 55 | 108 | ||
| 109 | g_fLargeAny = g_fLargeCache || fLargeVerify; | ||
| 56 | g_fInit = true; | 110 | g_fInit = true; |
| 57 | printf("RandomX: initialized (cache 256 MB, flags=%d)\n", (int)g_flags); | 111 | printf("RandomX: initialized (cache 256 MB, flags=%d, large pages: %s)\n", |
| 112 | (int)g_flags, RandomXLargePagesStatus()); | ||
| 113 | if (fRandomXLargePages && !g_fLargeCache) | ||
| 114 | printf("RandomX: large pages unavailable for the cache; %s " | ||
| 115 | "for about 10%% more hash rate\n", LargePagesHint()); | ||
| 58 | return true; | 116 | return true; |
| 59 | } | 117 | } |
| 60 | 118 | ||
| 61 | 119 | ||
| 120 | const char* RandomXLargePagesStatus() | ||
| 121 | { | ||
| 122 | if (!fRandomXLargePages) | ||
| 123 | return "off (-nolargepages)"; | ||
| 124 | if (g_fLargeCache && g_fLargeDataset) | ||
| 125 | return "cache + dataset"; | ||
| 126 | if (g_fLargeCache) | ||
| 127 | return "cache only"; | ||
| 128 | if (g_fLargeDataset) | ||
| 129 | return "dataset only"; | ||
| 130 | return g_fLargeAny ? "scratchpad only" : "unavailable"; | ||
| 131 | } | ||
| 132 | |||
| 133 | |||
| 62 | // One dataset, once, no matter how many miners ask for it. | 134 | // One dataset, once, no matter how many miners ask for it. |
| 63 | // | 135 | // |
| 64 | // Every miner thread calls this at startup. The g_fFast guard below is only | 136 | // Every miner thread calls this at startup. The g_fFast guard below is only |
| @@ -88,8 +160,18 @@ bool RandomXInitDataset(int nThreads) | |||
| 88 | if (g_fFast) | 160 | if (g_fFast) |
| 89 | return true; | 161 | return true; |
| 90 | 162 | ||
| 91 | randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); | 163 | // Only RANDOMX_FLAG_LARGE_PAGES means anything to randomx_alloc_dataset; |
| 92 | g_dataset = randomx_alloc_dataset(fastFlags); | 164 | // the rest of g_flags belongs to the VMs that read it. |
| 165 | if (fRandomXLargePages) | ||
| 166 | { | ||
| 167 | g_dataset = randomx_alloc_dataset(WithLargePages(RANDOMX_FLAG_DEFAULT)); | ||
| 168 | g_fLargeDataset = (g_dataset != NULL); | ||
| 169 | if (!g_dataset) | ||
| 170 | printf("RandomX: large pages unavailable for the 2 GB dataset; %s " | ||
| 171 | "for about 10%% more hash rate\n", LargePagesHint()); | ||
| 172 | } | ||
| 173 | if (!g_dataset) | ||
| 174 | g_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); | ||
| 93 | if (!g_dataset) | 175 | if (!g_dataset) |
| 94 | { | 176 | { |
| 95 | printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n"); | 177 | printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n"); |
| @@ -158,13 +240,26 @@ void* RandomXCreateMinerVM() | |||
| 158 | { | 240 | { |
| 159 | if (!g_fInit && !RandomXInit()) | 241 | if (!g_fInit && !RandomXInit()) |
| 160 | return NULL; | 242 | return NULL; |
| 243 | |||
| 244 | randomx_flags flags = g_flags; | ||
| 245 | randomx_cache* cache = g_cache; | ||
| 246 | randomx_dataset* dataset = NULL; | ||
| 161 | if (g_fFast && g_dataset) | 247 | if (g_fFast && g_dataset) |
| 162 | { | 248 | { |
| 163 | randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); | 249 | flags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); |
| 164 | return randomx_create_vm(fastFlags, NULL, g_dataset); | 250 | cache = NULL; |
| 251 | dataset = g_dataset; | ||
| 252 | } | ||
| 253 | |||
| 254 | // Each thread gets its own 2 MB scratchpad, so the large-page pool can run | ||
| 255 | // dry partway through a fleet of miners. Threads that miss out still run. | ||
| 256 | if (fRandomXLargePages) | ||
| 257 | { | ||
| 258 | randomx_vm* vm = randomx_create_vm(WithLargePages(flags), cache, dataset); | ||
| 259 | if (vm) | ||
| 260 | return vm; | ||
| 165 | } | 261 | } |
| 166 | // Light mode: own VM sharing the cache | 262 | return randomx_create_vm(flags, cache, dataset); |
| 167 | return randomx_create_vm(g_flags, g_cache, NULL); | ||
| 168 | } | 263 | } |
| 169 | 264 | ||
| 170 | 265 | ||
diff --git a/src/randomx_pow.h b/src/randomx_pow.h index 0027571..355b708 100644 --- a/src/randomx_pow.h +++ b/src/randomx_pow.h | |||
| @@ -41,4 +41,11 @@ uint256 RandomXHashWithVM(void* vm, const void* pHeader, size_t nSize); | |||
| 41 | // True when the 2 GB dataset is ready (fast mode active). | 41 | // True when the 2 GB dataset is ready (fast mode active). |
| 42 | bool RandomXFastReady(); | 42 | bool RandomXFastReady(); |
| 43 | 43 | ||
| 44 | // Ask for large (2 MB) pages for the cache, dataset and scratchpads. Set false | ||
| 45 | // by -nolargepages. Must be set before the first RandomXInit(). | ||
| 46 | extern bool fRandomXLargePages; | ||
| 47 | |||
| 48 | // Which allocations actually got large pages, for the status display. | ||
| 49 | const char* RandomXLargePagesStatus(); | ||
| 50 | |||
| 44 | #endif | 51 | #endif |
diff --git a/src/readme.txt b/src/readme.txt index 7490a9a..455884c 100644 --- a/src/readme.txt +++ b/src/readme.txt | |||
| @@ -41,7 +41,8 @@ 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 | /port=N listen on P2P port N (default 8433) | 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 | /socks=HOST:PORT | 46 | /socks=HOST:PORT |
| 46 | route outbound Nostr, .btf rendezvous, and direct onion peer | 47 | route outbound Nostr, .btf rendezvous, and direct onion peer |
| 47 | dials through a SOCKS5 proxy, e.g. /socks=127.0.0.1:9050 for local Tor | 48 | dials through a SOCKS5 proxy, e.g. /socks=127.0.0.1:9050 for local Tor |
diff --git a/src/selftest.cpp b/src/selftest.cpp index 65f215b..357d532 100644 --- a/src/selftest.cpp +++ b/src/selftest.cpp | |||
| @@ -3118,6 +3118,87 @@ static int RunNetMessageSelfTest() | |||
| 3118 | return nFail == 0 ? 0 : 1; | 3118 | return nFail == 0 ? 0 : 1; |
| 3119 | } | 3119 | } |
| 3120 | 3120 | ||
| 3121 | static int RunNetworkParamsSelfTest() | ||
| 3122 | { | ||
| 3123 | fflush(stdout); | ||
| 3124 | printf("network-params self-test\n"); | ||
| 3125 | |||
| 3126 | int nFail = 0; | ||
| 3127 | std::string strOldDataDir = strSetDataDir; | ||
| 3128 | try | ||
| 3129 | { | ||
| 3130 | SelectChainParams(false); | ||
| 3131 | nFail += Check(!IsTestNet(), "starts on mainnet after explicit selection") ? 0 : 1; | ||
| 3132 | nFail += Check(ntohs(GetDefaultPort()) == MAINNET_PORT, | ||
| 3133 | "mainnet default P2P port is 8433") ? 0 : 1; | ||
| 3134 | CAddress mainAddr("127.0.0.1"); | ||
| 3135 | nFail += Check(mainAddr.port == htons(MAINNET_PORT), | ||
| 3136 | "mainnet address parsing uses the mainnet default port") ? 0 : 1; | ||
| 3137 | CMessageHeader mainHeader("ping", 0); | ||
| 3138 | char mainMagic[4]; | ||
| 3139 | memcpy(mainMagic, mainHeader.pchMessageStart, sizeof(mainMagic)); | ||
| 3140 | uint256 mainGenesis = hashGenesisBlock; | ||
| 3141 | uint256 mainMerkle = hashGenesisMerkleRoot; | ||
| 3142 | unsigned int mainNonce = GENESIS_NONCE; | ||
| 3143 | |||
| 3144 | SelectChainParams(true); | ||
| 3145 | nFail += Check(IsTestNet(), "testnet selection is sticky") ? 0 : 1; | ||
| 3146 | nFail += Check(ntohs(GetDefaultPort()) == TESTNET_PORT, | ||
| 3147 | "testnet default P2P port is 18433") ? 0 : 1; | ||
| 3148 | CAddress testAddr("127.0.0.1"); | ||
| 3149 | nFail += Check(testAddr.port == htons(TESTNET_PORT), | ||
| 3150 | "testnet address parsing uses the testnet default port") ? 0 : 1; | ||
| 3151 | CMessageHeader testHeader("ping", 0); | ||
| 3152 | nFail += Check(memcmp(mainMagic, testHeader.pchMessageStart, sizeof(mainMagic)) != 0, | ||
| 3153 | "testnet message magic differs from mainnet") ? 0 : 1; | ||
| 3154 | nFail += Check(hashGenesisBlock != mainGenesis && | ||
| 3155 | hashGenesisMerkleRoot != mainMerkle && | ||
| 3156 | GENESIS_NONCE != mainNonce, | ||
| 3157 | "testnet genesis constants differ from mainnet") ? 0 : 1; | ||
| 3158 | nFail += Check(hashGenesisBlock == uint256("0xa9d11c6d697bcb7aea0653bc088b12dcf9f44e732df205162cf085fd9d9963eb") && | ||
| 3159 | hashGenesisMerkleRoot == uint256("0x510b293105e3ff85b8d4c3920e357f85d1a86bf199eb4e7d11f04f380030ec5c") && | ||
| 3160 | GENESIS_NONCE == 3199, | ||
| 3161 | "testnet genesis constants are pinned") ? 0 : 1; | ||
| 3162 | |||
| 3163 | std::string tmp; | ||
| 3164 | if (!MakeTempDir(tmp)) | ||
| 3165 | { | ||
| 3166 | nFail += Check(false, "creates a temporary data directory") ? 0 : 1; | ||
| 3167 | } | ||
| 3168 | else | ||
| 3169 | { | ||
| 3170 | strSetDataDir = tmp; | ||
| 3171 | SelectChainParams(false); | ||
| 3172 | std::string mainDir = GetAppDir(); | ||
| 3173 | SelectChainParams(true); | ||
| 3174 | std::string testDir = GetAppDir(); | ||
| 3175 | nFail += Check(mainDir == tmp, | ||
| 3176 | "mainnet uses the selected data directory") ? 0 : 1; | ||
| 3177 | nFail += Check(testDir == tmp + "/testnet", | ||
| 3178 | "testnet stores data below a testnet subdirectory") ? 0 : 1; | ||
| 3179 | RemoveTree(tmp); | ||
| 3180 | } | ||
| 3181 | } | ||
| 3182 | catch (const std::exception& e) | ||
| 3183 | { | ||
| 3184 | printf(" FAIL exception: %s\n", e.what()); | ||
| 3185 | nFail++; | ||
| 3186 | } | ||
| 3187 | catch (...) | ||
| 3188 | { | ||
| 3189 | printf(" FAIL unknown exception\n"); | ||
| 3190 | nFail++; | ||
| 3191 | } | ||
| 3192 | |||
| 3193 | strSetDataDir = strOldDataDir; | ||
| 3194 | SelectChainParams(false); | ||
| 3195 | |||
| 3196 | printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", | ||
| 3197 | nFail, nFail == 1 ? "" : "s"); | ||
| 3198 | fflush(stdout); | ||
| 3199 | return nFail == 0 ? 0 : 1; | ||
| 3200 | } | ||
| 3201 | |||
| 3121 | static CBlock MakeSizedConsensusBlock(size_t nScriptBytes) | 3202 | static CBlock MakeSizedConsensusBlock(size_t nScriptBytes) |
| 3122 | { | 3203 | { |
| 3123 | CTransaction tx; | 3204 | CTransaction tx; |
| @@ -3716,6 +3797,8 @@ int RunSelfTest(const std::string& name) | |||
| 3716 | return RunWalletPortabilitySelfTest(); | 3797 | return RunWalletPortabilitySelfTest(); |
| 3717 | if (name == "net-message") | 3798 | if (name == "net-message") |
| 3718 | return RunNetMessageSelfTest(); | 3799 | return RunNetMessageSelfTest(); |
| 3800 | if (name == "network-params") | ||
| 3801 | return RunNetworkParamsSelfTest(); | ||
| 3719 | if (name == "consensus-limits") | 3802 | if (name == "consensus-limits") |
| 3720 | return RunConsensusLimitsSelfTest(); | 3803 | return RunConsensusLimitsSelfTest(); |
| 3721 | if (name == "pool-stratum") | 3804 | if (name == "pool-stratum") |
| @@ -3730,6 +3813,6 @@ int RunSelfTest(const std::string& name) | |||
| 3730 | return RunManagedTorSelfTest(); | 3813 | return RunManagedTorSelfTest(); |
| 3731 | 3814 | ||
| 3732 | printf("Unknown self-test '%s'\n", name.c_str()); | 3815 | printf("Unknown self-test '%s'\n", name.c_str()); |
| 3733 | printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity, db-env-reopen, wallet-sqlite, wallet-sqlite-migration, wallet-crypto, wallet-encrypt, wallet-sqlite-encrypt, wallet-backend-default, wallet-convert, wallet-portability, net-message, consensus-limits, pool-stratum, payout-ledger, parse-money, socks5-proxy, managed-tor\n"); | 3816 | printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity, db-env-reopen, wallet-sqlite, wallet-sqlite-migration, wallet-crypto, wallet-encrypt, wallet-sqlite-encrypt, wallet-backend-default, wallet-convert, wallet-portability, net-message, network-params, consensus-limits, pool-stratum, payout-ledger, parse-money, socks5-proxy, managed-tor\n"); |
| 3734 | return 1; | 3817 | return 1; |
| 3735 | } | 3818 | } |