From df72fd52374611202deaef313af23c2c8d7f6043 Mon Sep 17 00:00:00 2001 From: alex v Date: Wed, 7 Aug 2024 23:29:40 +0200 Subject: [PATCH 1/6] add option to create wallet from seed --- src/bench/wallet_create.cpp | 2 +- src/bitcoin-wallet.cpp | 1 + src/blsct/wallet/keyman.cpp | 11 +++++++++-- src/blsct/wallet/keyman.h | 4 ++-- src/interfaces/wallet.h | 2 +- src/test/blsct/pos/pos_chain_tests.cpp | 2 +- src/test/blsct/wallet/txfactory_tests.cpp | 6 +++--- src/test/blsct/wallet/validation_tests.cpp | 2 +- src/wallet/interfaces.cpp | 4 ++-- src/wallet/rpc/wallet.cpp | 6 +++++- src/wallet/test/walletload_tests.cpp | 2 +- src/wallet/wallet.cpp | 4 ++-- src/wallet/wallet.h | 2 +- src/wallet/wallettool.cpp | 18 ++++++++++++------ 14 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp index 993c4c4b3fde8..2fc0898c050e6 100644 --- a/src/bench/wallet_create.cpp +++ b/src/bench/wallet_create.cpp @@ -34,7 +34,7 @@ static void WalletCreate(benchmark::Bench& bench, bool encrypted) fs::path wallet_path = test_setup->m_path_root / strprintf("test_wallet_%d", random.rand32()).c_str(); bench.run([&] { - auto wallet = CreateWallet(context, wallet_path.utf8string(), /*load_on_start=*/std::nullopt, options, status, error_string, warnings); + auto wallet = CreateWallet(context, wallet_path.utf8string(), {}, /*load_on_start=*/std::nullopt, options, status, error_string, warnings); assert(status == DatabaseStatus::SUCCESS); assert(wallet != nullptr); diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 6a46508ade51b..c8cbfc8273b34 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -43,6 +43,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman) argsman.AddArg("-debug=", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-blsct", "Create blsct wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-seed", "Seed used for the wallet creation. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-legacy", "Create legacy wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-format=", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); diff --git a/src/blsct/wallet/keyman.cpp b/src/blsct/wallet/keyman.cpp index 3e790b3782552..ecfee0ce074d5 100644 --- a/src/blsct/wallet/keyman.cpp +++ b/src/blsct/wallet/keyman.cpp @@ -261,13 +261,20 @@ void KeyMan::SetHDSeed(const PrivateKey& key) wallet::WalletBatch batch(m_storage.GetDatabase()); } -bool KeyMan::SetupGeneration(bool force) +bool KeyMan::SetupGeneration(const std::vector& seed, bool force) { if ((CanGenerateKeys() && !force) || m_storage.IsLocked()) { return false; } - SetHDSeed(GenerateNewSeed()); + if (seed.size() != 32) { + SetHDSeed(GenerateNewSeed()); + } else { + MclScalar scalarSeed; + scalarSeed.SetVch(seed); + SetHDSeed(scalarSeed); + } + if (!NewSubAddressPool() || !NewSubAddressPool(-1) || !NewSubAddressPool(-2)) { return false; } diff --git a/src/blsct/wallet/keyman.h b/src/blsct/wallet/keyman.h index c0633abb34763..59fe27ed37825 100644 --- a/src/blsct/wallet/keyman.h +++ b/src/blsct/wallet/keyman.h @@ -34,7 +34,7 @@ class Manager explicit Manager(wallet::WalletStorage& storage) : m_storage(storage) {} virtual ~Manager(){}; - virtual bool SetupGeneration(bool force = false) { return false; } + virtual bool SetupGeneration(const std::vector& seed, bool force = false) { return false; } /* Returns true if HD is enabled */ virtual bool IsHDEnabled() const { return false; } @@ -72,7 +72,7 @@ class KeyMan : public Manager, public KeyRing KeyMan(wallet::WalletStorage& storage, int64_t keypool_size) : Manager(storage), KeyRing(), m_keypool_size(keypool_size) {} - bool SetupGeneration(bool force = false) override; + bool SetupGeneration(const std::vector& seed, bool force = false) override; bool IsHDEnabled() const override; /* Returns true if the wallet can generate new keys */ diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 61142366234cc..0ef4ecc351184 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -323,7 +323,7 @@ class WalletLoader : public ChainClient { public: //! Create new wallet. - virtual util::Result> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector& warnings) = 0; + virtual util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, uint64_t wallet_creation_flags, std::vector& warnings) = 0; //! Load existing wallet. virtual util::Result> loadWallet(const std::string& name, std::vector& warnings) = 0; diff --git a/src/test/blsct/pos/pos_chain_tests.cpp b/src/test/blsct/pos/pos_chain_tests.cpp index 5e20f6c41c37d..d3428da2e1de3 100644 --- a/src/test/blsct/pos/pos_chain_tests.cpp +++ b/src/test/blsct/pos/pos_chain_tests.cpp @@ -46,7 +46,7 @@ BOOST_FIXTURE_TEST_CASE(StakedCommitment, TestBLSCTChain100Setup) LOCK(wallet.cs_wallet); auto blsct_km = wallet.GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/test/blsct/wallet/txfactory_tests.cpp b/src/test/blsct/wallet/txfactory_tests.cpp index f35747ff87c81..3293db9d5b8c5 100644 --- a/src/test/blsct/wallet/txfactory_tests.cpp +++ b/src/test/blsct/wallet/txfactory_tests.cpp @@ -22,7 +22,7 @@ BOOST_FIXTURE_TEST_CASE(ismine_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); @@ -53,7 +53,7 @@ BOOST_FIXTURE_TEST_CASE(createtransaction_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); @@ -114,7 +114,7 @@ BOOST_FIXTURE_TEST_CASE(addinput_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/test/blsct/wallet/validation_tests.cpp b/src/test/blsct/wallet/validation_tests.cpp index c6cfddcfdee4e..0e0105493de7a 100644 --- a/src/test/blsct/wallet/validation_tests.cpp +++ b/src/test/blsct/wallet/validation_tests.cpp @@ -25,7 +25,7 @@ BOOST_FIXTURE_TEST_CASE(validation_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 03264a0db0c0f..20754394d32fc 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -597,7 +597,7 @@ class WalletLoaderImpl : public WalletLoader void schedulerMockForward(std::chrono::seconds delta) override { Assert(m_context.scheduler)->MockForward(delta); } //! WalletLoader methods - util::Result> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector& warnings) override + util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, uint64_t wallet_creation_flags, std::vector& warnings) override { DatabaseOptions options; DatabaseStatus status; @@ -606,7 +606,7 @@ class WalletLoaderImpl : public WalletLoader options.create_flags = wallet_creation_flags; options.create_passphrase = passphrase; bilingual_str error; - std::unique_ptr wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; + std::unique_ptr wallet{MakeWallet(m_context, CreateWallet(m_context, name, seed, /*load_on_start=*/true, options, status, error, warnings))}; if (wallet) { return wallet; } else { diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 4d5e6473bb374..63c9b3401bd57 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -354,6 +354,7 @@ static RPCHelpMan createwallet() {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."}, {"blsct", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a wallet with BLSCT keys."}, + {"seed", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "Create the wallet from the specified seed."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", { @@ -420,8 +421,11 @@ static RPCHelpMan createwallet() options.create_flags = flags; options.create_passphrase = passphrase; bilingual_str error; + std::vector seed; + if (!request.params[9].isNull() && request.params[9].isStr()) + seed = ParseHex(request.params[9].get_str()); std::optional load_on_start = request.params[6].isNull() ? std::nullopt : std::optional(request.params[6].get_bool()); - const std::shared_ptr wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings); + const std::shared_ptr wallet = CreateWallet(context, request.params[0].get_str(), seed, load_on_start, options, status, error, warnings); if (!wallet) { RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR; throw JSONRPCError(code, error.original); diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp index 7869fdac43a48..91daad1998684 100644 --- a/src/wallet/test/walletload_tests.cpp +++ b/src/wallet/test/walletload_tests.cpp @@ -230,7 +230,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_blsct, TestingSetup) wallet->InitWalletFlags(wallet::WALLET_FLAG_BLSCT); LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration(true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, true)); // Get the keys in the wallet before encryption auto masterKeysMetadata = blsct_km->GetHDChain(); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 215f9ce07897a..770618448f5a4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -370,7 +370,7 @@ std::shared_ptr LoadWallet(WalletContext& context, const std::string& n return wallet; } -std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings) +std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings) { uint64_t wallet_creation_flags = options.create_flags; const SecureString& passphrase = options.create_passphrase; @@ -449,7 +449,7 @@ std::shared_ptr CreateWallet(WalletContext& context, const std::string& auto blsct_man = wallet->GetBLSCTKeyMan(); if (blsct_man) { - if (!blsct_man->SetupGeneration()) { + if (!blsct_man->SetupGeneration(seed)) { error = Untranslated("Unable to generate initial blsct keys"); status = DatabaseStatus::FAILED_CREATE; return nullptr; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3a3b3b816fa20..7106a1c9b5c69 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -96,7 +96,7 @@ std::vector> GetWallets(WalletContext& context); std::shared_ptr GetDefaultWallet(WalletContext& context, size_t& count); std::shared_ptr GetWallet(WalletContext& context, const std::string& name); std::shared_ptr LoadWallet(WalletContext& context, const std::string& name, std::optional load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); -std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); +std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); std::shared_ptr RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); std::unique_ptr HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet); void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr& wallet); diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index d7b3a5649400f..c22220634f247 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -29,7 +29,7 @@ static void WalletToolReleaseWallet(CWallet* wallet) delete wallet; } -static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags) +static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags, const std::vector& seed) { LOCK(wallet_instance->cs_wallet); @@ -47,7 +47,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag auto blsct_man = wallet_instance->GetOrCreateBLSCTKeyMan(); if (blsct_man) { - blsct_man->SetupGeneration(); + blsct_man->SetupGeneration(seed); } } @@ -55,7 +55,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag wallet_instance->TopUpKeyPool(); } -static std::shared_ptr MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options) +static std::shared_ptr MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options, const std::vector& seed) { DatabaseStatus status; bilingual_str error; @@ -100,7 +100,7 @@ static std::shared_ptr MakeWallet(const std::string& name, const fs::pa } } - if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags); + if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags, seed); return wallet_instance; } @@ -139,6 +139,10 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n"); return false; } + if (args.IsArgSet("-seed") && command != "create") { + tfm::format(std::cerr, "The -seed option can only be used with the 'create' command.\n"); + return false; + } if (command == "create" && !args.IsArgSet("-wallet")) { tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n"); return false; @@ -174,7 +178,9 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) options.require_format = DatabaseFormat::SQLITE; } - const std::shared_ptr wallet_instance = MakeWallet(name, path, options); + std::string seed = args.GetArg("-seed", ""); + + const std::shared_ptr wallet_instance = MakeWallet(name, path, options, ParseHex(seed)); if (wallet_instance) { WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); @@ -183,7 +189,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) DatabaseOptions options; ReadDatabaseArgs(args, options); options.require_existing = true; - const std::shared_ptr wallet_instance = MakeWallet(name, path, options); + const std::shared_ptr wallet_instance = MakeWallet(name, path, options, {}); if (!wallet_instance) return false; WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); From f666c3ed4495511602882bc28549a7999f739e70 Mon Sep 17 00:00:00 2001 From: alex v Date: Fri, 9 Aug 2024 21:07:24 +0200 Subject: [PATCH 2/6] add option to import view key --- src/Makefile.am | 1 + src/bench/wallet_create.cpp | 2 +- src/blsct/wallet/import_wallet_type.h | 16 ++++++++++++ src/blsct/wallet/keyman.cpp | 17 +++++++++---- src/blsct/wallet/keyman.h | 5 ++-- src/blsct/wallet/txfactory.h | 15 +++++++---- src/interfaces/wallet.h | 3 ++- src/test/blsct/pos/pos_chain_tests.cpp | 2 +- src/test/blsct/wallet/txfactory_tests.cpp | 6 ++--- src/test/blsct/wallet/validation_tests.cpp | 2 +- src/wallet/interfaces.cpp | 4 +-- src/wallet/rpc/wallet.cpp | 17 ++++++++++--- src/wallet/test/walletload_tests.cpp | 2 +- src/wallet/wallet.cpp | 4 +-- src/wallet/wallet.h | 2 +- src/wallet/wallettool.cpp | 29 ++++++++++++++++------ src/wallet/walletutil.h | 1 + 17 files changed, 92 insertions(+), 36 deletions(-) create mode 100644 src/blsct/wallet/import_wallet_type.h diff --git a/src/Makefile.am b/src/Makefile.am index 3c1221e960cba..d3bb8166eb7cc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,6 +200,7 @@ BLSCT_H = \ blsct/wallet/address.h \ blsct/wallet/hdchain.h \ blsct/wallet/helpers.h \ + blsct/wallet/import_wallet_type.h \ blsct/wallet/keyman.h \ blsct/wallet/keyring.h \ blsct/wallet/txfactory.h \ diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp index 2fc0898c050e6..40bd7da09380a 100644 --- a/src/bench/wallet_create.cpp +++ b/src/bench/wallet_create.cpp @@ -34,7 +34,7 @@ static void WalletCreate(benchmark::Bench& bench, bool encrypted) fs::path wallet_path = test_setup->m_path_root / strprintf("test_wallet_%d", random.rand32()).c_str(); bench.run([&] { - auto wallet = CreateWallet(context, wallet_path.utf8string(), {}, /*load_on_start=*/std::nullopt, options, status, error_string, warnings); + auto wallet = CreateWallet(context, wallet_path.utf8string(), {}, blsct::IMPORT_MASTER_KEY, /*load_on_start=*/std::nullopt, options, status, error_string, warnings); assert(status == DatabaseStatus::SUCCESS); assert(wallet != nullptr); diff --git a/src/blsct/wallet/import_wallet_type.h b/src/blsct/wallet/import_wallet_type.h new file mode 100644 index 0000000000000..13803ddfe24d5 --- /dev/null +++ b/src/blsct/wallet/import_wallet_type.h @@ -0,0 +1,16 @@ +// Copyright (c) 2023 The Navio developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef NAVIO_BLSCT_IMPORT_WALLET_TYPE_H +#define NAVIO_BLSCT_IMPORT_WALLET_TYPE_H + +namespace blsct { +enum SeedType { + IMPORT_MASTER_KEY, + IMPORT_VIEW_KEY +}; + +} // namespace blsct + +#endif // NAVIO_BLSCT_KEYMAN_H \ No newline at end of file diff --git a/src/blsct/wallet/keyman.cpp b/src/blsct/wallet/keyman.cpp index ecfee0ce074d5..b54851786da0f 100644 --- a/src/blsct/wallet/keyman.cpp +++ b/src/blsct/wallet/keyman.cpp @@ -248,7 +248,7 @@ void KeyMan::SetHDSeed(const PrivateKey& key) throw std::runtime_error(std::string(__func__) + ": AddSpendKey failed"); if (!AddViewKey(viewKey, viewKey.GetPublicKey())) - throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed"); + throw std::runtime_error(std::string(__func__) + ": AddViewKey failed"); if (!AddKeyPubKey(tokenKey, tokenKey.GetPublicKey())) throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed"); @@ -261,7 +261,7 @@ void KeyMan::SetHDSeed(const PrivateKey& key) wallet::WalletBatch batch(m_storage.GetDatabase()); } -bool KeyMan::SetupGeneration(const std::vector& seed, bool force) +bool KeyMan::SetupGeneration(const std::vector& seed, const SeedType& type, bool force) { if ((CanGenerateKeys() && !force) || m_storage.IsLocked()) { return false; @@ -270,9 +270,16 @@ bool KeyMan::SetupGeneration(const std::vector& seed, bool force) if (seed.size() != 32) { SetHDSeed(GenerateNewSeed()); } else { - MclScalar scalarSeed; - scalarSeed.SetVch(seed); - SetHDSeed(scalarSeed); + if (type == IMPORT_MASTER_KEY) { + MclScalar scalarSeed; + scalarSeed.SetVch(seed); + SetHDSeed(scalarSeed); + } else if (type == IMPORT_VIEW_KEY) { + MclScalar scalarView; + scalarView.SetVch(seed); + if (!AddViewKey(scalarView, viewKey.GetPublicKey())) + throw std::runtime_error(std::string(__func__) + ": AddViewKey failed"); + } } if (!NewSubAddressPool() || !NewSubAddressPool(-1) || !NewSubAddressPool(-2)) { diff --git a/src/blsct/wallet/keyman.h b/src/blsct/wallet/keyman.h index 59fe27ed37825..897ea134409e0 100644 --- a/src/blsct/wallet/keyman.h +++ b/src/blsct/wallet/keyman.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ class Manager explicit Manager(wallet::WalletStorage& storage) : m_storage(storage) {} virtual ~Manager(){}; - virtual bool SetupGeneration(const std::vector& seed, bool force = false) { return false; } + virtual bool SetupGeneration(const std::vector& seed, const SeedType& type, bool force = false) { return false; } /* Returns true if HD is enabled */ virtual bool IsHDEnabled() const { return false; } @@ -72,7 +73,7 @@ class KeyMan : public Manager, public KeyRing KeyMan(wallet::WalletStorage& storage, int64_t keypool_size) : Manager(storage), KeyRing(), m_keypool_size(keypool_size) {} - bool SetupGeneration(const std::vector& seed, bool force = false) override; + bool SetupGeneration(const std::vector& seed, const SeedType& type = IMPORT_MASTER_KEY, bool force = false) override; bool IsHDEnabled() const override; /* Returns true if the wallet can generate new keys */ diff --git a/src/blsct/wallet/txfactory.h b/src/blsct/wallet/txfactory.h index cb9f945ef3c81..3b02ac9dcfaab 100644 --- a/src/blsct/wallet/txfactory.h +++ b/src/blsct/wallet/txfactory.h @@ -28,17 +28,22 @@ class TxFactoryBase { protected: CMutableTransaction tx; - std::map> vOutputs; - std::map> vInputs; - std::map nAmounts; + std::map> + vOutputs; + std::map> + vInputs; + std::map + nAmounts; public: TxFactoryBase(){}; void AddOutput(const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0, const bool& fSubtractFeeFromAmount = false); bool AddInput(const CAmount& amount, const MclScalar& gamma, const blsct::PrivateKey& spendingKey, const TokenId& token_id, const COutPoint& outpoint, const bool& rbf = false); - std::optional BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake = 0, const CreateTransactionType& type = NORMAL, const bool& fSubtractedFee = false); - static std::optional CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); + std::optional + BuildTx(const blsct::DoublePublicKey& changeDestination, const CAmount& minStake = 0, const CreateTransactionType& type = NORMAL, const bool& fSubtractedFee = false); + static std::optional + CreateTransaction(const std::vector& inputCandidates, const blsct::DoublePublicKey& changeDestination, const SubAddress& destination, const CAmount& nAmount, std::string sMemo, const TokenId& token_id = TokenId(), const CreateTransactionType& type = NORMAL, const CAmount& minStake = 0); static void AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const wallet::CoinFilterParams& coins_params, std::vector& inputCandidates) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet); static void AddAvailableCoins(wallet::CWallet* wallet, blsct::KeyMan* blsct_km, const TokenId& token_id, const CreateTransactionType& type, std::vector& inputCandidates) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet); }; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 0ef4ecc351184..872e031078014 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -6,6 +6,7 @@ #define BITCOIN_INTERFACES_WALLET_H #include +#include #include #include #include @@ -323,7 +324,7 @@ class WalletLoader : public ChainClient { public: //! Create new wallet. - virtual util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, uint64_t wallet_creation_flags, std::vector& warnings) = 0; + virtual util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, const blsct::SeedType& type, uint64_t wallet_creation_flags, std::vector& warnings) = 0; //! Load existing wallet. virtual util::Result> loadWallet(const std::string& name, std::vector& warnings) = 0; diff --git a/src/test/blsct/pos/pos_chain_tests.cpp b/src/test/blsct/pos/pos_chain_tests.cpp index d3428da2e1de3..ce7316e3c6dcc 100644 --- a/src/test/blsct/pos/pos_chain_tests.cpp +++ b/src/test/blsct/pos/pos_chain_tests.cpp @@ -46,7 +46,7 @@ BOOST_FIXTURE_TEST_CASE(StakedCommitment, TestBLSCTChain100Setup) LOCK(wallet.cs_wallet); auto blsct_km = wallet.GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/test/blsct/wallet/txfactory_tests.cpp b/src/test/blsct/wallet/txfactory_tests.cpp index 3293db9d5b8c5..6a3cba307ed4c 100644 --- a/src/test/blsct/wallet/txfactory_tests.cpp +++ b/src/test/blsct/wallet/txfactory_tests.cpp @@ -22,7 +22,7 @@ BOOST_FIXTURE_TEST_CASE(ismine_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); @@ -53,7 +53,7 @@ BOOST_FIXTURE_TEST_CASE(createtransaction_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); @@ -114,7 +114,7 @@ BOOST_FIXTURE_TEST_CASE(addinput_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/test/blsct/wallet/validation_tests.cpp b/src/test/blsct/wallet/validation_tests.cpp index 0e0105493de7a..96f981a287f43 100644 --- a/src/test/blsct/wallet/validation_tests.cpp +++ b/src/test/blsct/wallet/validation_tests.cpp @@ -25,7 +25,7 @@ BOOST_FIXTURE_TEST_CASE(validation_test, TestingSetup) LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); auto recvAddress = std::get(blsct_km->GetNewDestination(0).value()); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 20754394d32fc..37ae8ce86ddb0 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -597,7 +597,7 @@ class WalletLoaderImpl : public WalletLoader void schedulerMockForward(std::chrono::seconds delta) override { Assert(m_context.scheduler)->MockForward(delta); } //! WalletLoader methods - util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, uint64_t wallet_creation_flags, std::vector& warnings) override + util::Result> createWallet(const std::string& name, const SecureString& passphrase, const std::vector& seed, const blsct::SeedType& type, uint64_t wallet_creation_flags, std::vector& warnings) override { DatabaseOptions options; DatabaseStatus status; @@ -606,7 +606,7 @@ class WalletLoaderImpl : public WalletLoader options.create_flags = wallet_creation_flags; options.create_passphrase = passphrase; bilingual_str error; - std::unique_ptr wallet{MakeWallet(m_context, CreateWallet(m_context, name, seed, /*load_on_start=*/true, options, status, error, warnings))}; + std::unique_ptr wallet{MakeWallet(m_context, CreateWallet(m_context, name, seed, type, /*load_on_start=*/true, options, status, error, warnings))}; if (wallet) { return wallet; } else { diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 63c9b3401bd57..cd5b23962882d 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -355,6 +355,7 @@ static RPCHelpMan createwallet() {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."}, {"blsct", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a wallet with BLSCT keys."}, {"seed", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "Create the wallet from the specified seed."}, + {"viewkey", RPCArg::Type::STR_HEX, RPCArg::Default{""}, "Create the wallet from the specified view key."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", { @@ -414,6 +415,16 @@ static RPCHelpMan createwallet() flags &= ~WALLET_FLAG_DESCRIPTORS; } + std::vector seed; + blsct::SeedType type = blsct::IMPORT_MASTER_KEY; + if (!request.params[9].isNull() && request.params[9].isStr()) { + seed = ParseHex(request.params[9].get_str()); + } else if (!request.params[10].isNull() && request.params[10].isStr()) { + seed = ParseHex(request.params[10].get_str()); + type = blsct::IMPORT_VIEW_KEY; + flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; + } + DatabaseOptions options; DatabaseStatus status; ReadDatabaseArgs(*context.args, options); @@ -421,11 +432,9 @@ static RPCHelpMan createwallet() options.create_flags = flags; options.create_passphrase = passphrase; bilingual_str error; - std::vector seed; - if (!request.params[9].isNull() && request.params[9].isStr()) - seed = ParseHex(request.params[9].get_str()); + std::optional load_on_start = request.params[6].isNull() ? std::nullopt : std::optional(request.params[6].get_bool()); - const std::shared_ptr wallet = CreateWallet(context, request.params[0].get_str(), seed, load_on_start, options, status, error, warnings); + const std::shared_ptr wallet = CreateWallet(context, request.params[0].get_str(), seed, type, load_on_start, options, status, error, warnings); if (!wallet) { RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR; throw JSONRPCError(code, error.original); diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp index 91daad1998684..8758401e398ef 100644 --- a/src/wallet/test/walletload_tests.cpp +++ b/src/wallet/test/walletload_tests.cpp @@ -230,7 +230,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_blsct, TestingSetup) wallet->InitWalletFlags(wallet::WALLET_FLAG_BLSCT); LOCK(wallet->cs_wallet); auto blsct_km = wallet->GetOrCreateBLSCTKeyMan(); - BOOST_CHECK(blsct_km->SetupGeneration({}, true)); + BOOST_CHECK(blsct_km->SetupGeneration({}, blsct::IMPORT_MASTER_KEY, true)); // Get the keys in the wallet before encryption auto masterKeysMetadata = blsct_km->GetHDChain(); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 770618448f5a4..c4115ebee9b83 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -370,7 +370,7 @@ std::shared_ptr LoadWallet(WalletContext& context, const std::string& n return wallet; } -std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings) +std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, const blsct::SeedType& type, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings) { uint64_t wallet_creation_flags = options.create_flags; const SecureString& passphrase = options.create_passphrase; @@ -449,7 +449,7 @@ std::shared_ptr CreateWallet(WalletContext& context, const std::string& auto blsct_man = wallet->GetBLSCTKeyMan(); if (blsct_man) { - if (!blsct_man->SetupGeneration(seed)) { + if (!blsct_man->SetupGeneration(seed, type)) { error = Untranslated("Unable to generate initial blsct keys"); status = DatabaseStatus::FAILED_CREATE; return nullptr; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7106a1c9b5c69..10e26c1e3c77c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -96,7 +96,7 @@ std::vector> GetWallets(WalletContext& context); std::shared_ptr GetDefaultWallet(WalletContext& context, size_t& count); std::shared_ptr GetWallet(WalletContext& context, const std::string& name); std::shared_ptr LoadWallet(WalletContext& context, const std::string& name, std::optional load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); -std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); +std::shared_ptr CreateWallet(WalletContext& context, const std::string& name, const std::vector& seed, const blsct::SeedType& type, std::optional load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); std::shared_ptr RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector& warnings); std::unique_ptr HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet); void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr& wallet); diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index c22220634f247..6710030cc8c5d 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -29,7 +29,7 @@ static void WalletToolReleaseWallet(CWallet* wallet) delete wallet; } -static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags, const std::vector& seed) +static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags, const std::vector& seed, const blsct::SeedType& type) { LOCK(wallet_instance->cs_wallet); @@ -47,7 +47,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag auto blsct_man = wallet_instance->GetOrCreateBLSCTKeyMan(); if (blsct_man) { - blsct_man->SetupGeneration(seed); + blsct_man->SetupGeneration(seed, type); } } @@ -55,7 +55,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag wallet_instance->TopUpKeyPool(); } -static std::shared_ptr MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options, const std::vector& seed) +static std::shared_ptr MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options, const std::vector& seed, const blsct::SeedType& type) { DatabaseStatus status; bilingual_str error; @@ -100,7 +100,7 @@ static std::shared_ptr MakeWallet(const std::string& name, const fs::pa } } - if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags, seed); + if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags, seed, type); return wallet_instance; } @@ -143,6 +143,10 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) tfm::format(std::cerr, "The -seed option can only be used with the 'create' command.\n"); return false; } + if (args.IsArgSet("-viewkey") && command != "create") { + tfm::format(std::cerr, "The -viewkey option can only be used with the 'create' command.\n"); + return false; + } if (command == "create" && !args.IsArgSet("-wallet")) { tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n"); return false; @@ -178,9 +182,20 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) options.require_format = DatabaseFormat::SQLITE; } - std::string seed = args.GetArg("-seed", ""); - const std::shared_ptr wallet_instance = MakeWallet(name, path, options, ParseHex(seed)); + std::string seed; + blsct::SeedType type; + + if (args.IsArgSet("-seed")) { + seed = args.GetArg("-seed", ""); + type = blsct::IMPORT_MASTER_KEY; + } else if (args.IsArgSet("-viewkey")) { + seed = args.GetArg("-seed", ""); + type = blsct::IMPORT_VIEW_KEY; + options.create_flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; + } + + const std::shared_ptr wallet_instance = MakeWallet(name, path, options, ParseHex(seed), type); if (wallet_instance) { WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); @@ -189,7 +204,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) DatabaseOptions options; ReadDatabaseArgs(args, options); options.require_existing = true; - const std::shared_ptr wallet_instance = MakeWallet(name, path, options, {}); + const std::shared_ptr wallet_instance = MakeWallet(name, path, options, {}, blsct::IMPORT_MASTER_KEY); if (!wallet_instance) return false; WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index dc952c5d36bed..72e320b1bea91 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_WALLET_WALLETUTIL_H #define BITCOIN_WALLET_WALLETUTIL_H +#include #include