From 51052e8bb752c395e1ddb2d6c9ae5006b7d4bae5 Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 19 Oct 2023 13:18:31 +0100 Subject: [PATCH 1/8] Merge bitcoin/bitcoin#22764: build: Include qt sources for parsing with extract_strings.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit b59b31ae0b04054c5cf225dad87046d3771707fc build: Drop redundant qt/bitcoin.cpp (Hennadii Stepanov) d90ad5a42ec6f48d0e504edc16d41c8ef266cc1d build: Include qt sources for parsing with extract_strings.py (Hennadii Stepanov) Pull request description: On master (4fc15d15667d9d9c4fb5515ce73c05b4596298ec) some strings are still untranslated. This PR fixes this issue. To verify: 1) `./autogen.sh && ./configure && make -C src translate` _before_ applying this change 2) apply this change 3) `./autogen.sh && ./configure && make -C src translate` _after_ applying this change The result of `git diff src/qt/bitcoinstrings.cpp`: ```diff --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -126,6 +126,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "You need to rebuild the database using -reindex to go back to unpruned " "mode. This will redownload the entire blockchain"), QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), +QT_TRANSLATE_NOOP("bitcoin-core", "(press q to shutdown and continue later)"), QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), @@ -204,6 +205,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to prepare statement t QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to read database verification error: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Unexpected application id. Expected %u, got %u"), QT_TRANSLATE_NOOP("bitcoin-core", "Section [%s] is not recognized."), +QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be read"), +QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be written"), QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" does not exist"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is a relative path"), @@ -242,4 +245,5 @@ QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe chara QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks…"), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)…"), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"), +QT_TRANSLATE_NOOP("bitcoin-core", "press q to shutdown"), }; ``` ACKs for top commit: ryanofsky: Code review ACK b59b31ae0b04054c5cf225dad87046d3771707fc. Being able to use `_()` macro in qt would allow simplifying some code, for example replacing repetitive: TheCharlatan: ACK b59b31ae0b04054c5cf225dad87046d3771707fc Tree-SHA512: 13d9d86b487a1b6e718ae96c198a0a927c881bf33df318412793ec9efba3a7e59cfa836204f73f5b53ff4c99edce778c11bffaa88138b80e37b71e36df6b816f --- src/Makefile.qt.include | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 04652688dbef..06de1e2237dc 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -489,11 +489,14 @@ SECONDARY: $(QT_QM) $(srcdir)/qt/dashstrings.cpp: FORCE @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $(libbitcoin_node_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES) + $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py \ + $(libbitcoin_node_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) \ + $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES) \ + $(BITCOIN_QT_BASE_CPP) $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) # The resulted dash_en.xlf source file should follow Transifex requirements. # See: https://docs.transifex.com/formats/xliff#how-to-distinguish-between-a-source-file-and-a-translation-file -translate: $(srcdir)/qt/dashstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/dashstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) -no-obsolete -I $(srcdir) -locations relative $^ -ts $(srcdir)/qt/locale/dash_en.ts @test -n $(LCONVERT) || echo "lconvert is required for updating translations" From 6eccb6078c1864449d34a5dcd36bcd7a175cf1b1 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 14 Mar 2022 08:37:43 +0100 Subject: [PATCH 2/8] Merge bitcoin/bitcoin#24505: wallet: Add a deprecation warning for newly created legacy wallets 61152183ab18960c8b42cf22ff7168762946678e wallet: Add a deprecation warning for newly created legacy wallets (Andrew Chow) Pull request description: As we slowly deprecate legacy wallets, we need to warn users that are making new legacy wallets that their wallet type is going to be unsupported in the future. ACKs for top commit: jonatack: ACK 61152183ab18960c8b42cf22ff7168762946678e S3RK: reACK 61152183ab18960c8b42cf22ff7168762946678e theStack: ACK 61152183ab18960c8b42cf22ff7168762946678e Tree-SHA512: e89bfb8168869542498958f0c9a2ab302dfd43287f8a49e7d9e09f60438a567bb8b7219a4e569797ee819b30b624f532fcc0b70c6aa0edcb392a301b8ce8b541 --- src/wallet/rpc/wallet.cpp | 4 +++- src/wallet/wallet.cpp | 5 +++++ test/functional/wallet_createwallet.py | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index c48a0d41b0f5..3b9d28d20f0a 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -634,7 +634,9 @@ static RPCHelpMan createwallet() {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using upgradetohd (by mnemonic) or sethdseed (WIF private key)."}, {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."}, {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."}, - {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."}, + {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation." + " Setting to \"false\" will create a legacy wallet; however, the legacy wallet type is being deprecated and" + " support for creating and opening legacy wallets will be removed in the future."}, {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "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."}, }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d7be196ed58b..d6cdcf824e6f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -484,6 +484,11 @@ std::shared_ptr CreateWallet(WalletContext& context, const std::string& // Write the wallet settings UpdateWalletSetting(*context.chain, name, load_on_start, warnings); + // Legacy wallets are being deprecated, warn if a newly created wallet is legacy + if (!(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) { + warnings.push_back(_("Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.")); + } + status = DatabaseStatus::SUCCESS; return wallet; } diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index f8964ecf428d..2052ec5b7b29 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -173,5 +173,10 @@ def run_test(self): self.log.info('Using a passphrase with private keys disabled returns error') assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w9', disable_private_keys=True, passphrase='thisisapassphrase') + if self.is_bdb_compiled(): + self.log.info("Test legacy wallet deprecation") + res = self.nodes[0].createwallet(wallet_name="legacy_w0", descriptors=False, load_on_startup=True) + assert_equal(res["warning"], "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.") + if __name__ == '__main__': CreateWalletTest().main() From 8a4df322b35d38262042db5b87adef79839c9c7e Mon Sep 17 00:00:00 2001 From: MacroFake Date: Tue, 13 Sep 2022 13:38:37 +0200 Subject: [PATCH 3/8] rpc: Set RPCArg options with designated initializers --- src/rpc/blockchain.cpp | 8 ++++---- src/rpc/mining.cpp | 8 +++----- src/rpc/server.cpp | 2 +- src/rpc/util.cpp | 14 +++++++------- src/rpc/util.h | 29 +++++++++++++---------------- src/wallet/rpc/backup.cpp | 30 +++++++++++++++--------------- src/wallet/rpc/coins.cpp | 2 +- src/wallet/rpc/spend.cpp | 10 +++++----- 8 files changed, 49 insertions(+), 54 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 1803294f7b3c..96cb775cd086 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1146,7 +1146,7 @@ static RPCHelpMan gettxoutsetinfo() "Note this call may take some time if you are not using coinstatsindex.\n", { {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."}, - {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).", "", {"", "string or numeric"}}, + {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).", RPCArgOptions{.type_str={"", "string or numeric"}}}, {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."}, }, RPCResult{ @@ -2019,13 +2019,13 @@ static RPCHelpMan getblockstats() "\nCompute per block statistics for a given window. All amounts are in duffs.\n" "It won't work for some heights with pruning.\n", { - {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, + {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", RPCArgOptions{.type_str={"", "string or numeric"}}}, {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)", { {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, }, - "stats"}, + RPCArgOptions{.oneline_description="stats"}}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2457,7 +2457,7 @@ static RPCHelpMan scantxoutset() }, }, }, - "[scanobjects,...]"}, + RPCArgOptions{.oneline_description="[scanobjects,...]"}}, }, { RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 385240ee1e93..33c85856dec3 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -552,15 +552,13 @@ static RPCHelpMan getblocktemplate() {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings", { {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"}, - }, - }, + }}, {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings", { {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"}, - }, - }, + }}, }, - "\"template_request\""}, + RPCArgOptions{.oneline_description="\"template_request\""}}, }, { RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""}, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 3889e09aa9e2..d864e4f04d3f 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -183,7 +183,7 @@ static RPCHelpMan stop() // to the client (intended for testing) "\nRequest a graceful shutdown of " PACKAGE_NAME ".", { - {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", "", {}, /*hidden=*/true}, + {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", RPCArgOptions{.hidden=true}}, }, RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"}, RPCExamples{""}, diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 738a5dea162e..9e36db172c86 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -361,8 +361,8 @@ struct Sections { case RPCArg::Type::BOOL: { if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion auto left = indent; - if (arg.m_type_str.size() != 0 && push_name) { - left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0); + if (arg.m_opts.type_str.size() != 0 && push_name) { + left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0); } else { left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false); } @@ -561,7 +561,7 @@ std::string RPCHelpMan::ToString() const ret += m_name; bool was_optional{false}; for (const auto& arg : m_args) { - if (arg.m_hidden) break; // Any arg that follows is also hidden + if (arg.m_opts.hidden) break; // Any arg that follows is also hidden const bool optional = arg.IsOptional(); ret += " "; if (optional) { @@ -582,7 +582,7 @@ std::string RPCHelpMan::ToString() const Sections sections; for (size_t i{0}; i < m_args.size(); ++i) { const auto& arg = m_args.at(i); - if (arg.m_hidden) break; // Any arg that follows is also hidden + if (arg.m_opts.hidden) break; // Any arg that follows is also hidden if (i == 0) ret += "\nArguments:\n"; @@ -647,8 +647,8 @@ std::string RPCArg::ToDescriptionString(bool is_named_arg) const { std::string ret; ret += "("; - if (m_type_str.size() != 0) { - ret += m_type_str.at(1); + if (m_opts.type_str.size() != 0) { + ret += m_opts.type_str.at(1); } else { switch (m_type) { case Type::STR_HEX: @@ -890,7 +890,7 @@ std::string RPCArg::ToStringObj(const bool oneline) const std::string RPCArg::ToString(const bool oneline) const { - if (oneline && !m_oneline_description.empty()) return m_oneline_description; + if (oneline && !m_opts.oneline_description.empty()) return m_opts.oneline_description; switch (m_type) { case Type::STR_HEX: diff --git a/src/rpc/util.h b/src/rpc/util.h index cbbd8831b283..fabd9666e9cc 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -133,6 +133,12 @@ enum class OuterType { /** Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range of 1000. */ std::vector EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider); +struct RPCArgOptions { + std::string oneline_description{}; //!< Should be empty unless it is supposed to override the auto-generated summary line + std::vector type_str{}; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_opts.type_str.at(0) will override the type of the value in a key-value pair, m_opts.type_str.at(1) will override the type in the argument description. + bool hidden{false}; //!< For testing only +}; + struct RPCArg { enum class Type { OBJ, @@ -167,32 +173,26 @@ struct RPCArg { using DefaultHint = std::string; /** Default constant value */ using Default = UniValue; - using Fallback = std::variant; + using Fallback = std::variant; const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments) const Type m_type; - const bool m_hidden; const std::vector m_inner; //!< Only used for arrays or dicts const Fallback m_fallback; const std::string m_description; - const std::string m_oneline_description; //!< Should be empty unless it is supposed to override the auto-generated summary line - const std::vector m_type_str; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_type_str.at(0) will override the type of the value in a key-value pair, m_type_str.at(1) will override the type in the argument description. + const RPCArgOptions m_opts; RPCArg( std::string name, Type type, Fallback fallback, std::string description, - std::string oneline_description = "", - std::vector type_str = {}, - bool hidden = false) + RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, - m_hidden{hidden}, m_fallback{std::move(fallback)}, m_description{std::move(description)}, - m_oneline_description{std::move(oneline_description)}, - m_type_str{std::move(type_str)} + m_opts{std::move(opts)} { CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ && type != Type::OBJ_USER_KEYS); } @@ -203,16 +203,13 @@ struct RPCArg { Fallback fallback, std::string description, std::vector inner, - std::string oneline_description = "", - std::vector type_str = {}) + RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, - m_hidden{false}, m_inner{std::move(inner)}, m_fallback{std::move(fallback)}, m_description{std::move(description)}, - m_oneline_description{std::move(oneline_description)}, - m_type_str{std::move(type_str)} + m_opts{std::move(opts)} { CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ || type == Type::OBJ_USER_KEYS); } @@ -227,7 +224,7 @@ struct RPCArg { /** * Return the type string of the argument. - * Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description). + * Set oneline to allow it to be overridden by a custom oneline type string (m_opts.oneline_description). */ std::string ToString(bool oneline) const; /** diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 666516516923..dab1919ea4c3 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -1493,15 +1493,15 @@ RPCHelpMan importmulti() { {"desc", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"}, {"scriptPubKey", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor", - /*oneline_description=*/"", {"\"