Skip to content

Commit

Permalink
Wallet scan optimisation (#1474)
Browse files Browse the repository at this point in the history
* Wallet scan optimisation

* UI fixes

* UI fixes

* Wallet rescan fixes

* Wallet rescan fixes

* Wallet rescan fixes

* Add date check

* scan optimisation fixes

* scan optimisation fixes

* scan optimisation fixes
  • Loading branch information
levoncrypto authored Sep 3, 2024
1 parent 5a1bb0b commit 30b8595
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 31 deletions.
12 changes: 11 additions & 1 deletion src/qt/forms/notifymnemonic.ui
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,21 @@
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="walletBirthDate">
<property name="text">
<string></string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="textLabel2">
<property name="text">
<string>Please write down these recovery seed phrase and keep them in a secure location.</string>
<string>Please write down these recovery seed phrase and wallet birth date and keep them in a secure location. Specifying the wallet's birth date when restoring your wallet speeds up and optimizes the scanning of your wallet.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand Down
60 changes: 43 additions & 17 deletions src/qt/forms/recover.ui
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ You can also choose to further encrypt your recovery seed phrase with an additio
You will need to save this passphrase as well with the recovery seed phrase. Failing to save the passphrase will lead to your funds being irrecoverable.

If you have an existing recovery seed phrase, please select "Recover existing wallet". If you have secured your recovery seed phrase with an additional passphrase, enter it too.
Also you can choose wallet birth date for more faster and optimised wallet scan.
</string>
</property>
<property name="wordWrap">
Expand Down Expand Up @@ -134,20 +135,51 @@ If you have an existing recovery seed phrase, please select "Recover existing wa
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout2">
<layout class="QVBoxLayout" name="verticalLayout2">
<item>
<widget class="QLabel" name="textLabel2">
<property name="text">
<string>Input recovery seed phrase here:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout2">
<item>
<widget class="QLabel" name="textLabel2">
<property name="text">
<string>Input recovery seed phrase here:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mnemonicWords"/>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="mnemonicWords"/>
</item>
<layout class="QHBoxLayout" name="horizontalLayoutDate">
<item>
<widget class="QLabel" name="textLabelDate">
<property name="text">
<string>Choose the wallet creation date:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDateEdit" name="dateInput">
<property name="calendarPopup">
<bool>true</bool>
</property>
<property name="displayFormat">
<string>dd-MM-yyyy</string>
</property>
<property name="date">
</property>
</widget>
</item>
</layout>
</item>

</layout>
</item>
<item>
Expand Down Expand Up @@ -234,12 +266,6 @@ If you have an existing recovery seed phrase, please select "Recover existing wa
</item>
<item>
<widget class="QLabel" name="errorMessage">
<property name="text">
<string/>
</property>
<property name="styleSheet">
<string notr="true">color:red;</string>
</property>
<property name="text">
<string/>
</property>
Expand Down
6 changes: 6 additions & 0 deletions src/qt/notifymnemonic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <QSettings>
#include <QMessageBox>
#include <QAbstractButton>
#include <QDate>

NotifyMnemonic::NotifyMnemonic(QWidget *parent) :
QWizard(parent),
Expand All @@ -36,6 +37,10 @@ void NotifyMnemonic::cancelEvent()
}
}

QString getCurrentDate() {
return QDate::currentDate().toString("dd-MM-yyyy");
}

void NotifyMnemonic::notify()
{
#ifdef ENABLE_WALLET
Expand All @@ -44,6 +49,7 @@ void NotifyMnemonic::notify()
NotifyMnemonic notify;
notify.setWindowIcon(QIcon(":icons/firo"));
notify.show();
notify.ui->walletBirthDate->setText("Wallet creation date: " + getCurrentDate());
notify.ui->mnemonic->setText(mnemonic.c_str());
notify.restart();
while(true)
Expand Down
15 changes: 15 additions & 0 deletions src/qt/recover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Recover::Recover(QWidget *parent) :

connect(this, &Recover::stopThread, thread, &QThread::quit);
thread->start();

ui->dateInput->setDisplayFormat("dd-MM-yyyy");
ui->dateInput->setMinimumDate(QDate(2019, 12, 11));
}

