Merge #16714: gui: add prune to intro screen with smart default

9924bce317 [gui] intro: enable pruning by default unless disk is big (Sjors Provoost)
c8de347a9d [gui] intro: add prune preference (Sjors Provoost)
1bbc49d207 [gui] intro: inform caller if intro was shown (Sjors Provoost)
1957103786 [gui] add explicit prune setter (Sjors Provoost)
1bccf6a52d [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:

  <img width="671" alt="big" src="https://user-images.githubusercontent.com/10217/63641289-10339000-c6ac-11e9-98d7-caf64dff0da6.png">

  If the user has insufficient space it's checked by default:
  <img width="897" alt="low" src="https://user-images.githubusercontent.com/10217/63641276-d4002f80-c6ab-11e9-9f5b-a53472f814ff.png">

  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:

  <img width="662" alt="medium" src="https://user-images.githubusercontent.com/10217/63641294-1c1f5200-c6ac-11e9-8ecb-6b69e42b1ece.png">

  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):
  <img width="658" alt="Schermafbeelding 2019-08-24 om 20 23 14" src="https://user-images.githubusercontent.com/10217/63641351-09594d00-c6ad-11e9-94fe-fe5ed562e109.png">

  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 9924bce317
  ryanofsky:
    utACK 9924bce317. 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
This commit is contained in:
Jonas Schnelli 2019-09-12 14:59:58 +02:00
commit 884f7cc81b
No known key found for this signature in database
GPG key ID: 1EB776BB03C7922D
9 changed files with 68 additions and 9 deletions

View file

@ -62,6 +62,7 @@ public:
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); }

View file

@ -46,6 +46,9 @@ public:
//! 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;

View file

@ -282,6 +282,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";
@ -487,8 +491,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 bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
@ -562,6 +568,11 @@ int GuiMain(int argc, char* argv[])
// Load GUI settings from QSettings
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
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());

View file

@ -67,6 +67,8 @@ public:
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

View file

@ -210,6 +210,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="prune">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblExplanation2">
<property name="text">

View file

@ -131,6 +131,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<int64_t>(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) {
@ -180,8 +185,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 */
@ -205,6 +212,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize());
intro.setDataDirectory(dataDir);
intro.setWindowIcon(QIcon(":icons/bitcoin"));
did_show_intro = true;
while(true)
{
@ -227,6 +235,9 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
}
}
// Additional preferences:
prune = intro.ui->prune->isChecked();
settings.setValue("strDataDir", dataDir);
settings.setValue("fReset", false);
}
@ -263,6 +274,11 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable
{
freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
ui->prune->setChecked(true);
} else if (bytesAvailable / GB_BYTES - requiredSpace < 10) {
freeString += " " + tr("(%n GB needed for full chain)", "", requiredSpace);
ui->freeSpace->setStyleSheet("QLabel { color: #999900 }");
ui->prune->setChecked(true);
} else {
ui->freeSpace->setStyleSheet("");
}

View file

@ -39,6 +39,7 @@ public:
/**
* 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 @@ public:
* @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();

View file

@ -92,11 +92,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() ? std::to_string(nPruneSizeMiB) : "0")) {
addOverriddenOption("-prune");
}
SetPrune(settings.value("bPrune").toBool());
if (!settings.contains("nDatabaseCache"))
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
@ -240,6 +236,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
{

View file

@ -77,6 +77,9 @@ public:
bool getCoinControlFeatures() const { return fCoinControlFeatures; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
/* Explicit setters */
void SetPrune(bool prune, bool force = false);
/* Restart flag helper */
void setRestartRequired(bool fRequired);
bool isRestartRequired() const;