Skip to content

Commit

Permalink
qt, test: add importpubkey, importprivkey, and importaddress tests
Browse files Browse the repository at this point in the history
  • Loading branch information
KolbyML committed May 18, 2023
1 parent b27e740 commit 76c98a8
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 0 deletions.
3 changes: 3 additions & 0 deletions build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ClCompile Include="..\..\src\qt\test\addressbooktests.cpp" />
<ClCompile Include="..\..\src\qt\test\apptests.cpp" />
<ClCompile Include="..\..\src\qt\test\importdescriptorstests.cpp" />
<ClCompile Include="..\..\src\qt\test\importlegacytests.cpp" />
<ClCompile Include="..\..\src\qt\test\importmultitests.cpp" />
<ClCompile Include="..\..\src\qt\test\optiontests.cpp" />
<ClCompile Include="..\..\src\qt\test\rpcnestedtests.cpp" />
Expand All @@ -25,6 +26,7 @@
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addressbooktests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_apptests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_importdescriptorstests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_importlegacytests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_importmultitests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_optiontests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_rpcnestedtests.cpp" />
Expand Down Expand Up @@ -99,6 +101,7 @@
<MocTestFiles Include="..\..\src\qt\test\addressbooktests.h" />
<MocTestFiles Include="..\..\src\qt\test\apptests.h" />
<MocTestFiles Include="..\..\src\qt\test\importdescriptorstests.h" />
<MocTestFiles Include="..\..\src\qt\test\importlegacytests.h" />
<MocTestFiles Include="..\..\src\qt\test\importmultitests.h" />
<MocTestFiles Include="..\..\src\qt\test\optiontests.h" />
<MocTestFiles Include="..\..\src\qt\test\rpcnestedtests.h" />
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.qttest.include
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if ENABLE_WALLET
TEST_QT_MOC_CPP += \
qt/test/moc_addressbooktests.cpp \
qt/test/moc_importdescriptorstests.cpp \
qt/test/moc_importlegacytests.cpp \
qt/test/moc_importmultitests.cpp \
qt/test/moc_wallettests.cpp
endif # ENABLE_WALLET
Expand All @@ -23,6 +24,7 @@ TEST_QT_H = \
qt/test/addressbooktests.h \
qt/test/apptests.h \
qt/test/importdescriptorstests.h \
qt/test/importlegacytests.h \
qt/test/importmultitests.h \
qt/test/optiontests.h \
qt/test/rpcnestedtests.h \
Expand All @@ -45,6 +47,7 @@ if ENABLE_WALLET
qt_test_test_bitcoin_qt_SOURCES += \
qt/test/addressbooktests.cpp \
qt/test/importdescriptorstests.cpp \
qt/test/importlegacytests.cpp \
qt/test/importmultitests.cpp \
qt/test/wallettests.cpp \
qt/test/util.cpp \
Expand Down
223 changes: 223 additions & 0 deletions src/qt/test/importlegacytests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/test/importlegacytests.h>
#include <qt/test/util.h>
#include <test/util/setup_common.h>

#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <qt/bitcoinamountfield.h>
#include <qt/importdialog.h>
#include <qt/clientmodel.h>
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
#include <qt/walletmodel.h>

#include <key_io.h>
#include <script/standard.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
#include <wallet/test/util.h>
#include <walletinitinterface.h>

#include <chrono>

#include <QApplication>
#include <QCheckBox>
#include <QLineEdit>
#include <QString>

using wallet::AddWallet;
using wallet::CreateMockWalletDatabase;
using wallet::CWallet;
using wallet::RemoveWallet;
using wallet::WalletContext;

struct ImportKeyData
{
QString key;
QString label;
bool rescan = true;
bool p2sh = false;
};

void EditKeyAndSubmit(ImportDialog* dialog, ImportDialog::Page _page, const ImportKeyData& data, QString expected_msg) {
QString warning_text;

dialog->findChild<QLineEdit*>("keyEditIKP")->setText(data.key);
dialog->findChild<QLineEdit*>("labelEditIKP")->setText(data.label);
dialog->findChild<QCheckBox*>("rescanButtonIKP")->setChecked(data.rescan);
if (_page == ImportDialog::importAddress) {
dialog->findChild<QCheckBox*>("p2shButtonIKP")->setChecked(data.p2sh);
}

ConfirmMessage(&warning_text, 5ms);
dialog->accept();
QCOMPARE(warning_text, expected_msg);
}

void TestImportLegacy(interfaces::Node& node)
{
// Set up wallet and chain with 105 blocks.
TestChain100Setup test;
auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(105, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
}

wallet->LoadWallet();
wallet->SetupLegacyScriptPubKeyMan();

// Initialize relevant QT models.
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
OptionsModel optionsModel(node);
bilingual_str error;
QVERIFY(optionsModel.Init(error));
ClientModel clientModel(node, &optionsModel);
WalletContext& context = *node.walletLoader().context();
AddWallet(context, wallet);
WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);

ImportDialog importDialogPubkey(ImportDialog::importPubkey, &walletModel);
ImportDialog importDialogPrivkey(ImportDialog::importPrivkey, &walletModel);
ImportDialog importDialogAddress(ImportDialog::importAddress, &walletModel);

