6bfa26048d testnet: Add timewarp attack prevention for Testnet4 (Fabian Jahr)
0100907ca1 testnet: Add Testnet4 difficulty adjustment rules fix (Fabian Jahr)
74a04f9e7a testnet: Introduce Testnet4 (Fabian Jahr)
Pull request description:
To supplement the [ongoing conceptual discussion about a testnet reset](https://groups.google.com/g/bitcoindev/c/9bL00vRj7OU/m/9yCPo3uUBwAJ) I have drafted a move to v4 including a fix to the difficulty adjustment mechanism, which was part of the motivation that started the discussion.
Conceptual considerations:
- The conceptual discussion about doing a testnet4 or softforking the fix into testnet3 is outside of the scope of this PR and I would ask reviewers to contribute their opinions on this on the ML instead. However, I am happy to adapt this PR to a softfork change on testnet3 if there is consensus for that instead.
- The difficulty adjustment fix suggested here touches the `CalculateNextWorkRequired` function and uses the same logic used in `GetNextWorkRequired` to find the last previous block that was not mined with difficulty 1 under the exceptionf. An alternative fix briefly mentioned on the mailing list by Jameson Lopp would be to "restrict the special testnet minimum difficulty rule so that it can't be triggered on the block right before a difficulty retarget". That would also fix the issue but I find my suggestion here a bit more elegant.
ACKs for top commit:
jsarenik:
tACK 6bfa26048d
achow101:
ACK 6bfa26048d
murchandamus:
tACK 6bfa26048d
Tree-SHA512: 0b8b69a621406a944da5be551b863d065358ba94d85dd3b80d83c412660e230ee93b27316081fbee9b4851cc4ff8585db64c7dfa26cb5148ac835663f2712c3d
@ -34,12 +34,13 @@ Windows | `%LOCALAPPDATA%\Bitcoin\` <sup>[\[1\]](#note1)</sup>
3. All content of the data directory, except for `bitcoin.conf` file, is chain-specific. This means the actual data directory paths for non-mainnet cases differ:
@ -311,13 +311,15 @@ Both variables are used as a guideline for how much space the user needs on thei
Note that all values should be taken from a **fully synced** node and have an overhead of 5-10% added on top of its base value.
To calculate `m_assumed_blockchain_size`, take the size in GiB of these directories:
- For `mainnet` -> the data directory, excluding the `/testnet3`, `/signet`, and `/regtest` directories and any overly large files, e.g. a huge `debug.log`
- For `mainnet` -> the data directory, excluding the `/testnet3`, `/testnet4`, `/signet`, and `/regtest` directories and any overly large files, e.g. a huge `debug.log`
- For `testnet` -> `/testnet3`
- For `testnet4` -> `/testnet4`
- For `signet` -> `/signet`
To calculate `m_assumed_chain_state_size`, take the size in GiB of these directories:
argsman.AddArg("-rpcconnect=<ip>",strprintf("Send commands to node running on <ip> (default: %s)",DEFAULT_RPCCONNECT),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpccookiefile=<loc>","Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcpassword=<pw>","Password for JSON-RPC connections",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcport=<port>",strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, signet: %u, regtest: %u)",defaultBaseParams->RPCPort(),testnetBaseParams->RPCPort(),signetBaseParams->RPCPort(),regtestBaseParams->RPCPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcport=<port>",strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)",defaultBaseParams->RPCPort(),testnetBaseParams->RPCPort(),testnet4BaseParams->RPCPort(),signetBaseParams->RPCPort(),regtestBaseParams->RPCPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcuser=<user>","Username for JSON-RPC connections",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcwait","Wait for RPC server to start",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-rpcwaittimeout=<n>",strprintf("Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d)",DEFAULT_WAIT_CLIENT_TIMEOUT),ArgsManager::ALLOW_ANY|ArgsManager::DISALLOW_NEGATION,OptionsCategory::OPTIONS);
argsman.AddArg("-regtest","Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app development. Equivalent to -chain=regtest.",ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testactivationheight=name@height.","Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)",ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::DEBUG_TEST);
argsman.AddArg("-testnet","Use the test chain. Equivalent to -chain=test.",ArgsManager::ALLOW_ANY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testnet","Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed with the next release. Consider moving to testnet4 now by using -testnet4.",ArgsManager::ALLOW_ANY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testnet4","Use the testnet4 chain. Equivalent to -chain=testnet4.",ArgsManager::ALLOW_ANY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]","Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)",ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signet","Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter",ArgsManager::ALLOW_ANY,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-signetchallenge","Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)",ArgsManager::ALLOW_ANY|ArgsManager::DISALLOW_NEGATION,OptionsCategory::CHAINPARAMS);
argsman.AddArg("-alertnotify=<cmd>","Execute command when an alert is raised (%s in cmd is replaced by message)",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
#endif
argsman.AddArg("-assumevalid=<hex>",strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s, signet: %s)",defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(),testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(),signetChainParams->GetConsensus().defaultAssumeValid.GetHex()),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-assumevalid=<hex>",strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet3: %s, testnet4: %s, signet: %s)",defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(),testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(),testnet4ChainParams->GetConsensus().defaultAssumeValid.GetHex(),signetChainParams->GetConsensus().defaultAssumeValid.GetHex()),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-blocksdir=<dir>","Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)",ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-blocksxor",
strprintf("Whether an XOR-key applies to blocksdir *.dat files. "
argsman.AddArg("-maxmempool=<n>",strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)",DEFAULT_MAX_MEMPOOL_SIZE_MB),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-maxorphantx=<n>",strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)",DEFAULT_MAX_ORPHAN_TRANSACTIONS),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-mempoolexpiry=<n>",strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)",DEFAULT_MEMPOOL_EXPIRY_HOURS),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-minimumchainwork=<hex>",strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s, signet: %s)",defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(),testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(),signetChainParams->GetConsensus().nMinimumChainWork.GetHex()),ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::OPTIONS);
argsman.AddArg("-minimumchainwork=<hex>",strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet3: %s, testnet4: %s, signet: %s)",defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(),testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(),testnet4ChainParams->GetConsensus().nMinimumChainWork.GetHex(),signetChainParams->GetConsensus().nMinimumChainWork.GetHex()),ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::OPTIONS);
argsman.AddArg("-par=<n>",strprintf("Set the number of script verification threads (0 = auto, up to %d, <0 = leave that many cores free, default: %d)",
argsman.AddArg("-persistmempool",strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)",DEFAULT_PERSIST_MEMPOOL),ArgsManager::ALLOW_ANY,OptionsCategory::OPTIONS);
argsman.AddArg("-addnode=<ip>",strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.",MAX_ADDNODE_CONNECTIONS),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-asmap=<file>",strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.",DEFAULT_ASMAP_FILENAME),ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-bantime=<n>",strprintf("Default duration (in seconds) of manually configured bans (default: %u)",DEFAULT_MISBEHAVING_BANTIME),ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-bind=<addr>[:<port>][=onion]",strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)",defaultBaseParams->OnionServiceTargetPort(),testnetBaseParams->OnionServiceTargetPort(),signetBaseParams->OnionServiceTargetPort(),regtestBaseParams->OnionServiceTargetPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-bind=<addr>[:<port>][=onion]",strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)",defaultBaseParams->OnionServiceTargetPort(),testnetBaseParams->OnionServiceTargetPort(),testnet4BaseParams->OnionServiceTargetPort(),signetBaseParams->OnionServiceTargetPort(),regtestBaseParams->OnionServiceTargetPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-cjdnsreachable","If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)",ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-connect=<ip>","Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.",ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-discover","Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)",ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-peerbloomfilters",strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)",DEFAULT_PEERBLOOMFILTERS),ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters",strprintf("Serve compact block filters to peers per BIP 157 (default: %u)",DEFAULT_PEERBLOCKFILTERS),ArgsManager::ALLOW_ANY,OptionsCategory::CONNECTION);
argsman.AddArg("-txreconciliation",strprintf("Enable transaction reconciliations per BIP 330 (default: %d)",DEFAULT_TXRECONCILIATION_ENABLE),ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-port=<port>",strprintf("Listen for connections on <port> (default: %u, testnet: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).",defaultChainParams->GetDefaultPort(),testnetChainParams->GetDefaultPort(),signetChainParams->GetDefaultPort(),regtestChainParams->GetDefaultPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
argsman.AddArg("-port=<port>",strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).",defaultChainParams->GetDefaultPort(),testnetChainParams->GetDefaultPort(),testnet4ChainParams->GetDefaultPort(),signetChainParams->GetDefaultPort(),regtestChainParams->GetDefaultPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::CONNECTION);
#ifdef HAVE_SOCKADDR_UN
argsman.AddArg("-proxy=<ip:port|path>","Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled). May be a local file path prefixed with 'unix:' if the proxy supports it.",ArgsManager::ALLOW_ANY|ArgsManager::DISALLOW_ELISION,OptionsCategory::CONNECTION);
argsman.AddArg("-rpccookiefile=<loc>","Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)",ArgsManager::ALLOW_ANY,OptionsCategory::RPC);
argsman.AddArg("-rpccookieperms=<readable-by>",strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"),ArgsManager::ALLOW_ANY,OptionsCategory::RPC);
argsman.AddArg("-rpcpassword=<pw>","Password for JSON-RPC connections",ArgsManager::ALLOW_ANY|ArgsManager::SENSITIVE,OptionsCategory::RPC);
argsman.AddArg("-rpcport=<port>",strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, signet: %u, regtest: %u)",defaultBaseParams->RPCPort(),testnetBaseParams->RPCPort(),signetBaseParams->RPCPort(),regtestBaseParams->RPCPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::RPC);
argsman.AddArg("-rpcport=<port>",strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u)",defaultBaseParams->RPCPort(),testnetBaseParams->RPCPort(),testnet4BaseParams->RPCPort(),signetBaseParams->RPCPort(),regtestBaseParams->RPCPort()),ArgsManager::ALLOW_ANY|ArgsManager::NETWORK_ONLY,OptionsCategory::RPC);
argsman.AddArg("-rpcservertimeout=<n>",strprintf("Timeout during HTTP requests (default: %d)",DEFAULT_HTTP_SERVER_TIMEOUT),ArgsManager::ALLOW_ANY|ArgsManager::DEBUG_ONLY,OptionsCategory::RPC);
argsman.AddArg("-rpcthreads=<n>",strprintf("Set the number of threads to service RPC calls (default: %d)",DEFAULT_HTTP_THREADS),ArgsManager::ALLOW_ANY,OptionsCategory::RPC);
argsman.AddArg("-rpcuser=<user>","Username for JSON-RPC connections",ArgsManager::ALLOW_ANY|ArgsManager::SENSITIVE,OptionsCategory::RPC);
t3_warning_log="Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4."
defwarning_msg(node,approx_size):
returnf'Warning: Disk space for "{node.datadir_path/node.chain/"blocks"}" may not accommodate the block files. Approximately {approx_size} GB of data will be stored in this directory.'