Recover::~Recover()
Expand All @@ -47,6 +50,8 @@ void Recover::setCreateNew()
ui->textLabel2->setEnabled(false);
ui->mnemonicWords->setEnabled(false);
ui->mnemonicWords->clear();
ui->dateInput->setEnabled(false);
ui->dateInput->clear();
ui->use24->setChecked(true);
ui->usePassphrase->setChecked(false);
ui->textLabel3->setEnabled(false);
Expand All @@ -58,12 +63,18 @@ void Recover::setCreateNew()
void Recover::on_createNew_clicked()
{
setCreateNew();
ui->dateInput->setDisplayFormat("dd-MM-yyyy");
ui->dateInput->setDate(QDate(2019, 12, 11));
}

void Recover::on_recoverExisting_clicked()
{
ui->textLabel2->setEnabled(true);
ui->mnemonicWords->setEnabled(true);
ui->dateInput->setEnabled(true);
ui->dateInput->setEnabled(true);
ui->dateInput->setDisplayFormat("dd-MM-yyyy");
ui->dateInput->setDate(ui->dateInput->minimumDate());
}

void Recover::on_usePassphrase_clicked()
Expand Down Expand Up @@ -106,6 +117,10 @@ bool Recover::askRecover(bool& newWallet)
if(recover.ui->recoverExisting->isChecked()) {
newWallet = false;
std::string mnemonic = recover.ui->mnemonicWords->text().toStdString();
QDate date = recover.ui->dateInput->date();
QDate newDate = date.addDays(-1);
recover.ui->dateInput->setDate(newDate);
SoftSetArg("-wcdate", recover.ui->dateInput->text().toStdString());
const char* str = mnemonic.c_str();
bool space = true;
int n = 0;
Expand Down
65 changes: 52 additions & 13 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2365,6 +2365,30 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,

}

static std::time_t parseDate(const std::string& dateStr) {
std::tm tm = {};
std::istringstream ss(dateStr);
ss >> std::get_time(&tm, "%d-%m-%Y");
if (ss.fail()) {
throw std::invalid_argument("Invalid date format: " + dateStr);
}
return std::mktime(&tm);
}

CBlockIndex* CWallet::GetBlockByDate(CBlockIndex* pindexStart, const std::string& dateStr) {
std::time_t targetTimestamp = parseDate(dateStr);

CBlockIndex* pindex = pindexStart;

while (pindex) {
if (pindex->GetBlockTime() > targetTimestamp) {
return chainActive[pindex->nHeight - 200];
}
pindex = chainActive.Next(pindex);
}
return chainActive[chainActive.Tip()->nHeight];
}

/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
Expand All @@ -2383,18 +2407,34 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex *pindexStart, bool f
CBlockIndex* pindex = pindexStart;
{
LOCK2(cs_main, cs_wallet);

// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
// if you are recovering wallet with mnemonics start rescan from block when mnemonics implemented in Firo
if (fRecoverMnemonic) {
pindex = chainActive[chainParams.GetConsensus().nMnemonicBlock];
if (pindex == NULL)
pindex = chainActive.Tip();
} else
while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);

// No need to read and scan block if block was created before our wallet birthday (as adjusted for block time variability).
// If you are recovering wallet with mnemonics, start rescan from the block when mnemonics were implemented in Firo.
// If the user provides a date, start scanning from the block that corresponds to that date.
// If no date is provided, start scanning from the mnemonic start block.

std::string wcdate = GetArg("-wcdate", "");
CBlockIndex* mnemonicStartBlock = chainActive[chainParams.GetConsensus().nMnemonicBlock];
if (mnemonicStartBlock == NULL)
mnemonicStartBlock = chainActive.Tip();

if (!wcdate.empty()) {
pindex = GetBlockByDate(mnemonicStartBlock, wcdate);
if (pindex->nHeight < chainParams.GetConsensus().nMnemonicBlock) {
pindex = mnemonicStartBlock;
}
} else {
bool fRescan = GetBoolArg("-rescan", false);
if (fRescan || fRecoverMnemonic) {
if (mnemonicContainer.IsNull())
pindex = chainActive.Genesis();
else
pindex = mnemonicStartBlock;
}
else
while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);
}
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height(), pindex->nHeight);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
Expand Down Expand Up @@ -7285,7 +7325,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}

uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true, fRecoverMnemonic);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
Expand Down
1 change: 1 addition & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) override;
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false, bool fRecoverMnemonic = false);
CBlockIndex* GetBlockByDate(CBlockIndex* pindexStart, const std::string& dateStr);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
Expand Down

0 comments on commit 30b8595

Please sign in to comment.