From a778ddd62fe13755609203f8f2f0851d27a487fd Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 10 Sep 2019 10:41:11 +1000 Subject: [PATCH 01/13] Merge #16477: build: skip deploying plugins we dont use in macdeployqtplus 1ac7b7f66bd53d2d719377c7e0ab8b38e970c88f scripts: filter more qt plugins we don't use in macdeployqtplus (fanquake) 57cdd0697d5c8fdae4a4c1da1cfa092916be87e7 scripts: misc cleanups in macdeployqtplus (fanquake) 51729a4dfacb5b8d3945d39fa581eaaa9ac9603d scripts: use format() in macdeployqtplus (fanquake) 1c37e81694efb08fea889d9f5151c91dbb74d025 scripts: add type annotations to macdeployqtplus (fanquake) Pull request description: I frequently run `make deploy` while testing on macOS to get a properly light themed .app. With a brew installed Qt, this currently results in a pretty bloated executable: | branch | .app size | .dmg size | `make deploy` time | | ------- | --------- | --------- | --------------------- | | master (febf3a856bcfb8fef2cb4ddcb8d1e0cab8a22580) | 235mb | 86mb | 38s | | This PR (da98f6d470d236c027b7eb8b5f5552fdca04e803) | 51mb | 21mb | 22s | Similar change to dd367ff8c93c2f9e112a324f5cd737c7fa7a2ffa. ```diff 'QtGui.framework'], 'pluginPath': '/usr/local/opt/qt/plugins', 'qtPath': '/usr/local/opt/qt'} -[('platforminputcontexts', 'libqtvirtualkeyboardplugin.dylib'), - ('geoservices', 'libqtgeoservices_esri.dylib'), - ('geoservices', 'libqtgeoservices_mapboxgl.dylib'), - ('geoservices', 'libqtgeoservices_nokia.dylib'), - ('geoservices', 'libqtgeoservices_itemsoverlay.dylib'), - ('geoservices', 'libqtgeoservices_osm.dylib'), - ('geoservices', 'libqtgeoservices_mapbox.dylib'), - ('sceneparsers', 'libgltfsceneexport.dylib'), - ('sceneparsers', 'libgltfsceneimport.dylib'), - ('platforms', 'libqwebgl.dylib'), +[('platforms', 'libqwebgl.dylib'), ('platforms', 'libqoffscreen.dylib'), ('platforms', 'libqminimal.dylib'), ('platforms', 'libqcocoa.dylib'), ('platformthemes', 'libqxdgdesktopportal.dylib'), - ('printsupport', 'libcocoaprintersupport.dylib'), - ('webview', 'libqtwebview_webengine.dylib'), - ('webview', 'libqtwebview_darwin.dylib'), - ('geometryloaders', 'libdefaultgeometryloader.dylib'), - ('geometryloaders', 'libgltfgeometryloader.dylib'), ('styles', 'libqmacstyle.dylib'), - ('canbus', 'libqttinycanbus.dylib'), - ('canbus', 'libqtpassthrucanbus.dylib'), - ('canbus', 'libqtvirtualcanbus.dylib'), - ('canbus', 'libqtpeakcanbus.dylib'), ('bearer', 'libqgenericbearer.dylib'), - ('imageformats', 'libqgif.dylib'), - ('imageformats', 'libqwbmp.dylib'), - ('imageformats', 'libqwebp.dylib'), - ('imageformats', 'libqico.dylib'), - ('imageformats', 'libqmacheif.dylib'), - ('imageformats', 'libqjpeg.dylib'), - ('imageformats', 'libqtiff.dylib'), - ('imageformats', 'libqicns.dylib'), - ('imageformats', 'libqtga.dylib'), - ('imageformats', 'libqmacjp2.dylib'), - ('texttospeech', 'libqtexttospeech_speechosx.dylib'), - ('generic', 'libqtuiotouchplugin.dylib'), - ('renderplugins', 'libscene2d.dylib'), - ('gamepads', 'libdarwingamepad.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_thai.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_openwnn.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_hangul.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_pinyin.dylib'), - ('virtualkeyboard', 'libqtvirtualkeyboard_tcime.dylib')] + ('generic', 'libqtuiotouchplugin.dylib')] ``` ACKs for top commit: laanwj: ACK 1ac7b7f66bd53d2d719377c7e0ab8b38e970c88f (purely Python code review and the fact that this passes travis, cannot run this on a mac) dongcarl: tested ACK 1ac7b7f66bd53d2d719377c7e0ab8b38e970c88f Tree-SHA512: 5974eeaf7229bb5bde2b283c1331ec57ee87f624db146401f6b77dee4ee5502e0bd669958a46205f10398a371f8e6c91ddacb9f0e1943f9f7d042fb6de7957a8 --- contrib/macdeploy/macdeployqtplus | 152 +++++++++++++++++++----------- 1 file changed, 97 insertions(+), 55 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 8142bc37b0d6..1b3adb9c156c 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -19,6 +19,7 @@ import subprocess, sys, re, os, shutil, stat, os.path, time from string import Template from argparse import ArgumentParser +from typing import List, Optional # This is ported from the original macdeployqt with modifications @@ -48,18 +49,18 @@ class FrameworkInfo(object): return False def __str__(self): - return """ Framework name: %s - Framework directory: %s - Framework path: %s - Binary name: %s - Binary directory: %s - Binary path: %s - Version: %s - Install name: %s - Deployed install name: %s - Source file Path: %s - Deployed Directory (relative to bundle): %s -""" % (self.frameworkName, + return """ Framework name: {} + Framework directory: {} + Framework path: {} + Binary name: {} + Binary directory: {} + Binary path: {} + Version: {} + Install name: {} + Deployed install name: {} + Source file Path: {} + Deployed Directory (relative to bundle): {} +""".format(self.frameworkName, self.frameworkDirectory, self.frameworkPath, self.binaryName, @@ -85,7 +86,7 @@ class FrameworkInfo(object): bundleBinaryDirectory = "Contents/MacOS" @classmethod - def fromOtoolLibraryLine(cls, line): + def fromOtoolLibraryLine(cls, line: str) -> Optional['FrameworkInfo']: # Note: line must be trimmed if line == "": return None @@ -146,13 +147,12 @@ class FrameworkInfo(object): info.sourceContentsDirectory = os.path.join(info.frameworkPath, "Contents") info.sourceVersionContentsDirectory = os.path.join(info.frameworkPath, "Versions", info.version, "Contents") info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources") - info.destinationContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Contents") info.destinationVersionContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Versions", info.version, "Contents") return info class ApplicationBundleInfo(object): - def __init__(self, path): + def __init__(self, path: str): self.path = path appName = "Dash-Qt" self.binaryPath = os.path.join(path, "Contents", "MacOS", appName) @@ -167,7 +167,7 @@ class DeploymentInfo(object): self.pluginPath = None self.deployedFrameworks = [] - def detectQtPath(self, frameworkDirectory): + def detectQtPath(self, frameworkDirectory: str): parentDir = os.path.dirname(frameworkDirectory) if os.path.exists(os.path.join(parentDir, "translations")): # Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x" @@ -180,9 +180,9 @@ class DeploymentInfo(object): if os.path.exists(pluginPath): self.pluginPath = pluginPath - def usesFramework(self, name): - nameDot = "%s." % name - libNameDot = "lib%s." % name + def usesFramework(self, name: str) -> bool: + nameDot = "{}.".format(name) + libNameDot = "lib{}.".format(name) for framework in self.deployedFrameworks: if framework.endswith(".framework"): if framework.startswith(nameDot): @@ -192,7 +192,7 @@ class DeploymentInfo(object): return True return False -def getFrameworks(binaryPath, verbose): +def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose >= 3: print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") @@ -202,7 +202,7 @@ def getFrameworks(binaryPath, verbose): if verbose >= 1: sys.stderr.write(o_stderr) sys.stderr.flush() - raise RuntimeError("otool failed with return code %d" % otool.returncode) + raise RuntimeError("otool failed with return code {}".format(otool.returncode)) otoolLines = o_stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary @@ -221,11 +221,11 @@ def getFrameworks(binaryPath, verbose): return libraries -def runInstallNameTool(action, *args): +def runInstallNameTool(action: str, *args): installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool") subprocess.check_call([installnametoolbin, "-"+action] + list(args)) -def changeInstallName(oldName, newName, binaryPath, verbose): +def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int): if verbose >= 3: print("Using install_name_tool:") print(" in", binaryPath) @@ -233,21 +233,21 @@ def changeInstallName(oldName, newName, binaryPath, verbose): print(" to", newName) runInstallNameTool("change", oldName, newName, binaryPath) -def changeIdentification(id, binaryPath, verbose): +def changeIdentification(id: str, binaryPath: str, verbose: int): if verbose >= 3: print("Using install_name_tool:") print(" change identification in", binaryPath) print(" to", id) runInstallNameTool("id", id, binaryPath) -def runStrip(binaryPath, verbose): +def runStrip(binaryPath: str, verbose: int): stripbin=os.getenv("STRIP", "strip") if verbose >= 3: print("Using strip:") print(" stripped", binaryPath) subprocess.check_call([stripbin, "-x", binaryPath]) -def copyFramework(framework, path, verbose): +def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]: if framework.sourceFilePath.startswith("Qt"): #standard place for Nokia Qt installer's frameworks fromPath = "/Library/Frameworks/" + framework.sourceFilePath @@ -309,7 +309,7 @@ def copyFramework(framework, path, verbose): return toPath -def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploymentInfo=None): +def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo: if deploymentInfo is None: deploymentInfo = DeploymentInfo() @@ -323,7 +323,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym # Get the Qt path from one of the Qt frameworks if deploymentInfo.qtPath is None and framework.isQtFramework(): deploymentInfo.detectQtPath(framework.frameworkDirectory) - + if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath): if verbose >= 2: print(framework.frameworkName, "already deployed, skipping.") @@ -355,15 +355,15 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym return deploymentInfo -def deployFrameworksForAppBundle(applicationBundle, strip, verbose): +def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo: frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0 and verbose >= 1: - print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)) + print("Warning: Could not find any external frameworks to deploy in {}.".format(applicationBundle.path)) return DeploymentInfo() else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) -def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): +def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: DeploymentInfo, strip: bool, verbose: int): # Lookup available plugins, exclude unneeded plugins = [] if deploymentInfo.pluginPath is None: @@ -373,10 +373,12 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): if pluginDirectory == "designer": # Skip designer plugins continue - elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend": - # Deploy the phonon plugins only if phonon is in use - if not deploymentInfo.usesFramework("phonon"): - continue + elif pluginDirectory == "printsupport": + # Skip printsupport plugins + continue + elif pluginDirectory == "imageformats": + # Skip imageformats plugins + continue elif pluginDirectory == "sqldrivers": # Deploy the sql plugins only if QtSql is in use if not deploymentInfo.usesFramework("QtSql"): @@ -409,6 +411,42 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): # Deploy the mediaservice plugins only if QtMultimediaWidgets is in use if not deploymentInfo.usesFramework("QtMultimediaWidgets"): continue + elif pluginDirectory == "canbus": + # Deploy the canbus plugins only if QtSerialBus is in use + if not deploymentInfo.usesFramework("QtSerialBus"): + continue + elif pluginDirectory == "webview": + # Deploy the webview plugins only if QtWebView is in use + if not deploymentInfo.usesFramework("QtWebView"): + continue + elif pluginDirectory == "gamepads": + # Deploy the webview plugins only if QtGamepad is in use + if not deploymentInfo.usesFramework("QtGamepad"): + continue + elif pluginDirectory == "geoservices": + # Deploy the webview plugins only if QtLocation is in use + if not deploymentInfo.usesFramework("QtLocation"): + continue + elif pluginDirectory == "texttospeech": + # Deploy the texttospeech plugins only if QtTextToSpeech is in use + if not deploymentInfo.usesFramework("QtTextToSpeech"): + continue + elif pluginDirectory == "virtualkeyboard": + # Deploy the virtualkeyboard plugins only if QtVirtualKeyboard is in use + if not deploymentInfo.usesFramework("QtVirtualKeyboard"): + continue + elif pluginDirectory == "sceneparsers": + # Deploy the virtualkeyboard plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue + elif pluginDirectory == "renderplugins": + # Deploy the renderplugins plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue + elif pluginDirectory == "geometryloaders": + # Deploy the geometryloaders plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue for pluginName in filenames: pluginPath = os.path.join(pluginDirectory, pluginName) @@ -431,6 +469,10 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): # Deploy the accessible qtquick plugin only if QtQuick is in use if not deploymentInfo.usesFramework("QtQuick"): continue + elif pluginPath == "platforminputcontexts/libqtvirtualkeyboardplugin.dylib": + # Deploy the virtualkeyboardplugin plugin only if QtVirtualKeyboard is in use + if not deploymentInfo.usesFramework("QtVirtualKeyboard"): + continue plugins.append((pluginDirectory, pluginName)) @@ -499,7 +541,7 @@ app_bundle = config.app_bundle[0] if not os.path.exists(app_bundle): if verbose >= 1: - sys.stderr.write("Error: Could not find app bundle \"%s\"\n" % (app_bundle)) + sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) sys.exit(1) app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] @@ -511,7 +553,7 @@ if config.translations_dir and config.translations_dir[0]: translations_dir = config.translations_dir[0] else: if verbose >= 1: - sys.stderr.write("Error: Could not find translation dir \"%s\"\n" % (translations_dir)) + sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(translations_dir)) sys.exit(1) # ------------------------------------------------ @@ -520,7 +562,7 @@ for p in config.add_resources: print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not find additional resource file \"{}\"\n".format(p)) sys.exit(1) # ------------------------------------------------ @@ -534,13 +576,13 @@ if len(config.fancy) == 1: if verbose >= 1: sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n") sys.exit(1) - + p = config.fancy[0] if verbose >= 3: - print("Fancy: Loading \"%s\"..." % p) + print("Fancy: Loading \"{}\"...".format(p)) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: @@ -548,7 +590,7 @@ if len(config.fancy) == 1: fancy = plistlib.load(fp, fmt=plistlib.FMT_XML) except: if verbose >= 1: - sys.stderr.write("Error: Could not parse fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: @@ -562,18 +604,18 @@ if len(config.fancy) == 1: assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) except: if verbose >= 1: - sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) if "background_picture" in fancy: bp = fancy["background_picture"] if verbose >= 3: - print("Fancy: Resolving background picture \"%s\"..." % bp) + print("Fancy: Resolving background picture \"{}\"...".format(bp)) if not os.path.exists(bp): bp = os.path.join(os.path.dirname(p), bp) if not os.path.exists(bp): if verbose >= 1: - sys.stderr.write("Error: Could not find background picture at \"%s\" or \"%s\"\n" % (fancy["background_picture"], bp)) + sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp)) sys.exit(1) else: fancy["background_picture"] = bp @@ -624,7 +666,7 @@ try: config.plugins = False except RuntimeError as e: if verbose >= 1: - sys.stderr.write("Error: %s\n" % str(e)) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ @@ -637,7 +679,7 @@ if config.plugins: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) except RuntimeError as e: if verbose >= 1: - sys.stderr.write("Error: %s\n" % str(e)) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ @@ -653,14 +695,14 @@ else: else: sys.stderr.write("Error: Could not find Qt translation path\n") sys.exit(1) - add_qt_tr = ["qt_%s.qm" % lng for lng in config.add_qt_tr[0].split(",")] + add_qt_tr = ["qt_{}.qm".format(lng) for lng in config.add_qt_tr[0].split(",")] for lng_file in add_qt_tr: p = os.path.join(qt_tr_dir, lng_file) if verbose >= 3: - print("Checking for \"%s\"..." % p) + print("Checking for \"{}\"...".format(p)) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file)) + sys.stderr.write("Error: Could not find Qt translation file \"{}\"\n".format(lng_file)) sys.exit(1) # ------------------------------------------------ @@ -701,14 +743,14 @@ if config.sign and 'CODESIGNARGS' not in os.environ: print("You must set the CODESIGNARGS environment variable. Skipping signing.") elif config.sign: if verbose >= 1: - print("Code-signing app bundle %s"%(target,)) - subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True) + print("Code-signing app bundle {}".format(target)) + subprocess.check_call("codesign --force {} {}".format(os.environ['CODESIGNARGS'], target), shell=True) # ------------------------------------------------ if config.dmg is not None: - def runHDIUtil(verb, image_basename, **kwargs): + def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] if "capture_stdout" in kwargs: del kwargs["capture_stdout"] @@ -722,7 +764,7 @@ if config.dmg is not None: for key, value in kwargs.items(): hdiutil_args.append("-" + key) - if not value is True: + if value is not True: hdiutil_args.append(str(value)) return run(hdiutil_args, universal_newlines=True) @@ -851,7 +893,7 @@ if config.dmg is not None: if verbose >= 2: print("+ Finalizing .dmg disk image +") time.sleep(5) - + try: runHDIUtil("convert", dmg_name + ".temp", format="UDBZ", o=dmg_name + ".dmg", ov=True) except subprocess.CalledProcessError as e: From d5d3c3e35ddb335c3281514a8a624746619a5b9b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 10 Sep 2019 12:42:52 +0300 Subject: [PATCH 02/13] Merge #16680: Preparations for more testchains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3bf9d8cac09fc88727ef2f2a2bea33b90b625e50 Testchains: Qt: Simplify network/chain styles (Jorge Timón) 052c54ecb02695e5d2694e8e0cbf5ccc89de86e8 Testchains: Generic selection with -chain= in addition of -testnet and -regtest (Jorge Timón) Pull request description: Separated from #8994 as suggested by MarcoFalke and Sjors in https://github.com/bitcoin/bitcoin/pull/8994#issuecomment-522555390 You can't really test the qt changes on their own, so to test them, use #8994 . ACKs for top commit: MarcoFalke: ACK 3bf9d8cac09fc88727ef2f2a2bea33b90b625e50 Tree-SHA512: 5b5e6083ebc0a44505a507fac633e7af18037c85e5e73f5d1e6f7e730575d3297ba8a31d1c2441df623b273f061c32d8fa324f4aa6bead01d23e88582029b568 --- src/bitcoin-cli.cpp | 2 +- src/bitcoin-tx.cpp | 2 +- src/bitcoind.cpp | 2 +- src/chainparamsbase.cpp | 5 +++-- src/qt/bitcoin.cpp | 4 ++-- src/qt/guiutil.cpp | 4 ++-- src/qt/networkstyle.cpp | 11 +++++++---- src/qt/networkstyle.h | 2 +- src/qt/test/apptests.cpp | 2 +- src/test/util_tests.cpp | 2 +- src/util/system.cpp | 7 ++++--- 11 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 1884d1c2a200..bd3ef610dfc5 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -148,7 +148,7 @@ static int AppInitRPC(int argc, char* argv[]) tfm::format(std::cerr, "Error reading configuration file: %s\n", error); return EXIT_FAILURE; } - // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) + // Check for -chain, -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) try { SelectBaseParams(gArgs.GetChainName()); } catch (const std::exception& e) { diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 9fc4c2f7b93c..b5890316653b 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -88,7 +88,7 @@ static int AppInitRawTx(int argc, char* argv[]) return true; } - // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) + // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(gArgs.GetChainName()); } catch (const std::exception& e) { diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 25c54be437b0..97b2b67531ef 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -88,7 +88,7 @@ static bool AppInit(int argc, char* argv[]) if (!args.ReadConfigFiles(error, true)) { return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error))); } - // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) + // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(args.GetChainName()); } catch (const std::exception& e) { diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 74a9039c6f55..9a6e33b9823c 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -32,9 +32,10 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) argsman.AddArg("-llmqtestinstantsendparams=:", "Override the default LLMQ size for the LLMQ_TEST_INSTANTSEND quorums (default: 3:2, regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-powtargetspacing=", "Override the default PowTargetSpacing value in seconds (default: 2.5 minutes, devnet-only)", ArgsManager::ALLOW_INT, OptionsCategory::CHAINPARAMS); argsman.AddArg("-minimumdifficultyblocks=", "The number of blocks that can be mined with the minimum difficulty at the start of a chain (default: 0, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-chain=", "Use the chain (default: main). Allowed values: main, test, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); 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.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-testnet", "Use the test chain", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); + "This is intended for regression testing tools and app development. Equivalent to -chain=regtest", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-vbparams=::(::(::))", "Use given start/end times for specified version bits deployment (regtest-only). " "Specifying window, threshold/thresholdstart, thresholdmin and falloffcoeff is optional.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 915863e84d4b..835cd9c41711 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -541,7 +541,7 @@ int GuiMain(int argc, char* argv[]) // - QSettings() will use the new application name after this, resulting in network-specific settings // - Needs to be done before createOptionsModel - // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) + // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { @@ -559,7 +559,7 @@ int GuiMain(int argc, char* argv[]) return EXIT_FAILURE; } - QScopedPointer networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + QScopedPointer networkStyle(NetworkStyle::instantiate(Params().NetworkIDString())); assert(!networkStyle.isNull()); // Allow for separate UI settings for testnets // QApplication::setApplicationName(networkStyle->getAppName()); // moved to NetworkStyle::NetworkStyle diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9ee068276ff6..d60a2d898ed5 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -838,7 +838,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) // Start client minimized QString strArgs = "-min"; // Set -testnet /-regtest options - strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false))); + strArgs += QString::fromStdString(strprintf(" -chain=%s", gArgs.GetChainName())); // Set the path to the shortcut target psl->SetPath(pszExePath); @@ -933,7 +933,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) optionFile << "Name=Dash Core\n"; else optionFile << strprintf("Name=Dash Core (%s)\n", chain); - optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false)); + optionFile << "Exec=" << pszExePath << strprintf(" -min -chain=%s\n", chain); optionFile << "Terminal=false\n"; optionFile << "Hidden=false\n"; optionFile.close(); diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index 47f8f3e7eb74..cb0151e943fb 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include static const struct { @@ -22,9 +24,9 @@ static const struct { const std::string titleAddText; } network_styles[] = { {"main", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, - {"test", QAPP_APP_NAME_TESTNET, 190, 20, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, + {"test", QAPP_APP_NAME_TESTNET, 190, 20}, {"devnet", QAPP_APP_NAME_DEVNET, 190, 20, "[devnet: %s]"}, - {"regtest", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"} + {"regtest", QAPP_APP_NAME_REGTEST, 160, 30} }; void NetworkStyle::rotateColor(QColor& col, const int iconColorHueShift, const int iconColorSaturationReduction) @@ -86,8 +88,9 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, splashImage = QPixmap(":/images/splash"); } -const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) +const NetworkStyle* NetworkStyle::instantiate(const std::string& networkId) { + std::string titleAddText = networkId == CBaseChainParams::MAIN ? "" : strprintf("[%s]", networkId); for (const auto& network_style : network_styles) { if (networkId == network_style.networkId) @@ -95,7 +98,7 @@ const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) std::string appName = network_style.appName; std::string titleAddText = network_style.titleAddText; - if (networkId == QString(CBaseChainParams::DEVNET.c_str())) { + if (networkId == CBaseChainParams::DEVNET.c_str()) { appName = strprintf(appName, gArgs.GetDevNetName()); titleAddText = strprintf(titleAddText, gArgs.GetDevNetName()); } diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h index 96f76a420d13..a01964cc2aa4 100644 --- a/src/qt/networkstyle.h +++ b/src/qt/networkstyle.h @@ -15,7 +15,7 @@ class NetworkStyle { public: /** Get style associated with provided network id, or 0 if not known */ - static const NetworkStyle *instantiate(const QString &networkId); + static const NetworkStyle* instantiate(const std::string& networkId); const QString &getAppName() const { return appName; } const QIcon &getAppIcon() const { return appIcon; } diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index d4c4f3874974..e2fdf0c49e07 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -73,7 +73,7 @@ void AppTests::appTests() GUIUtil::loadFonts(); m_app.createOptionsModel(true /* reset settings */); QScopedPointer style( - NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + NetworkStyle::instantiate(Params().NetworkIDString())); m_app.createWindow(style.data()); connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests); expectCallback("guiTests"); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 6eae5901551d..550d8b861cd2 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1135,7 +1135,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup) // Results file is formatted like: // // || - BOOST_CHECK_EQUAL(out_sha_hex, "f8cff01ad967dfc82cf71208aa2b60f01a0aa621c28356af5ca91d1d7370c217"); + BOOST_CHECK_EQUAL(out_sha_hex, "1cd2697d1665d086f15ed18b3333bc356c3d39ba490589dc58afd8fc2f457731"); } BOOST_AUTO_TEST_CASE(util_ReadWriteSettings) diff --git a/src/util/system.cpp b/src/util/system.cpp index 59bf0b14434b..2c3d9c59b3a3 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -976,10 +976,11 @@ std::string ArgsManager::GetChainName() const const bool fRegTest = get_net("-regtest"); const bool fTestNet = get_net("-testnet"); const bool fDevNet = get_net("-devnet", false); + const bool is_chain_arg_set = IsArgSet("-chain"); - int nameParamsCount = (fRegTest ? 1 : 0) + (fDevNet ? 1 : 0) + (fTestNet ? 1 : 0); + int nameParamsCount = (fRegTest ? 1 : 0) + (fDevNet ? 1 : 0) + (fTestNet ? 1 : 0) + (is_chain_arg_set ? 1 : 0); if (nameParamsCount > 1) - throw std::runtime_error("Only one of -regtest, -testnet or -devnet can be used."); + throw std::runtime_error("Only one of -regtest, -testnet, -devnet or -chain can be used."); if (fDevNet) return CBaseChainParams::DEVNET; @@ -987,7 +988,7 @@ std::string ArgsManager::GetChainName() const return CBaseChainParams::REGTEST; if (fTestNet) return CBaseChainParams::TESTNET; - return CBaseChainParams::MAIN; + return GetArg("-chain", CBaseChainParams::MAIN); } std::string ArgsManager::GetDevNetName() const From 6ea934964a74fda7ef8fb9dca1125ca348ae9b57 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 12 Sep 2019 14:59:58 +0200 Subject: [PATCH 03/13] Merge #16714: gui: add prune to intro screen with smart default 9924bce317b96ab0c57efb99330abd11b6f16b9a [gui] intro: enable pruning by default unless disk is big (Sjors Provoost) c8de347a9d6c88fe67d77aba6fcce1b7fd66791c [gui] intro: add prune preference (Sjors Provoost) 1bbc49d2078ee53488e214d00eb47462687b05c5 [gui] intro: inform caller if intro was shown (Sjors Provoost) 1957103786f97135f35ababc97efa1b481865eb0 [gui] add explicit prune setter (Sjors Provoost) 1bccf6a52d7fc08d8f605cfb2edc3277ec299c72 [node] add forceSetArg to interface (Sjors Provoost) Pull request description: This adds a checkbox to the intro screen to enable pruning from the get go. If the user has plenty of space, it's unchecked by default: big If the user has insufficient space it's checked by default: low When the user has barely enough space and is likely to need pruning in the near future, this is shown in yellow and we also check the prune box: medium The cut-off for this 10 GB above `m_assumed_blockchain_size` (`=240` in `chainparams.cpp`). If the user launches the first time with `-prune=...` then we disable the check box and display the correct size (rounded to GB): Schermafbeelding 2019-08-24 om 20 23 14 The 2 GB default matches the settings default. The user can't change it in the intro screen, but can change it later. I'm tempted to increase that default to 10 GB, and then have the intro screen reduce it if space is really tight. Tips for testing: * move your existing data dir elsewhere * wipe data dir at every restart (behavior is different if it exists) * launch with `bitcoin-qt -resetguisettings -lang=en` (there's some space issues in different languages) * fake your free space by changing `intro.cpp` line 90: `freeBytesAvailable = 5000000000; // 5 GB` * try both testnet and mainnet, because settings are seperate. In particular note how step 7 in `GuiMain` switches where `QTSettings settings` points to; this had me thoroughly confused on testnet, because I was setting them too early. ACKs for top commit: jonasschnelli: Tested ACK 9924bce317b96ab0c57efb99330abd11b6f16b9a ryanofsky: utACK 9924bce317b96ab0c57efb99330abd11b6f16b9a. The changes are very logical, and implement the feature in a clean that way that doesn't add a lot of complication and shouldn't interfere with future improvements. I looked at Luke's branch too, and I think there's also a lot of great stuff there that seems fully compatible with this change. Tree-SHA512: 9523961451c53aebd347716976bc3a4a398f989dc21e9bbbd357060bd11a8f46c435f068bd421bb31ccb08e55445ef67bc347d8d19a4fb8fde9d6d3f9a3bcbb0 --- src/interfaces/node.h | 3 +++ src/node/interfaces.cpp | 1 + src/qt/bitcoin.cpp | 15 +++++++++++++-- src/qt/bitcoin.h | 2 ++ src/qt/forms/intro.ui | 10 ++++++++++ src/qt/intro.cpp | 18 +++++++++++++++++- src/qt/intro.h | 3 ++- src/qt/optionsmodel.cpp | 22 +++++++++++++++++----- src/qt/optionsmodel.h | 3 +++ 9 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 8aee777821d4..1b8f0e81c223 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -125,6 +125,9 @@ class Node //! Set command line arguments. virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0; + //! Set a command line argument + virtual void forceSetArg(const std::string& arg, const std::string& value) = 0; + //! Set a command line argument if it doesn't already have a value virtual bool softSetArg(const std::string& arg, const std::string& value) = 0; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e821709e7fc5..27e86c6d6860 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -198,6 +198,7 @@ class NodeImpl : public Node return gArgs.ParseParameters(argc, argv, error); } bool readConfigFiles(std::string& error) override { return gArgs.ReadConfigFiles(error, true); } + void forceSetArg(const std::string& arg, const std::string& value) override { gArgs.ForceSetArg(arg, value); } bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); } bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); } void selectParams(const std::string& network) override { SelectParams(network); } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 835cd9c41711..19fa42dd66a2 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -298,6 +298,10 @@ void BitcoinApplication::parameterSetup() m_node.initParameterInteraction(); } +void BitcoinApplication::SetPrune(bool prune, bool force) { + optionsModel->SetPrune(prune, force); +} + void BitcoinApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; @@ -517,8 +521,10 @@ int GuiMain(int argc, char* argv[]) /// 5. Now that settings and translations are available, ask user for data directory // User language is set up: pick a data directory - if (!Intro::pickDataDirectory(*node)) - return EXIT_SUCCESS; + bool did_show_intro = false; + bool prune = false; // Intro dialog prune check box + // Gracefully exit if the user cancels + if (!Intro::showIfNeeded(*node, did_show_intro, prune)) return EXIT_SUCCESS; /// 6. Determine availability of data directory and parse dash.conf /// - Do not call GetDataDir(true) before this step finishes @@ -688,6 +694,11 @@ int GuiMain(int argc, char* argv[]) "Warning: UI debug mode (-debug-ui) enabled" + QString(gArgs.IsArgSet("-custom-css-dir") ? "." : " without a custom css directory set with -custom-css-dir.")); } + if (did_show_intro) { + // Store intro dialog settings other than datadir (network specific) + app.SetPrune(prune, true); + } + if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false)) app.createSplashScreen(networkStyle.data()); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 82f1535a477b..cd4f88bd560c 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -65,6 +65,8 @@ class BitcoinApplication: public QApplication void parameterSetup(); /// Create options model void createOptionsModel(bool resetSettings); + /// Update prune value + void SetPrune(bool prune, bool force = false); /// Create main window void createWindow(const NetworkStyle *networkStyle); /// Create splash screen diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui index 91d4553ce70f..659e2c8b23db 100644 --- a/src/qt/forms/intro.ui +++ b/src/qt/forms/intro.ui @@ -210,6 +210,16 @@ + + + + Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features. + + + + + + diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 6794abce5c39..cfaac609a0a3 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -132,6 +132,11 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME)); uint64_t pruneTarget = std::max(0, gArgs.GetArg("-prune", 0)); + if (pruneTarget > 1) { // -prune=1 means enabled, above that it's a size in MB + ui->prune->setChecked(true); + ui->prune->setEnabled(false); + } + ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : 2)); requiredSpace = m_blockchain_size; QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); if (pruneTarget) { @@ -182,8 +187,10 @@ void Intro::setDataDirectory(const QString &dataDir) } } -bool Intro::pickDataDirectory(interfaces::Node& node) +bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune) { + did_show_intro = false; + QSettings settings; /* If data directory provided on command line, no need to look at settings or show a picking dialog */ @@ -211,6 +218,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node) GUIUtil::loadStyleSheet(true); intro.setDataDirectory(dataDirDefaultCurrent); intro.setWindowIcon(QIcon(":icons/dash")); + did_show_intro = true; while(true) { @@ -233,6 +241,9 @@ bool Intro::pickDataDirectory(interfaces::Node& node) } } + // Additional preferences: + prune = intro.ui->prune->isChecked(); + settings.setValue("strDataDir", dataDir); settings.setValue("strDataDirDefault", dataDirDefaultCurrent); settings.setValue("fReset", false); @@ -270,6 +281,11 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable { freeString += " " + tr("(of %1 GB needed)").arg(requiredSpace); ui->freeSpace->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); + ui->prune->setChecked(true); + } else if (bytesAvailable / GB_BYTES - requiredSpace < 10) { + freeString += " " + tr("(%1 GB needed for full chain)").arg(requiredSpace); + ui->freeSpace->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); + ui->prune->setChecked(true); } else { ui->freeSpace->setStyleSheet(""); } diff --git a/src/qt/intro.h b/src/qt/intro.h index 9e178b7a3ae8..e1514ab0c18c 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -39,6 +39,7 @@ class Intro : public QDialog /** * Determine data directory. Let the user choose if the current one doesn't exist. + * Let the user configure additional preferences such as pruning. * * @returns true if a data directory was selected, false if the user cancelled the selection * dialog. @@ -46,7 +47,7 @@ class Intro : public QDialog * @note do NOT call global GetDataDir() before calling this function, this * will cause the wrong path to be cached. */ - static bool pickDataDirectory(interfaces::Node& node); + static bool showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune); Q_SIGNALS: void requestCheck(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 24413017cb25..d5b81909731e 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -186,11 +186,7 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("bPrune", false); if (!settings.contains("nPruneSize")) settings.setValue("nPruneSize", 2); - // Convert prune size from GB to MiB: - const uint64_t nPruneSizeMiB = (settings.value("nPruneSize").toInt() * GB_BYTES) >> 20; - if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? ToString(nPruneSizeMiB) : "0")) { - addOverriddenOption("-prune"); - } + SetPrune(settings.value("bPrune").toBool()); // If GUI is setting prune, then we also must set disablegovernance and txindex if (settings.value("bPrune").toBool()) { @@ -377,6 +373,22 @@ static const QString GetDefaultProxyAddress() return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT); } +void OptionsModel::SetPrune(bool prune, bool force) +{ + QSettings settings; + settings.setValue("bPrune", prune); + // Convert prune size from GB to MiB: + const uint64_t nPruneSizeMiB = (settings.value("nPruneSize").toInt() * GB_BYTES) >> 20; + std::string prune_val = prune ? std::to_string(nPruneSizeMiB) : "0"; + if (force) { + m_node.forceSetArg("-prune", prune_val); + return; + } + if (!m_node.softSetArg("-prune", prune_val)) { + addOverriddenOption("-prune"); + } +} + // read QSettings values and return them QVariant OptionsModel::data(const QModelIndex & index, int role) const { diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 5d105106d011..dfc8724d3830 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -94,6 +94,9 @@ class OptionsModel : public QAbstractListModel const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } void emitCoinJoinEnabledChanged(); + /* Explicit setters */ + void SetPrune(bool prune, bool force = false); + /* Restart flag helper */ void setRestartRequired(bool fRequired); bool isRestartRequired() const; From e75d5b73660a840a9a177b2183e2c035fdd8c954 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 8 Jan 2020 22:03:32 +0800 Subject: [PATCH 04/13] Merge #17696: qt: Force set nPruneSize in QSettings after the intro dialog af112ab62895b145660f4cd7ff842e9cfea2a530 qt: Rename SetPrune() to InitializePruneSetting() (Hennadii Stepanov) b0bfbe50282877a1eee87118902901a280d6656d refactor: Drop `bool force' parameter (Hennadii Stepanov) 68c9bbe9bc91f882404556998666b1b5acea60e4 qt: Force set nPruneSize in QSettings after intro (Hennadii Stepanov) a82bd8fa5708c16d1db3edc4e82d70788eb5af19 util: Replace magics with DEFAULT_PRUNE_TARGET_GB (Hennadii Stepanov) Pull request description: On master (5622d8f3156a293e61d0964c33d4b21d8c9fd5e0), having `QSettings` set already ``` $ grep nPruneSize ~/.config/Bitcoin/Bitcoin-Qt-testnet.conf nPruneSize=6 ``` enabling prune option in the intro dialog ``` $ ./src/qt/bitcoin-qt -choosedatadir -testnet ``` ![DeepinScreenshot_select-area_20191208120425](https://user-images.githubusercontent.com/32963518/70388183-eed68580-19b6-11ea-9aa1-f9ad9aaa68a6.png) has no effect: ``` $ grep Prune ~/.bitcoin/testnet3/debug.log 2019-12-08T10:04:41Z Prune configured to target 5722 MiB on disk for block and undo files. ``` --- With this PR: ``` $ grep Prune ~/.bitcoin/testnet3/debug.log 2019-12-08T10:20:35Z Prune configured to target 1907 MiB on disk for block and undo files. ``` This PR has been split of #17453 (the first two commits) as it fixes an orthogonal bug. Refs: - https://github.com/bitcoin/bitcoin/pull/17453#discussion_r345424240 - https://github.com/bitcoin/bitcoin/pull/17453#discussion_r350960201 ACKs for top commit: Sjors: Code review re-ACK af112ab62895b145660f4cd7ff842e9cfea2a530 ryanofsky: Code review ACK af112ab62895b145660f4cd7ff842e9cfea2a530. Just suggested changes since last review (thanks!) promag: Tested ACK af112ab62895b145660f4cd7ff842e9cfea2a530. Latest suggestions and changes look good to me. Tree-SHA512: 8ddad34b30dcc2cdcad6678ba8a0b36fa176e4e3465862ef6eee9be0f98d8146705138c9c7995dd8c0990af41078ca743fef1a90ed9240081f052f32ddec72b9 --- src/qt/bitcoin.cpp | 9 ++++++--- src/qt/bitcoin.h | 4 ++-- src/qt/guiconstants.h | 3 +++ src/qt/intro.cpp | 2 +- src/qt/optionsmodel.cpp | 16 +++++++++++++--- src/qt/optionsmodel.h | 3 ++- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 19fa42dd66a2..ec700cb23656 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -298,8 +298,11 @@ void BitcoinApplication::parameterSetup() m_node.initParameterInteraction(); } -void BitcoinApplication::SetPrune(bool prune, bool force) { - optionsModel->SetPrune(prune, force); +void BitcoinApplication::InitializePruneSetting(bool prune) +{ + // If prune is set, intentionally override existing prune size with + // the default size since this is called when choosing a new datadir. + optionsModel->SetPruneTargetGB(prune ? DEFAULT_PRUNE_TARGET_GB : 0, true); } void BitcoinApplication::requestInitialize() @@ -696,7 +699,7 @@ int GuiMain(int argc, char* argv[]) if (did_show_intro) { // Store intro dialog settings other than datadir (network specific) - app.SetPrune(prune, true); + app.InitializePruneSetting(prune); } if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false)) diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index cd4f88bd560c..78a5e419a11b 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -65,8 +65,8 @@ class BitcoinApplication: public QApplication void parameterSetup(); /// Create options model void createOptionsModel(bool resetSettings); - /// Update prune value - void SetPrune(bool prune, bool force = false); + /// Initialize prune setting + void InitializePruneSetting(bool prune); /// Create main window void createWindow(const NetworkStyle *networkStyle); /// Create splash screen diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 4e5b8db3bb57..0b03d80eb1e6 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -47,4 +47,7 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80; /* One gigabyte (GB) in bytes */ static constexpr uint64_t GB_BYTES{1000000000}; +// Default prune target displayed in GUI. +static constexpr int DEFAULT_PRUNE_TARGET_GB{2}; + #endif // BITCOIN_QT_GUICONSTANTS_H diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index cfaac609a0a3..928bc9d6a7ac 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -136,7 +136,7 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz ui->prune->setChecked(true); ui->prune->setEnabled(false); } - ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : 2)); + ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : DEFAULT_PRUNE_TARGET_GB)); requiredSpace = m_blockchain_size; QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); if (pruneTarget) { diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index d5b81909731e..b175ced9b592 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -185,8 +185,8 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("bPrune")) settings.setValue("bPrune", false); if (!settings.contains("nPruneSize")) - settings.setValue("nPruneSize", 2); - SetPrune(settings.value("bPrune").toBool()); + settings.setValue("nPruneSize", DEFAULT_PRUNE_TARGET_GB); + SetPruneEnabled(settings.value("bPrune").toBool()); // If GUI is setting prune, then we also must set disablegovernance and txindex if (settings.value("bPrune").toBool()) { @@ -373,7 +373,7 @@ static const QString GetDefaultProxyAddress() return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT); } -void OptionsModel::SetPrune(bool prune, bool force) +void OptionsModel::SetPruneEnabled(bool prune, bool force) { QSettings settings; settings.setValue("bPrune", prune); @@ -389,6 +389,16 @@ void OptionsModel::SetPrune(bool prune, bool force) } } +void OptionsModel::SetPruneTargetGB(int prune_target_gb, bool force) +{ + const bool prune = prune_target_gb > 0; + if (prune) { + QSettings settings; + settings.setValue("nPruneSize", prune_target_gb); + } + SetPruneEnabled(prune, force); +} + // read QSettings values and return them QVariant OptionsModel::data(const QModelIndex & index, int role) const { diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index dfc8724d3830..6fe838da4e45 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -95,7 +95,8 @@ class OptionsModel : public QAbstractListModel void emitCoinJoinEnabledChanged(); /* Explicit setters */ - void SetPrune(bool prune, bool force = false); + void SetPruneEnabled(bool prune, bool force = false); + void SetPruneTargetGB(int prune_target_gb, bool force = false); /* Restart flag helper */ void setRestartRequired(bool fRequired); From 78e475a70a795455feda64e8a994f8bd7c96b49d Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 27 Jan 2020 18:15:32 +0100 Subject: [PATCH 05/13] Merge #17453: gui: Fix intro dialog labels when the prune button is toggled 4f7127d1e3a51f0f55d42a08439c516dcc8d1a26 gui: Make Intro consistent with prune checkbox (Hennadii Stepanov) 4824a7d36cf47e766865e0fefe952ec860eb82dd gui: Add Intro::UpdateFreeSpaceLabel() (Hennadii Stepanov) daa3f3fa9071a229275dd6a1b8445237ddc3fa97 refactor: Add Intro::UpdatePruneLabels() (Hennadii Stepanov) e4caa82a03df5c6a6d5d29f34ab006d732c6dac1 refactor: Replace static variable with data member (Hennadii Stepanov) 2bede28cd9ec638d8bb32c187ccf12d89345218e util: Add PruneGBtoMiB() function (Hennadii Stepanov) e35e4b2ba052c9a533626286026dbe0a2d546c5b util: Add PruneMiBtoGB() function (Hennadii Stepanov) Pull request description: On master (a6f6333ba253cda83221ee529810cacf930e413f) and on 0.19.0.1 the intro dialog with prune enabled (checkbox "Discard blocks..." is checked) provides a user with wrong info about the required disk space: ![DeepinScreenshot_bitcoin-qt_20191208112228](https://user-images.githubusercontent.com/32963518/70387510-8daab400-19ae-11ea-9338-29add9c31118.png) Also the paragraph "If you have chosen to limit..." is missed. --- With this PR when prune checkbox is toggled, the related text labels and the amount of required space shown are updated (previously they were only updated when the data directory was updated): ![Screenshot from 2019-12-08 11-34-53](https://user-images.githubusercontent.com/32963518/70387542-eed28780-19ae-11ea-9565-49d8a64b2f33.png) --- This PR is an alternative to #17035. **ryanofsky**'s [suggestion](https://github.com/bitcoin/bitcoin/pull/17035#discussion_r337594268) also has been implemented. ACKs for top commit: emilengler: ACK 4f7127d1e3a51f0f55d42a08439c516dcc8d1a26 Sjors: tACK 4f7127d1e3a51f0f55d42a08439c516dcc8d1a26 ryanofsky: Code review ACK 4f7127d1e3a51f0f55d42a08439c516dcc8d1a26. It seems like there are a few visible changes here: jonasschnelli: utACK 4f7127d1e3a51f0f55d42a08439c516dcc8d1a26 Tree-SHA512: fa0bbdcfafde97d7906cda066cbd4608b936a71cae1b4cda3ee3aa2eed3a9795f279f14c6b1b4997278e094db891c7d3bb695368ba0882347aa42165a86e5172 --- src/qt/intro.cpp | 102 +++++++++++++++++++++++----------------- src/qt/intro.h | 12 +++-- src/qt/optionsmodel.cpp | 5 +- src/qt/optionsmodel.h | 11 +++++ 4 files changed, 82 insertions(+), 48 deletions(-) diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 928bc9d6a7ac..e84a614f77f2 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -23,9 +24,6 @@ #include -/* Total required space (in GB) depending on user choice (prune, not prune) */ -static uint64_t requiredSpace; - /* Check free space asynchronously to prevent hanging the UI thread. Up to one request to check a path is in flight to this thread; when the check() @@ -110,14 +108,24 @@ void FreespaceChecker::check() Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); } +namespace { +//! Return pruning size that will be used if automatic pruning is enabled. +int GetPruneTargetGB() +{ + int64_t prune_target_mib = gArgs.GetArg("-prune", 0); + // >1 means automatic pruning is enabled by config, 1 means manual pruning, 0 means no pruning. + return prune_target_mib > 1 ? PruneMiBtoGB(prune_target_mib) : DEFAULT_PRUNE_TARGET_GB; +} +} // namespace -Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_size) : +Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_size_gb) : QDialog(parent), ui(new Ui::Intro), thread(nullptr), signalled(false), - m_blockchain_size(blockchain_size), - m_chain_state_size(chain_state_size) + m_blockchain_size_gb(blockchain_size_gb), + m_chain_state_size_gb(chain_state_size_gb), + m_prune_target_gb{GetPruneTargetGB()} { ui->setupUi(this); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME)); @@ -125,37 +133,24 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz ui->lblExplanation1->setText(ui->lblExplanation1->text() .arg(PACKAGE_NAME) - .arg(m_blockchain_size) + .arg(m_blockchain_size_gb) .arg(2014) .arg("Dash") ); ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME)); - uint64_t pruneTarget = std::max(0, gArgs.GetArg("-prune", 0)); - if (pruneTarget > 1) { // -prune=1 means enabled, above that it's a size in MB + if (gArgs.GetArg("-prune", 0) > 1) { // -prune=1 means enabled, above that it's a size in MiB ui->prune->setChecked(true); ui->prune->setEnabled(false); } - ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : DEFAULT_PRUNE_TARGET_GB)); - requiredSpace = m_blockchain_size; - QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); - if (pruneTarget) { - uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); - if (prunedGBs <= requiredSpace) { - requiredSpace = prunedGBs; - storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory."); - } - ui->lblExplanation3->setVisible(true); - } else { - ui->lblExplanation3->setVisible(false); - } - requiredSpace += m_chain_state_size; - ui->sizeWarningLabel->setText( - tr("%1 will download and store a copy of the Dash block chain.").arg(PACKAGE_NAME) + " " + - storageRequiresMsg.arg(requiredSpace) + " " + - tr("The wallet will also be stored in this directory.") - ); - this->adjustSize(); + ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(m_prune_target_gb)); + UpdatePruneLabels(ui->prune->isChecked()); + + connect(ui->prune, &QCheckBox::toggled, [this](bool prune_checked) { + UpdatePruneLabels(prune_checked); + UpdateFreeSpaceLabel(); + }); + startThread(); } @@ -276,25 +271,31 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable { ui->freeSpace->setText(""); } else { - QString freeString = tr("%1 GB of free space available").arg(bytesAvailable/GB_BYTES); - if(bytesAvailable < requiredSpace * GB_BYTES) - { - freeString += " " + tr("(of %1 GB needed)").arg(requiredSpace); - ui->freeSpace->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); - ui->prune->setChecked(true); - } else if (bytesAvailable / GB_BYTES - requiredSpace < 10) { - freeString += " " + tr("(%1 GB needed for full chain)").arg(requiredSpace); - ui->freeSpace->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); - ui->prune->setChecked(true); - } else { - ui->freeSpace->setStyleSheet(""); + m_bytes_available = bytesAvailable; + if (ui->prune->isEnabled()) { + ui->prune->setChecked(m_bytes_available < (m_blockchain_size_gb + m_chain_state_size_gb + 10) * GB_BYTES); } - ui->freeSpace->setText(freeString + "."); + UpdateFreeSpaceLabel(); } /* Don't allow confirm in ERROR state */ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR); } +void Intro::UpdateFreeSpaceLabel() +{ + QString freeString = tr("%n GB of free space available", "", m_bytes_available / GB_BYTES); + if (m_bytes_available < m_required_space_gb * GB_BYTES) { + freeString += " " + tr("(of %n GB needed)", "", m_required_space_gb); + ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); + } else if (m_bytes_available / GB_BYTES - m_required_space_gb < 10) { + freeString += " " + tr("(%n GB needed for full chain)", "", m_required_space_gb); + ui->freeSpace->setStyleSheet("QLabel { color: #999900 }"); + } else { + ui->freeSpace->setStyleSheet(""); + } + ui->freeSpace->setText(freeString + "."); +} + void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) { /* Disable OK button until check result comes in */ @@ -355,3 +356,20 @@ QString Intro::getPathToCheck() mutex.unlock(); return retval; } + +void Intro::UpdatePruneLabels(bool prune_checked) +{ + m_required_space_gb = m_blockchain_size_gb + m_chain_state_size_gb; + QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); + if (prune_checked && m_prune_target_gb <= m_blockchain_size_gb) { + m_required_space_gb = m_prune_target_gb + m_chain_state_size_gb; + storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory."); + } + ui->lblExplanation3->setVisible(prune_checked); + ui->sizeWarningLabel->setText( + tr("%1 will download and store a copy of the Dash block chain.").arg(PACKAGE_NAME) + " " + + storageRequiresMsg.arg(m_required_space_gb) + " " + + tr("The wallet will also be stored in this directory.") + ); + this->adjustSize(); +} diff --git a/src/qt/intro.h b/src/qt/intro.h index e1514ab0c18c..30f941598758 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -31,7 +31,7 @@ class Intro : public QDialog public: explicit Intro(QWidget *parent = nullptr, - uint64_t blockchain_size = 0, uint64_t chain_state_size = 0); + int64_t blockchain_size_gb = 0, int64_t chain_state_size_gb = 0); ~Intro(); QString getDataDirectory(); @@ -67,12 +67,18 @@ private Q_SLOTS: QMutex mutex; bool signalled; QString pathToCheck; - uint64_t m_blockchain_size; - uint64_t m_chain_state_size; + const int64_t m_blockchain_size_gb; + const int64_t m_chain_state_size_gb; + //! Total required space (in GB) depending on user choice (prune or not prune). + int64_t m_required_space_gb{0}; + uint64_t m_bytes_available{0}; + const int64_t m_prune_target_gb; void startThread(); void checkPath(const QString &dataDir); QString getPathToCheck(); + void UpdatePruneLabels(bool prune_checked); + void UpdateFreeSpaceLabel(); friend class FreespaceChecker; }; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index b175ced9b592..6911dadbd5ab 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -377,9 +377,8 @@ void OptionsModel::SetPruneEnabled(bool prune, bool force) { QSettings settings; settings.setValue("bPrune", prune); - // Convert prune size from GB to MiB: - const uint64_t nPruneSizeMiB = (settings.value("nPruneSize").toInt() * GB_BYTES) >> 20; - std::string prune_val = prune ? std::to_string(nPruneSizeMiB) : "0"; + const int64_t prune_target_mib = PruneGBtoMiB(settings.value("nPruneSize").toInt()); + std::string prune_val = prune ? ToString(prune_target_mib) : "0"; if (force) { m_node.forceSetArg("-prune", prune_val); return; diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 6fe838da4e45..ac334a4df252 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_OPTIONSMODEL_H #include +#include #include @@ -18,6 +19,16 @@ class Node; extern const char *DEFAULT_GUI_PROXY_HOST; static constexpr uint16_t DEFAULT_GUI_PROXY_PORT = 9050; +/** + * Convert configured prune target MiB to displayed GB. Round up to avoid underestimating max disk usage. + */ +static inline int PruneMiBtoGB(int64_t mib) { return (mib * 1024 * 1024 + GB_BYTES - 1) / GB_BYTES; } + +/** + * Convert displayed prune target GB to configured MiB. Round down so roundtrip GB -> MiB -> GB conversion is stable. + */ +static inline int64_t PruneGBtoMiB(int gb) { return gb * GB_BYTES / 1024 / 1024; } + /** Interface from Qt to configuration data structure for Bitcoin client. To Qt, the options are presented as a list with the different options laid out vertically. From d4bc451492b362242b151a85364d48788abd02e8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 13 Sep 2019 15:15:15 +0200 Subject: [PATCH 06/13] Merge #15584: build: disable BIP70 support by default BIP70 is removed in "merge #17165: Remove BIP70 support (#4023)". So, this commit contains only some follow-ups to unify codebase e09913f1c47e693b0c6fafef55b9ca78e5f3abc0 doc: specify protobuf as optional in build docs (fanquake) 376f4929f8f75011b72b2f9c3164980db482278a build: disable BIP70 support by default (fanquake) Pull request description: Disable BIP70 support in the GUI by default for `0.19.0` (for eventual removal in `0.20.0`?). Users who want to compile with BIP70 support enabled can pass `--enable-bip70` to `./configure`. I've inverted the current `--disable-bip70` test to instead pass `--enable-bip70`. Tested configurations on `macOS` (`protobuf` installed with `brew`). Protobuf available and `./configure`: ``` Options used to compile and link: with wallet = yes with gui / qt = yes with bip70 = no ``` Protobuf available and `./configure --enable-bip70`: ``` Options used to compile and link: with wallet = yes with gui / qt = yes with bip70 = yes ``` Protobuf not available (i.e `brew unlink protobuf`) and `./configure`: ``` Options used to compile and link: with wallet = yes with gui / qt = yes with bip70 = no ``` Protobuf not available and `./configure --enable-bip70`: ``` checking whether to build test_bitcoin-qt... yes checking whether to build BIP70 support... configure: error: protobuf missing ``` TODO: - [x] Remove `protobuf` from other Travis builds - [ ] Documentation updates (mention that `protobuf` is now optional)? - [ ] Could split release notes into GUI and build ACKs for top commit: laanwj: ACK e09913f1c47e693b0c6fafef55b9ca78e5f3abc0 elichai: ACK e09913f1c47e693b0c6fafef55b9ca78e5f3abc0 Read the autotools changes. awesome that this removes the protobuf requirement. practicalswift: ACK e09913f1c47e693b0c6fafef55b9ca78e5f3abc0 -- diff looks correct Tree-SHA512: 7bf87ae8555e24db2da2e89cc4d4e90d09be27499ad386ad65879d05df8f96d9a1384379891ac8963d17728c90e55961560813df97e849e631e2de8c08e210c8 --- .travis.yml | 4 ++-- ci/test/00_setup_env_mac_host.sh | 2 +- ci/test/00_setup_env_native_cxx20.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dcf8dd202748..ddbc148d0b27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -232,7 +232,7 @@ after_success: FILE_ENV="./ci/test/00_setup_env_win64.sh" - stage: test - name: '32-bit + dash [GOAL: install] [GUI: no BIP70]' + name: '32-bit + dash [GOAL: install] [GUI]' env: >- FILE_ENV="./ci/test/00_setup_env_i686.sh" @@ -276,7 +276,7 @@ after_success: FILE_ENV="./ci/test/00_setup_env_mac.sh" - stage: test - name: 'macOS 10.14 native [GOAL: install] [GUI: BIP70 enabled] [no depends]' + name: 'macOS 10.14 native [GOAL: install] [GUI] [no depends]' os: osx # Use the most recent version: # Xcode 11, macOS 10.14, JDK 12.0.1 diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh index 33a4da5bcfd4..7779a34e7f69 100755 --- a/ci/test/00_setup_env_mac_host.sh +++ b/ci/test/00_setup_env_mac_host.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-apple-darwin19 -export BREW_PACKAGES="automake berkeley-db4 libtool boost miniupnpc pkg-config protobuf qt qrencode python3 ccache zeromq" +export BREW_PACKAGES="automake berkeley-db4 libtool boost miniupnpc pkg-config qt qrencode python3 ccache zeromq" export PIP_PACKAGES="zmq" export RUN_CI_ON_HOST=true export RUN_UNIT_TESTS=true diff --git a/ci/test/00_setup_env_native_cxx20.sh b/ci/test/00_setup_env_native_cxx20.sh index ca89949270eb..c17fd1e42e27 100755 --- a/ci/test/00_setup_env_native_cxx20.sh +++ b/ci/test/00_setup_env_native_cxx20.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" +export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev" export DEP_OPTS="NO_UPNP=1 DEBUG=1" export CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG -DARENA_DEBUG" export PYZMQ=true From 3e0160b85ed3de14648c74ec3f4c099c1c07a81e Mon Sep 17 00:00:00 2001 From: fanquake Date: Sat, 23 May 2020 18:23:53 +0800 Subject: [PATCH 07/13] Merge #19058: doc: Drop protobuf stuff ea9fcfd1305f92a7c3ca4d3c05951ceba1b6b05b doc: Drop protobuf stuff (Hennadii Stepanov) Pull request description: This is a follow-up to #17165. ACKs for top commit: fanquake: ACK ea9fcfd1305f92a7c3ca4d3c05951ceba1b6b05b - clicked the links and they seem to work. Tree-SHA512: 0861bbac3a3ff781a413e15f5ed02c624bc15d572a001a53cd2fb9f7683456175f69e9d666b72f260abbb5114b67cefca9fada4d179c62384c90479534ae63d5 --- doc/productivity.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/productivity.md b/doc/productivity.md index 7997eca073a8..aa949a0ea2c1 100644 --- a/doc/productivity.md +++ b/doc/productivity.md @@ -12,7 +12,7 @@ Table of Contents * [Multiple working directories with `git worktrees`](#multiple-working-directories-with-git-worktrees) * [Interactive "dummy rebases" for fixups and execs with `git merge-base`](#interactive-dummy-rebases-for-fixups-and-execs-with-git-merge-base) * [Writing code](#writing-code) - * [Format C/C++/Protobuf diffs with `clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy) + * [Format C/C++ diffs with `clang-format-diff.py`](#format-cc-diffs-with-clang-format-diffpy) * [Format Python diffs with `yapf-diff.py`](#format-python-diffs-with-yapf-diffpy) * [Rebasing/Merging code](#rebasingmerging-code) * [More conflict context with `merge.conflictstyle diff3`](#more-conflict-context-with-mergeconflictstyle-diff3) @@ -119,13 +119,13 @@ You can also set up [upstream refspecs](#reference-prs-easily-with-refspecs) to Writing code ------------ -### Format C/C++/Protobuf diffs with `clang-format-diff.py` +### Format C/C++ diffs with `clang-format-diff.py` See [contrib/devtools/README.md](/contrib/devtools/README.md#clang-format-diff.py). ### Format Python diffs with `yapf-diff.py` -Usage is exactly the same as [`clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy). You can get it [here](https://github.com/MarcoFalke/yapf-diff). +Usage is exactly the same as [`clang-format-diff.py`](#format-cc-diffs-with-clang-format-diffpy). You can get it [here](https://github.com/MarcoFalke/yapf-diff). Rebasing/Merging code ------------- From dc5da97e0517f675b5b1066c1e802ae2cc536973 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 24 Sep 2019 10:58:58 +0200 Subject: [PATCH 08/13] Merge #16941: travis: Disable feature_block in tsan run due to OOM faa079db92e614bddfe8bd323ddcd2adb77e0961 travis: Disable feature_block in tsan run (MarcoFalke) Pull request description: The `feature_block` test causes the travis machine to OOM, when run with the thread sanitizer. The stderr says: ``` ==27237==ERROR: ThreadSanitizer failed to allocate 0xf6000 (1007616) bytes of LargeMmapAllocator (error code: 12) ... FATAL: ThreadSanitizer CHECK failed: /build/llvm-toolchain-3.8-_PD09B/llvm-toolchain-3.8-3.8/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:183 "((0 && "unable to mmap")) != (0)" (0x0, 0x0) ERROR: Failed to mmap ``` (from https://travis-ci.org/bitcoin/bitcoin/jobs/588194563#L10505) Fix this by disabling `feature_block` on travis. Longer term, I'd like to move away from travis, but I'll leave this for a follow-up. ACKs for top commit: fanquake: ACK faa079db92e614bddfe8bd323ddcd2adb77e0961 Tree-SHA512: c0dc2272853aac53f68eb9e110c8500c4a92211ba89d856660bacdf6e959d875477e422b3280b743d85fc8a65e083bf9153911f12039d026e2501f426540dac4 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ddbc148d0b27..de92303e5555 100644 --- a/.travis.yml +++ b/.travis.yml @@ -250,6 +250,7 @@ after_success: name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs, sanitizers: thread (TSan), no wallet]' env: >- FILE_ENV="./ci/test/00_setup_env_native_tsan.sh" + TEST_RUNNER_EXTRA="--exclude feature_block" # Not enough memory on travis machines # x86_64 Linux (no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer) - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]' From 2307f977840ea8537e53c1ccbdfdcad26dde7ff8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 30 Sep 2019 15:32:11 +0200 Subject: [PATCH 09/13] Merge #16991: qa: Fix service flag comparison check in rpc_net test (luke-jr) 9c23ebd6b18fb1058a8d3e8aae9e0595d3a57ad5 qa: Fix service flag comparison check in rpc_net test (Luke Dashjr) Pull request description: Rebase of #16936 ACKs for top commit: darosior: ACK 9c23ebd6b18fb1058a8d3e8aae9e0595d3a57ad5 Tree-SHA512: 74f287740403da1040ab1e235ef6eba4e304f3ee5d57a3b25d1e2e1f2f982d256528d398a4d6cb24ba393798e680a8f46cd7dae54ed84ab2c747e96288f1f884 --- test/functional/rpc_net.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 953681adee01..12752e52a08e 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -17,13 +17,11 @@ wait_until, ) from test_framework.mininode import P2PInterface +import test_framework.messages from test_framework.messages import ( CAddress, msg_addr, NODE_NETWORK, - NODE_GETUTXO,NODE_BLOOM, - NODE_NETWORK_LIMITED, - NODE_HEADERS_COMPRESSED, ) @@ -34,16 +32,10 @@ def assert_net_servicesnames(servicesflag, servicenames): :param servicesflag: The services as an integer. :param servicenames: The list of decoded services names, as strings. """ - if servicesflag & NODE_NETWORK: - assert "NETWORK" in servicenames - if servicesflag & NODE_GETUTXO: - assert "GETUTXO" in servicenames - if servicesflag & NODE_BLOOM: - assert "BLOOM" in servicenames - if servicesflag & NODE_NETWORK_LIMITED: - assert "NETWORK_LIMITED" in servicenames - if servicesflag & NODE_HEADERS_COMPRESSED: - assert "HEADERS_COMPRESSED" in servicenames + servicesflag_generated = 0 + for servicename in servicenames: + servicesflag_generated |= getattr(test_framework.messages, 'NODE_' + servicename) + assert servicesflag_generated == servicesflag class NetTest(DashTestFramework): @@ -126,7 +118,7 @@ def _test_getnetworkinfo(self): # check the `servicesnames` field network_info = [node.getnetworkinfo() for node in self.nodes] for info in network_info: - assert_net_servicesnames(int(info["localservices"], 16), info["localservicesnames"]) + assert_net_servicesnames(int(info["localservices"], 0x10), info["localservicesnames"]) self.log.info('Test extended connections info') self.connect_nodes(1, 2) @@ -166,7 +158,7 @@ def _test_getpeerinfo(self): assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr']) # check the `servicesnames` field for info in peer_info: - assert_net_servicesnames(int(info[0]["services"], 16), info[0]["servicesnames"]) + assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) def test_service_flags(self): self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63)) From 3e1c8a6a589e63591be1e028926eaf3966f6a90f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 24 Apr 2019 10:08:26 -0400 Subject: [PATCH 10/13] Merge #16465: test: Test p2sh-witness and bech32 in wallet_import_rescan fa3c6575cac5e3841797980fe60b8368ae579dba lint: Add false positive to python dead code linter (MarcoFalke) fa25668e1c8982548f1c6f94780709c625811469 test: Test p2sh-witness and bech32 in wallet_import_rescan (MarcoFalke) fa79af298917d501cee26370fdf9d44d05133d15 test: Replace fragile "rng" with call to random() (MarcoFalke) fac3dcf7d052586548f2100a0d576618a85741f9 test: Generate one block for each send in wallet_import_rescan (MarcoFalke) Pull request description: This adds test coverage for segwit in the `wallet_import_rescan` test, among other cleanups. ACKs for top commit: jnewbery: ACK fa3c6575cac5e3841797980fe60b8368ae579dba Tree-SHA512: 877741763c62c1bf9d868864a1e3f0699857e8c028e9fcd65c7eeb73600c22cbe97b7b51093737743d9e87bcb991c1fe1086f673e18765aef0fcfe27951402f0 --- test/functional/wallet_import_rescan.py | 57 ++++++++++++++++--------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 550646fa7c31..7015a61dcdd3 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -26,8 +26,10 @@ ) import collections +from decimal import Decimal import enum import itertools +import random Call = enum.Enum("Call", "single multiaddress multiscript") Data = enum.Enum("Data", "address pub priv") @@ -50,7 +52,7 @@ def do_import(self, timestamp): assert_equal(response, None) elif self.call in (Call.multiaddress, Call.multiscript): - response = self.node.importmulti([{ + request = { "scriptPubKey": { "address": self.address["address"] } if self.call == Call.multiaddress else self.address["scriptPubKey"], @@ -59,13 +61,18 @@ def do_import(self, timestamp): "keys": [self.key] if self.data == Data.priv else [], "label": self.label, "watchonly": self.data != Data.priv - }], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}) + } + response = self.node.importmulti( + requests=[request], + options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}, + ) assert_equal(response, [{"success": True}]) - def check(self, txid=None, amount=None, confirmations=None): + def check(self, txid=None, amount=None, confirmation_height=None): """Verify that listtransactions/listreceivedbyaddress return expected values.""" txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True) + current_height = self.node.getblockcount() assert_equal(len(txs), self.expected_txs) addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address']) @@ -80,13 +87,13 @@ def check(self, txid=None, amount=None, confirmations=None): assert_equal(tx["category"], "receive") assert_equal(tx["label"], self.label) assert_equal(tx["txid"], txid) - assert_equal(tx["confirmations"], confirmations) + assert_equal(tx["confirmations"], 1 + current_height - confirmation_height) assert_equal("trusted" not in tx, True) address, = [ad for ad in addresses if txid in ad["txids"]] assert_equal(address["address"], self.address["address"]) assert_equal(address["amount"], self.expected_balance) - assert_equal(address["confirmations"], confirmations) + assert_equal(address["confirmations"], 1 + current_height - confirmation_height) # Verify the transaction is correctly marked watchonly depending on # whether the transaction pays to an imported public key or # imported private key. The test setup ensures that transaction @@ -114,6 +121,13 @@ def check(self, txid=None, amount=None, confirmations=None): # Rescans start at the earliest block up to 2 hours before the key timestamp. TIMESTAMP_WINDOW = 2 * 60 * 60 +AMOUNT_DUST = 0.00000546 + + +def get_rand_amount(): + r = random.uniform(AMOUNT_DUST, 1) + return Decimal(str(round(r, 8))) + class ImportRescanTest(BitcoinTestFramework): def set_test_params(self): @@ -125,13 +139,13 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() def setup_network(self): - extra_args = [[] for _ in range(self.num_nodes)] + self.extra_args = [[] for _ in range(self.num_nodes)] for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: # txindex is enabled by default in Dash and needs to be disabled for import-rescan.py - extra_args[i] += ["-prune=1", "-txindex=0", "-reindex"] + self.extra_args[i] += ["-prune=1", "-txindex=0", "-reindex"] - self.add_nodes(self.num_nodes, extra_args=extra_args) + self.add_nodes(self.num_nodes, extra_args=self.extra_args) # Import keys with pruning disabled self.start_nodes(extra_args=[[]] * self.num_nodes) @@ -149,15 +163,18 @@ def run_test(self): variant.label = "label {} {}".format(i, variant) variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label)) variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) - variant.initial_amount = 1 - (i + 1) / 64 + variant.initial_amount = get_rand_amount() variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount) + self.nodes[0].generate(1) # Generate one block for each send + variant.confirmation_height = self.nodes[0].getblockcount() + variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] - # Generate a block containing the initial transactions, then another - # block further in the future (past the rescan window). - self.nodes[0].generate(1) + # Generate a block further in the future (past the rescan window). assert_equal(self.nodes[0].getrawmempool(), []) - timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] - set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1) + set_node_times( + self.nodes, + self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + TIMESTAMP_WINDOW + 1, + ) self.nodes[0].generate(1) self.sync_all() @@ -167,11 +184,11 @@ def run_test(self): self.log.info('Run import for variant {}'.format(variant)) expect_rescan = variant.rescan == Rescan.yes variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))] - variant.do_import(timestamp) + variant.do_import(variant.timestamp) if expect_rescan: variant.expected_balance = variant.initial_amount variant.expected_txs = 1 - variant.check(variant.initial_txid, variant.initial_amount, 2) + variant.check(variant.initial_txid, variant.initial_amount, variant.confirmation_height) else: variant.expected_balance = 0 variant.expected_txs = 0 @@ -179,11 +196,11 @@ def run_test(self): # Create new transactions sending to each address. for i, variant in enumerate(IMPORT_VARIANTS): - variant.sent_amount = 1 - (2 * i + 1) / 128 + variant.sent_amount = get_rand_amount() variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount) + self.nodes[0].generate(1) # Generate one block for each send + variant.confirmation_height = self.nodes[0].getblockcount() - # Generate a block containing the new transactions. - self.nodes[0].generate(1) assert_equal(self.nodes[0].getrawmempool(), []) self.sync_all() @@ -192,7 +209,7 @@ def run_test(self): self.log.info('Run check for variant {}'.format(variant)) variant.expected_balance += variant.sent_amount variant.expected_txs += 1 - variant.check(variant.sent_txid, variant.sent_amount, 1) + variant.check(variant.sent_txid, variant.sent_amount, variant.confirmation_height) for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: self.stop_node(i, expected_stderr='Warning: You are starting with governance validation disabled. This is expected because you are running a pruned node.') From 6ad9bdf722c35b91e7b97d2dd4805031e127e67c Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 15 Aug 2019 16:02:02 -0400 Subject: [PATCH 11/13] Merge #16060: Bury bip9 deployments e78aaf41f43d0e2ad78fa6d8dad61032c8ef73d0 [docs] Add release notes for burying bip 9 soft fork deployments (John Newbery) 8319e738f9f118025b332e4fa804d4c31e4113f4 [tests] Add coverage for the content of getblockchaininfo.softforks (James O'Beirne) 0328dcdcfcb56dc8918697716d7686be048ad0b3 [Consensus] Bury segwit deployment (John Newbery) 1c93b9b31c2ab7358f9d55f52dd46340397c906d [Consensus] Bury CSV deployment height (John Newbery) 3862e473f0cb71a762c0306b171b591341d58142 [rpc] Tidy up reporting of buried and ongoing softforks (John Newbery) Pull request description: This hardcodes CSV and segwit activation heights, similar to the BIP 90 buried deployments for BIPs 34, 65 and 66. CSV and segwit have been active for over 18 months. Hardcoding the activation height is a code simplification, makes it easier to understand segwit activation status, and reduces technical debt. This was originally attempted by jl2012 in #11398 and again by me in #12360. ACKs for top commit: ajtowns: ACK e78aaf41f43d0e2ad78fa6d8dad61032c8ef73d0 ; checked diff to previous acked commit, checked tests still work ariard: ACK e78aaf4, check diff, run the tests again and successfully activated csv/segwit heights on mainnet as expected. MarcoFalke: ACK e78aaf41f43d0e2ad78fa6d8dad61032c8ef73d0 (still didn't check if the mainnet block heights are correct, but the code looks good now) Tree-SHA512: 7e951829106e21a81725f7d3e236eddbb59349189740907bb47e33f5dbf95c43753ac1231f47ae7bee85c8c81b2146afcdfdc11deb1503947f23093a9c399912 --- doc/release-notes-16060.md | 15 ++ src/chainparams.cpp | 28 +--- src/consensus/params.h | 3 +- src/rpc/blockchain.cpp | 126 +++++++------- src/validation.cpp | 12 +- src/versionbitsinfo.cpp | 5 - test/functional/feature_bip68_sequence.py | 16 +- test/functional/feature_cltv.py | 17 +- test/functional/feature_csv_activation.py | 103 ++++-------- test/functional/feature_dersig.py | 17 +- test/functional/feature_dip0020_activation.py | 6 +- .../feature_dip3_deterministicmns.py | 8 +- .../feature_llmq_is_cl_conflicts.py | 8 +- .../feature_new_quorum_type_activation.py | 11 +- test/functional/rpc_blockchain.py | 155 +++++++++++++++++- .../test_framework/test_framework.py | 5 +- test/functional/test_framework/util.py | 10 +- 17 files changed, 321 insertions(+), 224 deletions(-) create mode 100644 doc/release-notes-16060.md diff --git a/doc/release-notes-16060.md b/doc/release-notes-16060.md new file mode 100644 index 000000000000..7fdf9daf90ef --- /dev/null +++ b/doc/release-notes-16060.md @@ -0,0 +1,15 @@ +Low-level RPC changes +---------------------- + +- Soft fork reporting in the `getblockchaininfo` return object has been + updated. For full details, see the RPC help text. In summary: + - The `bip9_softforks` sub-object is no longer returned + - The `softforks` sub-object now returns an object keyed by soft fork name, + rather than an array + - Each softfork object in the `softforks` object contains a `type` value which + is either `buried` (for soft fork deployments where the activation height is + hard-coded into the client implementation), or `bip9` (for soft fork deployments + where activation is controlled by BIP 9 signaling). + +- `getblocktemplate` no longer returns a `rules` array containing `CSV` + (the BIP 9 deployments that are currently in active state). diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 35874b5c8970..373ca4f15b54 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -156,6 +156,7 @@ class CMainParams : public CChainParams { consensus.BIP34Hash = uint256S("0x000001f35e70f7c5705f64c6c5cc3dea9449e74d5b5c7cf74dad1bcca14a8012"); consensus.BIP65Height = 619382; // 00000000000076d8fcea02ec0963de4abfd01e771fec0863f960c2c64fe6f357 consensus.BIP66Height = 245817; // 00000000000b1fa2dfa312863570e13fae9ca7b5566cb27e55422620b469aefa + consensus.CSVHeight = 622944; // 00000000000002e3d3a6224cfce80bae367fd3283d1e5a8ba50e5e60b2d2905d consensus.DIP0001Height = 782208; consensus.DIP0003Height = 1028160; consensus.DIP0003EnforcementHeight = 1047200; @@ -176,11 +177,6 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of BIP68, BIP112, and BIP113. - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1486252800; // Feb 5th, 2017 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517788800; // Feb 5th, 2018 - // Deployment of DIP0001 consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1508025600; // Oct 15th, 2017 @@ -404,6 +400,7 @@ class CTestNetParams : public CChainParams { consensus.BIP34Hash = uint256S("0x000008ebb1db2598e897d17275285767717c6acfeac4c73def49fbea1ddcbcb6"); consensus.BIP65Height = 2431; // 0000039cf01242c7f921dcb4806a5994bc003b48c1973ae0c89b67809c2bb2ab consensus.BIP66Height = 2075; // 0000002acdd29a14583540cb72e1c5cc83783560e38fa7081495d474fe1671f7 + consensus.CSVHeight = 8064; // 00000005eb94d027e34649373669191188858a22c70f4a6d29105e559124cec7 consensus.DIP0001Height = 5500; consensus.DIP0003Height = 7000; consensus.DIP0003EnforcementHeight = 7300; @@ -424,11 +421,6 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of BIP68, BIP112, and BIP113. - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1544655600; // Dec 13th, 2018 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL; - // Deployment of DIP0001 consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1544655600; // Dec 13th, 2018 @@ -625,6 +617,7 @@ class CDevNetParams : public CChainParams { consensus.BIP34Height = 1; // BIP34 activated immediately on devnet consensus.BIP65Height = 1; // BIP65 activated immediately on devnet consensus.BIP66Height = 1; // BIP66 activated immediately on devnet + consensus.CSVHeight = 1; // BIP68 activated immediately on devnet consensus.DIP0001Height = 2; // DIP0001 activated immediately on devnet consensus.DIP0003Height = 2; // DIP0003 activated immediately on devnet consensus.DIP0003EnforcementHeight = 2; // DIP0003 activated immediately on devnet @@ -645,11 +638,6 @@ class CDevNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of BIP68, BIP112, and BIP113. - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1506556800; // September 28th, 2017 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL; - // Deployment of DIP0001 consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1505692800; // Sep 18th, 2017 @@ -917,6 +905,7 @@ class CRegTestParams : public CChainParams { consensus.BIP34Hash = uint256(); consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests) consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests) + consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests) consensus.DIP0001Height = 2000; consensus.DIP0003Height = 432; consensus.DIP0003EnforcementHeight = 500; @@ -936,9 +925,6 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 999999999999ULL; @@ -1009,7 +995,7 @@ class CRegTestParams : public CChainParams { m_assumed_blockchain_size = 0; m_assumed_chain_state_size = 0; - UpdateVersionBitsParametersFromArgs(args); + UpdateActivationParametersFromArgs(args); UpdateDIP3ParametersFromArgs(args); UpdateDIP8ParametersFromArgs(args); UpdateBudgetParametersFromArgs(args); @@ -1105,7 +1091,7 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[d].nFalloffCoeff = nFalloffCoeff; } } - void UpdateVersionBitsParametersFromArgs(const ArgsManager& args); + void UpdateActivationParametersFromArgs(const ArgsManager& args); /** * Allows modifying the DIP3 activation and enforcement height @@ -1171,7 +1157,7 @@ class CRegTestParams : public CChainParams { void UpdateLLMQInstantSendDIP0024FromArgs(const ArgsManager& args); }; -void CRegTestParams::UpdateVersionBitsParametersFromArgs(const ArgsManager& args) +void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args) { if (!args.IsArgSet("-vbparams")) return; diff --git a/src/consensus/params.h b/src/consensus/params.h index d9f238ea823e..7277920fcddf 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -15,7 +15,6 @@ namespace Consensus { enum DeploymentPos { DEPLOYMENT_TESTDUMMY, - DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. DEPLOYMENT_DIP0001, // Deployment of DIP0001 and lower transaction fees. DEPLOYMENT_BIP147, // Deployment of BIP147 (NULLDUMMY) DEPLOYMENT_DIP0003, // Deployment of DIP0002 and DIP0003 (txv3 and deterministic MN lists) @@ -78,6 +77,8 @@ struct Params { int BIP65Height; /** Block height at which BIP66 becomes active */ int BIP66Height; + /** Block height at which CSV (BIP68, BIP112 and BIP113) becomes active */ + int CSVHeight; /** Block height at which DIP0001 becomes active */ int DIP0001Height; /** Block height at which DIP0003 becomes active */ diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 732e89066ed8..a0cb4c2ae539 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1418,54 +1418,49 @@ static UniValue verifychain(const JSONRPCRequest& request) ::ChainstateActive(), Params(), ::ChainstateActive().CoinsTip(), *node_context.evodb, check_level, check_depth); } -/** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) +static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - UniValue rv(UniValue::VOBJ); - bool activated = false; - switch(version) - { - case 2: - activated = pindex->nHeight >= consensusParams.BIP34Height; - break; - case 3: - activated = pindex->nHeight >= consensusParams.BIP66Height; - break; - case 4: - activated = pindex->nHeight >= consensusParams.BIP65Height; - break; - } - rv.pushKV("status", activated); - return rv; -} + // For buried deployments. + // A buried deployment is one where the height of the activation has been hardcoded into + // the client implementation long after the consensus change has activated. See BIP 90. + // Buried deployments with activation height value of + // std::numeric_limits::max() are disabled and thus hidden. + if (height == std::numeric_limits::max()) return; -static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) -{ UniValue rv(UniValue::VOBJ); - rv.pushKV("id", name); - rv.pushKV("version", version); - rv.pushKV("reject", SoftForkMajorityDesc(version, pindex, consensusParams)); - return rv; + rv.pushKV("type", "buried"); + // getblockchaininfo reports the softfork as active from when the chain height is + // one below the activation height + rv.pushKV("active", ::ChainActive().Tip()->nHeight + 1 >= height); + rv.pushKV("height", height); + softforks.pushKV(name, rv); } -static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - UniValue rv(UniValue::VOBJ); + // For BIP9 deployments. + // Deployments (e.g. testdummy) with timeout value before Jan 1, 2009 are hidden. + // A timeout value of 0 guarantees a softfork will never be activated. + // This is used when merging logic to implement a proposed softfork without a specified deployment schedule. + if (consensusParams.vDeployments[id].nTimeout <= 1230768000) return; + + UniValue bip9(UniValue::VOBJ); const ThresholdState thresholdState = VersionBitsState(::ChainActive().Tip(), consensusParams, id, versionbitscache); switch (thresholdState) { - case ThresholdState::DEFINED: rv.pushKV("status", "defined"); break; - case ThresholdState::STARTED: rv.pushKV("status", "started"); break; - case ThresholdState::LOCKED_IN: rv.pushKV("status", "locked_in"); break; - case ThresholdState::ACTIVE: rv.pushKV("status", "active"); break; - case ThresholdState::FAILED: rv.pushKV("status", "failed"); break; + case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break; + case ThresholdState::STARTED: bip9.pushKV("status", "started"); break; + case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break; + case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break; + case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break; } if (ThresholdState::STARTED == thresholdState) { - rv.pushKV("bit", consensusParams.vDeployments[id].bit); + bip9.pushKV("bit", consensusParams.vDeployments[id].bit); } - rv.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); - rv.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); - rv.pushKV("since", VersionBitsStateSinceHeight(::ChainActive().Tip(), consensusParams, id, versionbitscache)); + bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); + bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); + int64_t since_height = VersionBitsStateSinceHeight(::ChainActive().Tip(), consensusParams, id, versionbitscache); + bip9.pushKV("since", since_height); if (ThresholdState::STARTED == thresholdState) { UniValue statsUV(UniValue::VOBJ); @@ -1475,18 +1470,18 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse statsUV.pushKV("elapsed", statsStruct.elapsed); statsUV.pushKV("count", statsStruct.count); statsUV.pushKV("possible", statsStruct.possible); - rv.pushKV("statistics", statsUV); + bip9.pushKV("statistics", statsUV); } - return rv; -} -static void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) -{ - // Deployments with timeout value of 0 are hidden. - // A timeout value of 0 guarantees a softfork will never be activated. - // This is used when softfork codes are merged without specifying the deployment schedule. - if (consensusParams.vDeployments[id].nTimeout > 0) - bip9_softforks.pushKV(VersionBitsDeploymentInfo[id].name, BIP9SoftForkDesc(consensusParams, id)); + UniValue rv(UniValue::VOBJ); + rv.pushKV("type", "bip9"); + rv.pushKV("bip9", bip9); + if (ThresholdState::ACTIVE == thresholdState) { + rv.pushKV("height", since_height); + } + rv.pushKV("active", ThresholdState::ACTIVE == thresholdState); + + softforks.pushKV(name, rv); } UniValue getblockchaininfo(const JSONRPCRequest& request) @@ -1512,28 +1507,17 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) {RPCResult::Type::NUM, "pruneheight", "lowest-height complete block stored (only present if pruning is enabled)"}, {RPCResult::Type::BOOL, "automatic_pruning", "whether automatic pruning is enabled (only present if pruning is enabled)"}, {RPCResult::Type::NUM, "prune_target_size", "the target size used by pruning (only present if automatic pruning is enabled)"}, - {RPCResult::Type::ARR, "softforks", "status of softforks in progress", - { - {RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR, "xxxx", "name of the softfork"}, - {RPCResult::Type::STR, "version", "block version"}, - {RPCResult::Type::OBJ, "reject", "progress toward rejecting pre-softfork blocks", - { - {RPCResult::Type::BOOL, "status", "true if threshold reached"}, - }}, - }}, - }}, - {RPCResult::Type::OBJ_DYN, "bip9_softforks", "status of BIP9 softforks in progress", + {RPCResult::Type::OBJ, "softforks", "status of softforks in progress", { - {RPCResult::Type::OBJ, "xxxx", "name of the softfork", + {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, + {RPCResult::Type::OBJ, "bip9", "status of bip9 softforks (only for \"bip9\" type)", { {RPCResult::Type::STR, "status", "one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\""}, {RPCResult::Type::NUM, "bit", "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)"}, {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, - {RPCResult::Type::OBJ, "statistics", "numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)", + {RPCResult::Type::OBJ, "statistics", "numeric statistics about BIP9 signalling for a softfork", { {RPCResult::Type::NUM, "period", "the length in blocks of the BIP9 signalling period"}, {RPCResult::Type::NUM, "threshold", "the number of blocks with the version bit set required to activate the feature"}, @@ -1542,6 +1526,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) {RPCResult::Type::BOOL, "possible", "returns false if there are not enough blocks left in this period to pass activation threshold"}, }}, }}, + {RPCResult::Type::NUM, "height", "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, + {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, }}, {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"}, }}, @@ -1586,17 +1572,17 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) } const Consensus::Params& consensusParams = Params().GetConsensus(); - UniValue softforks(UniValue::VARR); - UniValue bip9_softforks(UniValue::VOBJ); + UniValue softforks(UniValue::VOBJ); // sorted by activation block - softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); - softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); - softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); - for (int pos = Consensus::DEPLOYMENT_CSV; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) { - BIP9SoftForkDescPushBack(bip9_softforks, consensusParams, static_cast(pos)); - } + BuriedForkDescPushBack(softforks,"bip34", consensusParams.BIP34Height); + BuriedForkDescPushBack(softforks,"bip66", consensusParams.BIP66Height); + BuriedForkDescPushBack(softforks,"bip65", consensusParams.BIP65Height); + BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight); + for (int pos = Consensus::DEPLOYMENT_TESTDUMMY + 1; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) { + BIP9SoftForkDescPushBack(softforks, VersionBitsDeploymentInfo[pos].name, consensusParams, static_cast(pos)); + } + BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); obj.pushKV("softforks", softforks); - obj.pushKV("bip9_softforks", bip9_softforks); obj.pushKV("warnings", GetWarnings(false)); return obj; diff --git a/src/validation.cpp b/src/validation.cpp index 5c2bcc3d2415..f48f81cb9c2b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2040,8 +2040,8 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } - // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. - if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { + // Start enforcing BIP112 (CHECKSEQUENCEVERIFY) + if (pindex->nHeight >= consensusparams.CSVHeight) { flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } @@ -2224,9 +2224,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, } /// END DASH - // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. + // Start enforcing BIP68 (sequence locks) int nLockTimeFlags = 0; - if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { + if (pindex->nHeight >= chainparams.GetConsensus().CSVHeight) { nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; } @@ -3976,9 +3976,9 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat AssertLockHeld(cs_main); const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; - // Start enforcing BIP113 (Median Time Past) using versionbits logic. + // Start enforcing BIP113 (Median Time Past). int nLockTimeFlags = 0; - if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { + if (nHeight >= consensusParams.CSVHeight) { assert(pindexPrev != nullptr); nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; } diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp index c2a3d1c15a3b..1daea3af5a90 100644 --- a/src/versionbitsinfo.cpp +++ b/src/versionbitsinfo.cpp @@ -12,11 +12,6 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.gbt_force =*/ true, /*.check_mn_protocol =*/ false, }, - { - /*.name =*/ "csv", - /*.gbt_force =*/ true, - /*.check_mn_protocol =*/ false, - }, { /*.name =*/ "dip0001", /*.gbt_force =*/ true, diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index faf5843b2d5e..cc2972b0618f 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -11,8 +11,8 @@ assert_equal, assert_greater_than, assert_raises_rpc_error, - get_bip9_status, - satoshi_round + satoshi_round, + softfork_active, ) from test_framework.script_util import DUMMY_P2SH_SCRIPT @@ -50,7 +50,7 @@ def run_test(self): self.log.info("Running test sequence-lock-unconfirmed-inputs") self.test_sequence_lock_unconfirmed_inputs() - self.log.info("Running test BIP68 not consensus before versionbits activation") + self.log.info("Running test BIP68 not consensus before activation") self.test_bip68_not_consensus() self.log.info("Activating BIP68 (and 112/113)") @@ -334,12 +334,12 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock): self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) self.nodes[0].generate(10) - # Make sure that BIP68 isn't being used to validate blocks, prior to - # versionbits activation. If more blocks are mined prior to this test + # Make sure that BIP68 isn't being used to validate blocks prior to + # activation height. If more blocks are mined prior to this test # being run, then it's possible the test has activated the soft fork, and # this test should be moved to run earlier, or deleted. def test_bip68_not_consensus(self): - assert get_bip9_status(self.nodes[0], 'csv')['status'] != 'active' + assert not softfork_active(self.nodes[0], 'csv') txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) @@ -388,9 +388,9 @@ def activateCSV(self): height = self.nodes[0].getblockcount() assert_greater_than(min_activation_height - height, 2) self.nodes[0].generate(min_activation_height - height - 2) - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in") + assert not softfork_active(self.nodes[0], 'csv') self.nodes[0].generate(1) - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active") + assert softfork_active(self.nodes[0], 'csv') self.sync_blocks() # Use self.nodes[1] to test that version 2 transactions are standard. diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 971cd6ecf591..82969347fb08 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -65,14 +65,11 @@ def set_test_params(self): self.rpc_timeout = 120 def test_cltv_info(self, *, is_active): - assert_equal( - next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip65'), + assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], { - "id": "bip65", - "version": 4, - "reject": { - "status": is_active - } + "active": is_active, + "height": CLTV_HEIGHT, + "type": "buried", }, ) @@ -103,9 +100,9 @@ def run_test(self): block.hashMerkleRoot = block.calc_merkle_root() block.solve() - self.test_cltv_info(is_active=False) + self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules self.nodes[0].p2p.send_and_ping(msg_block(block)) - self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules + self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules assert_equal(self.nodes[0].getbestblockhash(), block.hash) self.log.info("Test that blocks must now be at least version 4") @@ -151,7 +148,7 @@ def run_test(self): block.hashMerkleRoot = block.calc_merkle_root() block.solve() - self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules + self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules self.nodes[0].p2p.send_and_ping(msg_block(block)) self.test_cltv_info(is_active=True) # Active as of current tip assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 04d5e7d30f01..57ac50d11f38 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -2,23 +2,17 @@ # Copyright (c) 2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test activation of the first version bits soft fork. +"""Test CSV soft fork activation. This soft fork will activate the following BIPS: BIP 68 - nSequence relative lock times BIP 112 - CHECKSEQUENCEVERIFY BIP 113 - MedianTimePast semantics for nLockTime -regtest lock-in with 108/144 block signalling -activation after a further 144 blocks - mine 82 blocks whose coinbases will be used to generate inputs for our tests -mine 61 blocks to transition from DEFINED to STARTED -mine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period -mine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN -mine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572 -mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered -mine 1 block and test that enforcement has triggered (which triggers ACTIVE) +mine 345 blocks and seed block chain with the 82 inputs will use for our tests at height 427 +mine 2 blocks and verify soft fork not yet activated +mine 1 block and test that soft fork is activated (rules enforced for next block) Test BIP 113 is enforced Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height Mine 1 block so next height is 581 and test BIP 68 now passes time but not height @@ -58,13 +52,14 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - get_bip9_status, hex_str_to_bytes, + softfork_active, ) TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above) COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs BASE_RELATIVE_LOCKTIME = 10 +CSV_ACTIVATION_HEIGHT = 432 SEQ_DISABLE_FLAG = 1 << 31 SEQ_RANDOM_HIGH_BIT = 1 << 25 SEQ_TYPE_FLAG = 1 << 22 @@ -168,20 +163,19 @@ def setup_network(self): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - def generate_blocks(self, number, version, test_blocks=None): - if test_blocks is None: - test_blocks = [] + def generate_blocks(self, number): + test_blocks = [] for i in range(number): - block = self.create_test_block([], version) + block = self.create_test_block([]) test_blocks.append(block) self.last_block_time += 600 self.tip = block.sha256 self.tipheight += 1 return test_blocks - def create_test_block(self, txs, version=536870912): + def create_test_block(self, txs): block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600) - block.nVersion = version + block.nVersion = 4 block.vtx.extend(txs) block.hashMerkleRoot = block.calc_merkle_root() block.rehash() @@ -207,50 +201,15 @@ def run_test(self): self.tip = int(self.nodes[0].getbestblockhash(), 16) self.nodeaddress = self.nodes[0].getnewaddress() - # TODO: uncomment the code below when bitcoin#16060 is backported, - # should go right below `# Activation height is hardcoded` line - # # We advance to block height five below BIP112 activation for the following tests - # test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT-5 - COINBASE_BLOCK_COUNT) - - self.log.info("Test that the csv softfork is DEFINED") - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') - test_blocks = self.generate_blocks(60, 4) - self.send_blocks(test_blocks) - - self.log.info("Advance from DEFINED to STARTED, height = 143") - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') - - self.log.info("Fail to achieve LOCKED_IN") - # 100 out of 144 signal bit 0. Use a variety of bits to simulate multiple parallel softforks - - test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) - test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) - test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) - test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) - self.send_blocks(test_blocks) - - self.log.info("Failed to advance past STARTED, height = 287") - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') - - self.log.info("Generate blocks to achieve LOCK-IN") - # 108 out of 144 signal bit 0 to achieve lock-in - # using a variety of bits to simulate multiple parallel softforks - test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) - test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) - test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) - test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) - self.send_blocks(test_blocks) - - self.log.info("Advanced from STARTED to LOCKED_IN, height = 431") - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') - - # Generate 140 more version 4 blocks - test_blocks = self.generate_blocks(140, 4) + # Activation height is hardcoded + test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT-5 - COINBASE_BLOCK_COUNT) + #test_blocks = self.generate_blocks(345) self.send_blocks(test_blocks) + assert not softfork_active(self.nodes[0], 'csv') - # Inputs at height = 572 + # Inputs at height = 431 # - # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) + # Put inputs for all tests in the chain at height 431 (tip now = 430) (time increases by 600s per block) # Note we reuse inputs for v1 and v2 txs so must test these separately # 16 normal inputs bip68inputs = [] @@ -282,7 +241,7 @@ def run_test(self): bip113input = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress) self.nodes[0].setmocktime(self.last_block_time + 600) - inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572 + inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 431 self.nodes[0].setmocktime(TIME_GENESIS_BLOCK + 600 * 1000 + 100) self.tip = int(inputblockhash, 16) self.tipheight += 1 @@ -290,11 +249,12 @@ def run_test(self): assert_equal(len(self.nodes[0].getblock(inputblockhash, True)["tx"]), TESTING_TX_COUNT + 1) # 2 more version 4 blocks - test_blocks = self.generate_blocks(2, 4) + test_blocks = self.generate_blocks(2) self.send_blocks(test_blocks) - self.log.info("Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575)") - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') + assert_equal(self.tipheight, CSV_ACTIVATION_HEIGHT - 2) + self.log.info("Height = {}, CSV not yet active (will activate for block {}, not {})".format(self.tipheight, CSV_ACTIVATION_HEIGHT, CSV_ACTIVATION_HEIGHT - 1)) + assert not softfork_active(self.nodes[0], 'csv') # Test both version 1 and version 2 transactions for all tests # BIP113 test transaction will be modified before each use to put in appropriate block time @@ -372,10 +332,11 @@ def run_test(self): self.send_blocks([self.create_test_block(success_txs)]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block - test_blocks = self.generate_blocks(1, 4) + # 1 more version 4 block to get us to height 432 so the fork should now be active for the next block + assert not softfork_active(self.nodes[0], 'csv') + test_blocks = self.generate_blocks(1) self.send_blocks(test_blocks) - assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') + assert softfork_active(self.nodes[0], 'csv') self.log.info("Post-Soft Fork Tests.") @@ -396,8 +357,8 @@ def run_test(self): self.send_blocks([self.create_test_block([bip113tx])]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - # Next block height = 580 after 4 blocks of random version - test_blocks = self.generate_blocks(4, 1234) + # Next block height = 437 after 4 blocks of random version + test_blocks = self.generate_blocks(4) self.send_blocks(test_blocks) self.log.info("BIP 68 tests") @@ -424,8 +385,8 @@ def run_test(self): for tx in bip68heighttxs: self.send_blocks([self.create_test_block([tx])], success=False, reject_reason='bad-txns-nonfinal') - # Advance one block to 581 - test_blocks = self.generate_blocks(1, 1234) + # Advance one block to 438 + test_blocks = self.generate_blocks(1) self.send_blocks(test_blocks) # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 @@ -435,8 +396,8 @@ def run_test(self): for tx in bip68heighttxs: self.send_blocks([self.create_test_block([tx])], success=False, reject_reason='bad-txns-nonfinal') - # Advance one block to 582 - test_blocks = self.generate_blocks(1, 1234) + # Advance one block to 439 + test_blocks = self.generate_blocks(1) self.send_blocks(test_blocks) # All BIP 68 txs should pass diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 5ab9dfbba761..740a208beebb 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -45,14 +45,11 @@ def set_test_params(self): self.rpc_timeout = 240 def test_dersig_info(self, *, is_active): - assert_equal( - next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip66'), + assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip66'], { - "id": "bip66", - "version": 3, - "reject": { - "status": is_active - } + "active": is_active, + "height": DERSIG_HEIGHT, + "type": "buried", }, ) @@ -84,9 +81,9 @@ def run_test(self): block.rehash() block.solve() - self.test_dersig_info(is_active=False) + self.test_dersig_info(is_active=False) # Not active as of current tip and next block does not need to obey rules self.nodes[0].p2p.send_and_ping(msg_block(block)) - self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules + self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules assert_equal(self.nodes[0].getbestblockhash(), block.hash) self.log.info("Test that blocks must now be at least version 3") @@ -131,7 +128,7 @@ def run_test(self): block.rehash() block.solve() - self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules + self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules self.nodes[0].p2p.send_and_ping(msg_block(block)) self.test_dersig_info(is_active=True) # Active as of current tip assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) diff --git a/test/functional/feature_dip0020_activation.py b/test/functional/feature_dip0020_activation.py index 471e4fdc667a..df3fcbd7b1c3 100755 --- a/test/functional/feature_dip0020_activation.py +++ b/test/functional/feature_dip0020_activation.py @@ -5,7 +5,7 @@ from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, ToHex from test_framework.script import CScript, OP_CAT, OP_DROP, OP_TRUE from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, get_bip9_status, satoshi_round +from test_framework.util import assert_equal, assert_raises_rpc_error, get_bip9_details, softfork_active, satoshi_round ''' feature_dip0020_activation.py @@ -55,12 +55,12 @@ def run_test(self): tx0_hex = ToHex(tx0) # This tx isn't valid yet - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'locked_in') + assert_equal(get_bip9_details(self.nodes[0], 'dip0020')['status'], 'locked_in') assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex) # Generate enough blocks to activate DIP0020 opcodes self.node.generate(98) - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'active') + assert softfork_active(self.nodes[0], 'dip0020') # Still need 1 more block for mempool to accept new opcodes assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex) diff --git a/test/functional/feature_dip3_deterministicmns.py b/test/functional/feature_dip3_deterministicmns.py index 570436a35719..9a39ab1040a5 100755 --- a/test/functional/feature_dip3_deterministicmns.py +++ b/test/functional/feature_dip3_deterministicmns.py @@ -12,7 +12,7 @@ from test_framework.blocktools import create_block, create_coinbase, get_masternode_payment from test_framework.messages import CCbTx, COIN, CTransaction, FromHex, ToHex, uint256_to_string from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, force_finish_mnsync, get_bip9_status, p2p_port +from test_framework.util import assert_equal, force_finish_mnsync, p2p_port class Masternode(object): pass @@ -390,10 +390,10 @@ def mine_block(self, node, vtx=None, miner_address=None, mn_payee=None, mn_amoun coinbasevalue += new_fees if mn_amount is None: - realloc_info = get_bip9_status(self.nodes[0], 'realloc') + realloc_info = node.getblockchaininfo()['softforks']['realloc'] realloc_height = 99999999 - if realloc_info['status'] == 'active': - realloc_height = realloc_info['since'] + if realloc_info['active']: + realloc_height = realloc_info['height'] mn_amount = get_masternode_payment(height, coinbasevalue, realloc_height) miner_amount = coinbasevalue - mn_amount diff --git a/test/functional/feature_llmq_is_cl_conflicts.py b/test/functional/feature_llmq_is_cl_conflicts.py index 9616cd32a2ba..dd3deaa9023e 100755 --- a/test/functional/feature_llmq_is_cl_conflicts.py +++ b/test/functional/feature_llmq_is_cl_conflicts.py @@ -18,7 +18,7 @@ from test_framework.messages import CCbTx, CInv, COIN, CTransaction, FromHex, hash256, msg_clsig, msg_inv, ser_string, ToHex, uint256_from_str, uint256_to_string from test_framework.mininode import P2PInterface from test_framework.test_framework import DashTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes, get_bip9_status, wait_until +from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes, wait_until class TestP2PConn(P2PInterface): @@ -308,10 +308,10 @@ def create_block(self, node, vtx=None): coinbasevalue -= bt_fees coinbasevalue += new_fees - realloc_info = get_bip9_status(self.nodes[0], 'realloc') + realloc_info = self.nodes[0].getblockchaininfo()['softforks']['realloc'] realloc_height = 99999999 - if realloc_info['status'] == 'active': - realloc_height = realloc_info['since'] + if realloc_info['active']: + realloc_height = realloc_info['height'] mn_amount = get_masternode_payment(height, coinbasevalue, realloc_height) miner_amount = coinbasevalue - mn_amount diff --git a/test/functional/feature_new_quorum_type_activation.py b/test/functional/feature_new_quorum_type_activation.py index d70aa78a4bef..fc42ad36b50c 100755 --- a/test/functional/feature_new_quorum_type_activation.py +++ b/test/functional/feature_new_quorum_type_activation.py @@ -3,7 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, get_bip9_status +from test_framework.util import assert_equal, get_bip9_details ''' feature_new_quorum_type_activation.py @@ -20,19 +20,20 @@ def set_test_params(self): self.extra_args = [["-vbparams=dip0020:0:999999999999:10:8:6:5"]] def run_test(self): - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'defined') + self.log.info(get_bip9_details(self.nodes[0], 'dip0020')) + assert_equal(get_bip9_details(self.nodes[0], 'dip0020')['status'], 'defined') self.nodes[0].generate(9) - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'started') + assert_equal(get_bip9_details(self.nodes[0], 'dip0020')['status'], 'started') ql = self.nodes[0].quorum("list") assert_equal(len(ql), 3) assert "llmq_test_v17" not in ql self.nodes[0].generate(10) - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'locked_in') + assert_equal(get_bip9_details(self.nodes[0], 'dip0020')['status'], 'locked_in') ql = self.nodes[0].quorum("list") assert_equal(len(ql), 3) assert "llmq_test_v17" not in ql self.nodes[0].generate(10) - assert_equal(get_bip9_status(self.nodes[0], 'dip0020')['status'], 'active') + assert_equal(get_bip9_details(self.nodes[0], 'dip0020')['status'], 'active') ql = self.nodes[0].quorum("list") assert_equal(len(ql), 4) assert "llmq_test_v17" in ql diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 0220069cb35d..a1a502fe0499 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -83,7 +83,6 @@ def _test_getblockchaininfo(self): keys = [ 'bestblockhash', - 'bip9_softforks', 'blocks', 'chain', 'chainwork', @@ -128,6 +127,160 @@ def _test_getblockchaininfo(self): assert res['automatic_pruning'] assert_equal(res['prune_target_size'], 576716800) assert_greater_than(res['size_on_disk'], 0) + { + 'testdummy': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 28, + 'start_time': 0, + 'timeout': 999999999999, + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True + } + }, + 'active': False} + } + assert_equal(res['softforks'], { + 'bip34': {'type': 'buried', 'active': False, 'height': 500}, + 'bip66': {'type': 'buried', 'active': False, 'height': 1251}, + 'bip65': {'type': 'buried', 'active': False, 'height': 1351}, + 'csv': {'type': 'buried', 'active': False, 'height': 432}, + 'dip0001': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 1, + 'start_time': 0, + 'timeout': 999999999999, + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True + }, + }, + 'active': False}, + 'bip147': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 2, + 'start_time': 0, + 'timeout': 999999999999, + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True + }, + }, + 'active': False}, + 'dip0003': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 3, + 'start_time': 0, + 'timeout': 999999999999, + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True + }, + }, + 'active': False}, + 'dip0008': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 4, + 'start_time': 0, + 'timeout': 999999999999, + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True + }, + }, + 'active': False}, + 'realloc': { + 'type': 'bip9', + 'bip9': { + 'status': 'defined', + 'start_time': 0, + 'timeout': 999999999999, + 'since': 0 + }, + 'active': False}, + 'dip0020': { + 'type': 'bip9', + 'bip9': { + 'status': 'locked_in', + 'start_time': 0, + 'timeout': 999999999999, + 'since': 200 + }, + 'active': False}, + 'dip0024': { + 'type': 'bip9', + 'bip9': { + 'status': 'defined', + 'start_time': 0, + 'timeout': 999999999999, + 'since': 0 + }, + 'active': False}, + 'v19': { + 'type': 'bip9', + 'bip9': { + 'status': 'defined', + 'start_time': 0, + 'timeout': 999999999999, + 'since': 0 + }, + 'active': False}, + 'v20': { + 'type': 'bip9', + 'bip9': { + 'status': 'defined', + 'start_time': 0, + 'timeout': 999999999999, + 'since': 0 + }, 'active': False}, + 'testdummy': { + 'type': 'bip9', + 'bip9': { + 'status': 'started', + 'bit': 28, + 'start_time': 0, + 'timeout': 999999999999, # testdummy does not have a timeout so is set to the max int64 value + 'since': 144, + 'statistics': { + 'period': 144, + 'threshold': 108, + 'elapsed': 57, + 'count': 57, + 'possible': True, + }, + }, + 'active': False}, + }) def _test_getchaintxstats(self): self.log.info("Test getchaintxstats") diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index c84c83f41f54..8741b59f0050 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -50,6 +50,7 @@ set_node_times, set_timeout_scale, satoshi_round, + softfork_active, wait_until, get_chain_folder, rpc_port, ) @@ -1046,9 +1047,9 @@ def activate_by_name(self, name, expected_activation_height=None): self.bump_mocktime(blocks_left) self.nodes[0].generate(blocks_left) self.sync_blocks() - assert self.nodes[0].getblockchaininfo()['bip9_softforks'][name]['status'] != 'active' + assert not softfork_active(self.nodes[0], name) - while self.nodes[0].getblockchaininfo()['bip9_softforks'][name]['status'] != 'active': + while not softfork_active(self.nodes[0], name): self.bump_mocktime(batch_size) self.nodes[0].generate(batch_size) self.sync_blocks() diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 43bdf366bae9..312d650644cd 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -430,9 +430,13 @@ def get_chain_folder(datadir, chain): pass return chain -def get_bip9_status(node, key): - info = node.getblockchaininfo() - return info['bip9_softforks'][key] +def get_bip9_details(node, key): + """Return extra info about bip9 softfork""" + return node.getblockchaininfo()['softforks'][key]['bip9'] + +def softfork_active(node, key): + """Return whether a softfork is active.""" + return node.getblockchaininfo()['softforks'][key]['active'] def set_node_times(nodes, t): for node in nodes: From d26b07a8f7f495f08e6ebbd613753bed5fc5f7da Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Mar 2023 16:07:38 +0700 Subject: [PATCH 12/13] feat: burry DIP0001 deployment to follow-up bitcoin#16060 --- src/chainparams.cpp | 28 ++-------------------------- src/consensus/params.h | 1 - src/rpc/blockchain.cpp | 1 + src/versionbitsinfo.cpp | 5 ----- test/functional/rpc_blockchain.py | 18 +----------------- 5 files changed, 4 insertions(+), 49 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 373ca4f15b54..3eea388972c0 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -157,7 +157,7 @@ class CMainParams : public CChainParams { consensus.BIP65Height = 619382; // 00000000000076d8fcea02ec0963de4abfd01e771fec0863f960c2c64fe6f357 consensus.BIP66Height = 245817; // 00000000000b1fa2dfa312863570e13fae9ca7b5566cb27e55422620b469aefa consensus.CSVHeight = 622944; // 00000000000002e3d3a6224cfce80bae367fd3283d1e5a8ba50e5e60b2d2905d - consensus.DIP0001Height = 782208; + consensus.DIP0001Height = 782208; // 000000000000000cbc9cb551e8ee1ac7aa223585cbdfb755d3683bafd93679e4 consensus.DIP0003Height = 1028160; consensus.DIP0003EnforcementHeight = 1047200; consensus.DIP0003EnforcementHash = uint256S("000000000000002d1734087b4c5afc3133e4e1c3e1a89218f62bcd9bb3d17f81"); @@ -177,13 +177,6 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of DIP0001 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1508025600; // Oct 15th, 2017 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 1539561600; // Oct 15th, 2018 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nWindowSize = 4032; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nThresholdStart = 3226; // 80% of 4032 - // Deployment of BIP147 consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].nStartTime = 1524477600; // Apr 23th, 2018 @@ -401,7 +394,7 @@ class CTestNetParams : public CChainParams { consensus.BIP65Height = 2431; // 0000039cf01242c7f921dcb4806a5994bc003b48c1973ae0c89b67809c2bb2ab consensus.BIP66Height = 2075; // 0000002acdd29a14583540cb72e1c5cc83783560e38fa7081495d474fe1671f7 consensus.CSVHeight = 8064; // 00000005eb94d027e34649373669191188858a22c70f4a6d29105e559124cec7 - consensus.DIP0001Height = 5500; + consensus.DIP0001Height = 5500; // 00000001d60a01d8f1f39011cc6b26e3a1c97a24238cab856c2da71a4dd801a9 consensus.DIP0003Height = 7000; consensus.DIP0003EnforcementHeight = 7300; consensus.DIP0003EnforcementHash = uint256S("00000055ebc0e974ba3a3fb785c5ad4365a39637d4df168169ee80d313612f8f"); @@ -421,13 +414,6 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of DIP0001 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1544655600; // Dec 13th, 2018 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nThresholdStart = 50; // 50% of 100 - // Deployment of BIP147 consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].nStartTime = 1544655600; // Dec 13th, 2018 @@ -638,13 +624,6 @@ class CDevNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of DIP0001 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 1505692800; // Sep 18th, 2017 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nThresholdStart = 50; // 50% of 100 - // Deployment of BIP147 consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].nStartTime = 1517792400; // Feb 5th, 2018 @@ -925,9 +904,6 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].bit = 1; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 999999999999ULL; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].bit = 2; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_BIP147].nTimeout = 999999999999ULL; diff --git a/src/consensus/params.h b/src/consensus/params.h index 7277920fcddf..cdb261485d83 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -15,7 +15,6 @@ namespace Consensus { enum DeploymentPos { DEPLOYMENT_TESTDUMMY, - DEPLOYMENT_DIP0001, // Deployment of DIP0001 and lower transaction fees. DEPLOYMENT_BIP147, // Deployment of BIP147 (NULLDUMMY) DEPLOYMENT_DIP0003, // Deployment of DIP0002 and DIP0003 (txv3 and deterministic MN lists) DEPLOYMENT_DIP0008, // Deployment of ChainLock enforcement diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a0cb4c2ae539..0e22184decbe 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1578,6 +1578,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) BuriedForkDescPushBack(softforks,"bip66", consensusParams.BIP66Height); BuriedForkDescPushBack(softforks,"bip65", consensusParams.BIP65Height); BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight); + BuriedForkDescPushBack(softforks, "dip0001", consensusParams.DIP0001Height); for (int pos = Consensus::DEPLOYMENT_TESTDUMMY + 1; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) { BIP9SoftForkDescPushBack(softforks, VersionBitsDeploymentInfo[pos].name, consensusParams, static_cast(pos)); } diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp index 1daea3af5a90..3a1438782953 100644 --- a/src/versionbitsinfo.cpp +++ b/src/versionbitsinfo.cpp @@ -12,11 +12,6 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.gbt_force =*/ true, /*.check_mn_protocol =*/ false, }, - { - /*.name =*/ "dip0001", - /*.gbt_force =*/ true, - /*.check_mn_protocol =*/ true, - }, { /*.name =*/ "bip147", /*.gbt_force =*/ true, diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index a1a502fe0499..c329ca9aa0ec 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -151,23 +151,7 @@ def _test_getblockchaininfo(self): 'bip66': {'type': 'buried', 'active': False, 'height': 1251}, 'bip65': {'type': 'buried', 'active': False, 'height': 1351}, 'csv': {'type': 'buried', 'active': False, 'height': 432}, - 'dip0001': { - 'type': 'bip9', - 'bip9': { - 'status': 'started', - 'bit': 1, - 'start_time': 0, - 'timeout': 999999999999, - 'since': 144, - 'statistics': { - 'period': 144, - 'threshold': 108, - 'elapsed': 57, - 'count': 57, - 'possible': True - }, - }, - 'active': False}, + 'dip0001': { 'type': 'buried', 'active': False, 'height': 2000}, 'bip147': { 'type': 'bip9', 'bip9': { From 84573364f53e42d91c823090d35a952ce9ec15e3 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 28 Mar 2023 16:25:39 +0700 Subject: [PATCH 13/13] feat: burry DIP0008 deployment to follow-up bitcoin#16060 --- src/chainparams.cpp | 24 ------------------------ src/consensus/params.h | 1 - src/rpc/blockchain.cpp | 1 + src/versionbitsinfo.cpp | 5 ----- test/functional/rpc_blockchain.py | 18 +----------------- 5 files changed, 2 insertions(+), 47 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3eea388972c0..d389f8e2e5ad 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -191,13 +191,6 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 4032; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThresholdStart = 3226; // 80% of 4032 - // Deployment of DIP0008 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1557878400; // May 15th, 2019 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 1589500800; // May 15th, 2020 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 4032; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThresholdStart = 3226; // 80% of 4032 - // Deployment of Block Reward Reallocation consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].bit = 5; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].nStartTime = 1601510400; // Oct 1st, 2020 @@ -428,13 +421,6 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 100; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThresholdStart = 50; // 50% of 100 - // Deployment of DIP0008 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThresholdStart = 50; // 50% of 100 - // Deployment of Block Reward Reallocation consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].bit = 5; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].nStartTime = 1598918400; // Sep 1st, 2020 @@ -638,13 +624,6 @@ class CDevNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 100; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThresholdStart = 50; // 50% of 100 - // Deployment of DIP0008 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019 - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThresholdStart = 50; // 50% of 100 - // Deployment of Block Reward Reallocation consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].bit = 5; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].nStartTime = 1598918400; // Sep 1st, 2020 @@ -910,9 +889,6 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].bit = 3; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 999999999999ULL; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].bit = 5; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_REALLOC].nTimeout = 999999999999ULL; diff --git a/src/consensus/params.h b/src/consensus/params.h index cdb261485d83..2dfc2f0436ff 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -17,7 +17,6 @@ enum DeploymentPos { DEPLOYMENT_TESTDUMMY, DEPLOYMENT_BIP147, // Deployment of BIP147 (NULLDUMMY) DEPLOYMENT_DIP0003, // Deployment of DIP0002 and DIP0003 (txv3 and deterministic MN lists) - DEPLOYMENT_DIP0008, // Deployment of ChainLock enforcement DEPLOYMENT_REALLOC, // Deployment of Block Reward Reallocation DEPLOYMENT_DIP0020, // Deployment of DIP0020, DIP0021 and LMQ_100_67 quorums DEPLOYMENT_DIP0024, // Deployment of DIP0024 (Quorum Rotation) and decreased governance proposal fee diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 0e22184decbe..fc61889dcf32 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1579,6 +1579,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) BuriedForkDescPushBack(softforks,"bip65", consensusParams.BIP65Height); BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight); BuriedForkDescPushBack(softforks, "dip0001", consensusParams.DIP0001Height); + BuriedForkDescPushBack(softforks, "dip0008", consensusParams.DIP0008Height); for (int pos = Consensus::DEPLOYMENT_TESTDUMMY + 1; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) { BIP9SoftForkDescPushBack(softforks, VersionBitsDeploymentInfo[pos].name, consensusParams, static_cast(pos)); } diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp index 3a1438782953..bcec42dbbdf5 100644 --- a/src/versionbitsinfo.cpp +++ b/src/versionbitsinfo.cpp @@ -22,11 +22,6 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.gbt_force =*/ true, /*.check_mn_protocol =*/ false, }, - { - /*.name =*/ "dip0008", - /*.gbt_force =*/ true, - /*.check_mn_protocol =*/ false, - }, { /*.name =*/ "realloc", /*.gbt_force =*/ true, diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index c329ca9aa0ec..444f6f94ab46 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -152,6 +152,7 @@ def _test_getblockchaininfo(self): 'bip65': {'type': 'buried', 'active': False, 'height': 1351}, 'csv': {'type': 'buried', 'active': False, 'height': 432}, 'dip0001': { 'type': 'buried', 'active': False, 'height': 2000}, + 'dip0008': { 'type': 'buried', 'active': False, 'height': 432}, 'bip147': { 'type': 'bip9', 'bip9': { @@ -186,23 +187,6 @@ def _test_getblockchaininfo(self): }, }, 'active': False}, - 'dip0008': { - 'type': 'bip9', - 'bip9': { - 'status': 'started', - 'bit': 4, - 'start_time': 0, - 'timeout': 999999999999, - 'since': 144, - 'statistics': { - 'period': 144, - 'threshold': 108, - 'elapsed': 57, - 'count': 57, - 'possible': True - }, - }, - 'active': False}, 'realloc': { 'type': 'bip9', 'bip9': {