// Public key
Key key = BuildAddress(wallet.get());
ImportKeyData data;
data.key = key.pubkey;
EditKeyAndSubmit(&importDialogPubkey, ImportDialog::importPubkey, data, QString("Import Succeeded"));

AddressInfo addressInfo;
GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, true);
QCOMPARE(addressInfo.ismine, false);

// Public key + Label
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.pubkey;
data.rescan = false;
data.label = "Successful public key import";
EditKeyAndSubmit(&importDialogPubkey, ImportDialog::importPubkey, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, true);
QCOMPARE(addressInfo.ismine, false);
QCOMPARE(addressInfo.label, "Successful public key import");

// Public key + Rescan
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.pubkey;
EditKeyAndSubmit(&importDialogPubkey, ImportDialog::importPubkey, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, true);
QCOMPARE(addressInfo.ismine, false);

// Public key must be hex string
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.p2pkh_addr;
EditKeyAndSubmit(&importDialogPubkey, ImportDialog::importPubkey, data, QString("Pubkey must be a hex string"));

// Public key not a valid public key
data = ImportKeyData();
data.key = "02e053f77836d086a6082f441fc0db6a71de0620f3e1c9797d80ade82979c73c";
EditKeyAndSubmit(&importDialogPubkey, ImportDialog::importPubkey, data, QString("Pubkey is not a valid public key"));

// Private key
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.privkey;
EditKeyAndSubmit(&importDialogPrivkey, ImportDialog::importPrivkey, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, false);
QCOMPARE(addressInfo.ismine, true);

// Private key + Label
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.privkey;
data.label = "Successful private key import";
EditKeyAndSubmit(&importDialogPrivkey, ImportDialog::importPrivkey, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, false);
QCOMPARE(addressInfo.ismine, true);
QCOMPARE(addressInfo.label, "Successful private key import");

// Private key not a valid public key
data = ImportKeyData();
data.key = "cSFUNyEbpxP6Jur5kJftYEugGzkd1QUjHwSwkjH5yco6z1oERCq";
EditKeyAndSubmit(&importDialogPrivkey, ImportDialog::importPrivkey, data, QString("Invalid private key encoding."));

// Address
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.p2pkh_addr;
EditKeyAndSubmit(&importDialogAddress, ImportDialog::importAddress, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, true);
QCOMPARE(addressInfo.ismine, false);

// Address + Label
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.p2pkh_addr;
data.label = "Successful address import";
EditKeyAndSubmit(&importDialogAddress, ImportDialog::importAddress, data, QString("Import Succeeded"));

GetAddressInfo(wallet.get(), addressInfo, key.p2pkh_addr);
QCOMPARE(addressInfo.iswatchonly, true);
QCOMPARE(addressInfo.ismine, false);
QCOMPARE(addressInfo.label, "Successful address import");

// Invalid Address or script
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.privkey;
EditKeyAndSubmit(&importDialogAddress, ImportDialog::importAddress, data, QString("Invalid Bitcoin address or script"));

// Invalid Address can't import Bech32m into a legacy wallet
data = ImportKeyData();
data.key = "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6";
EditKeyAndSubmit(&importDialogAddress, ImportDialog::importAddress, data, QString("Bech32m addresses cannot be imported into legacy wallets"));

// Invalid Address use the p2sh flag with an address
key = BuildAddress(wallet.get());
data = ImportKeyData();
data.key = key.p2pkh_addr;
data.p2sh = true;
EditKeyAndSubmit(&importDialogAddress, ImportDialog::importAddress, data, QString("Cannot use the p2sh flag with an address - use a script instead"));
}

void ImportLegacyTests::importLegacyTests()
{
#ifdef Q_OS_MACOS
if (QApplication::platformName() == "minimal") {
// Disable for mac on "minimal" platform to avoid crashes inside the Qt
// framework when it tries to look up unimplemented cocoa functions,
// and fails to handle returned nulls
// (https://bugreports.qt.io/browse/QTBUG-49686).
QWARN("Skipping ImportLegacyTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
"with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.");
return;
}
#endif
TestImportLegacy(m_node);
}
27 changes: 27 additions & 0 deletions src/qt/test/importlegacytests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_TEST_IMPORTLEGACYTESTS_H
#define BITCOIN_QT_TEST_IMPORTLEGACYTESTS_H

#include <QObject>
#include <QTest>

namespace interfaces {
class Node;
} // namespace interfaces

class ImportLegacyTests : public QObject
{
public:
explicit ImportLegacyTests(interfaces::Node& node) : m_node(node) {}
interfaces::Node& m_node;

Q_OBJECT

private Q_SLOTS:
void importLegacyTests();
};

#endif // BITCOIN_QT_TEST_IMPORTLEGACYTESTS_H
4 changes: 4 additions & 0 deletions src/qt/test/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
#include <qt/test/importdescriptorstests.h>
#include <qt/test/importlegacytests.h>
#include <qt/test/importmultitests.h>
#include <qt/test/wallettests.h>
#endif // ENABLE_WALLET
Expand Down Expand Up @@ -112,6 +113,9 @@ int main(int argc, char* argv[])

ImportDescriptorsTests test8(app.node());
num_test_failures += QTest::qExec(&test8);

ImportLegacyTests test9(app.node());
num_test_failures += QTest::qExec(&test9);
#endif

if (num_test_failures) {
Expand Down

0 comments on commit 76c98a8

Please sign in to comment.