refactor: Replace BResult with util::Result #25721

pull ryanofsky wants to merge 1 commits into bitcoin:master from ryanofsky:pr/bresult-del changing 24 files +247 −125
  1. ryanofsky commented at 7:26 pm on July 27, 2022: contributor

    Rename BResult class to util::Result and update the class interface to be more compatible with std::optional and with a full-featured result class implemented in #25665. Motivation for this change is to update existing BResult usages now so they don’t have to change later when more features are added in #25665.

    This change makes the following improvements originally implemented in #25665:

    • More explicit API. Drops potentially misleading BResult constructor that treats any bilingual string argument as an error. Adds util::Error constructor so it is never ambiguous when a result is being assigned an error or non-error value.

    • Better type compatibility. Supports util::Result<bilingual_str> return values to hold translated messages which are not errors.

    • More standard and consistent API. util::Result supports most of the same operators and methods as std::optional. BResult had a less familiar interface with HasRes/GetObj/ReleaseObj methods. The Result/Res/Obj naming was also not internally consistent.

    • Better code organization. Puts src/util/ code in the util:: namespace so naming reflects code organization and it is obvious where the class is coming from. Drops “B” from name because it is undocumented what it stands for (bilingual?)

    • Has unit tests.

  2. DrahtBot added the label Refactoring on Jul 27, 2022
  3. DrahtBot commented at 8:55 pm on July 27, 2022: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #25756 (rest: Remove support for a number of -deprecatedrest options by stickies-v)
    • #25755 (rest: Use from_blockhash and txdetails query parameters by stickies-v)
    • #25754 (rest: Extend HTTPRequest interface to support querying path (parameters) by stickies-v)
    • #25753 (rest: Move format string from path-like parameter to query parameter by stickies-v)
    • #25734 (wallet, refactor: #24584 follow-ups by josibake)
    • #25722 (refactor: Use util::Result class for wallet loading by ryanofsky)
    • #25685 (wallet: Faster transaction creation by removing pre-set-inputs fetching responsibility from Coin Selection by furszy)
    • #25666 (refactor: wallet, do not translate init options names by furszy)
    • #25665 (refactor: Add util::Result class and use it in LoadChainstate by ryanofsky)
    • #25656 (refactor: wallet: return BResult from GetReservedDestination methods by theStack)
    • #25616 (refactor: Return BResult from WalletLoader methods by w0xlt)
    • #25297 (wallet: speedup transactions sync, rescan and load by grouping all independent db writes on a single batched db transaction by furszy)
    • #25273 (wallet: Pass through transaction locktime and preset input sequences and scripts to CreateTransaction by achow101)
    • #25269 (wallet: re-activate the not triggered “AmountWithFeeExceedsBalance” error by furszy)
    • #25183 (rpc: Filter inputs by type during CoinSelection by aureleoules)
    • #24897 ([Draft / POC] Silent Payments by w0xlt)
    • #19602 (wallet: Migrate legacy wallets to descriptor wallets by achow101)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  4. ryanofsky force-pushed on Jul 27, 2022
  5. ryanofsky commented at 9:30 pm on July 27, 2022: contributor
    Updated 13aeab1cf6de1777db480ee7f568d78daecf49dd -> 2aa408b4ccc57539a7f6b383e6c98acac10e39c0 (pr/bresult-del.1 -> pr/bresult-del.2, compare) dropping dependency on #25665 as suggested #25665 (comment) Updated 2aa408b4ccc57539a7f6b383e6c98acac10e39c0 -> e71b858bc0f30784191725d71a77bab4d280a6f9 (pr/bresult-del.2 -> pr/bresult-del.3, compare) adding missing test file Updated e71b858bc0f30784191725d71a77bab4d280a6f9 -> 42f4f7d126f6729c4924b0630f67d171f4d0ac9b (pr/bresult-del.3 -> pr/bresult-del.4, compare) fixing comment
  6. ryanofsky force-pushed on Jul 27, 2022
  7. ryanofsky marked this as ready for review on Jul 27, 2022
  8. ryanofsky force-pushed on Jul 27, 2022
  9. w0xlt approved
  10. w0xlt commented at 3:16 am on July 30, 2022: contributor
    Concept ACK. But maybe the changes can be split in two or more commits.
  11. in src/util/result.h:58 in 42f4f7d126 outdated
    83+    T value_or(const U& default_value) const { return has_value() ? value() : default_value; }
    84+    operator bool() const { return has_value(); }
    85+    const T* operator->() const { return &value(); }
    86+    const T& operator*() const { return value(); }
    87+    T* operator->() { return &value(); }
    88+    T& operator*() { return value(); }
    


    MarcoFalke commented at 2:14 pm on August 1, 2022:
    For reference, this addresses my feedback from #25218 (review)
  12. in src/util/result.h:51 in 42f4f7d126 outdated
    76+
    77+    //! std::optional methods, so functions returning optional<T> can change to
    78+    //! return Result<T> with minimal changes to existing code, and vice versa.
    79+    bool has_value() const { return m_variant.index() == 1; }
    80+    const T& value() const { assert(*this); return std::get<1>(m_variant); }
    81+    T& value() { assert(*this); return std::get<1>(m_variant); }
    


    MarcoFalke commented at 2:18 pm on August 1, 2022:
    Missing LIFETIMEBOUND for any method that returns & or *?

    ryanofsky commented at 4:59 pm on August 1, 2022:

    re: #25721 (review)

    Missing LIFETIMEBOUND for any method that returns & or *?

    Thanks, added

  13. in src/wallet/spend.cpp:979 in 42f4f7d126 outdated
    981         CCoinControl tmp_cc = coin_control;
    982         tmp_cc.m_avoid_partial_spends = true;
    983         auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
    984         // Helper optional class for now
    985-        std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes() ? std::make_optional(res_tx_grouped.GetObj()) : std::nullopt};
    986+        std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped ? std::make_optional(*res_tx_grouped) : std::nullopt};
    


    MarcoFalke commented at 2:23 pm on August 1, 2022:

    If the goal of this pull is to make the interface equal to std::optional, what is the point of keeping this line? If there is one, why not use std::move? See #25218 (review)

    0        std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped ? std::make_optional(std::move(*res_tx_grouped)) : std::nullopt};
    

    ryanofsky commented at 5:00 pm on August 1, 2022:

    re: #25721 (review)

    If the goal of this pull is to make the interface equal to std::optional, what is the point of keeping this line? If there is one, why not use std::move? See #25218 (comment)

    Thanks! Dropped the line. I just didn’t notice this chance to simplify.

  14. in src/bench/wallet_loading.cpp:48 in 42f4f7d126 outdated
    45@@ -46,10 +46,10 @@ static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
    46 static void AddTx(CWallet& wallet)
    47 {
    48     const auto& dest = wallet.GetNewDestination(OutputType::BECH32, "");
    


    MarcoFalke commented at 2:34 pm on August 1, 2022:
    0    const auto& dest = *Assert(wallet.GetNewDestination(OutputType::BECH32, ""));
    

    nit: Could remove the assert and * below, and add them to this line? (Though, it then might need a std::move to avoid a use-after-free?)


    ryanofsky commented at 4:59 pm on August 1, 2022:

    re: #25721 (review)

    nit: Could remove the assert and * below, and add them to this line? (Though, it then might need a std::move to avoid a use-after-free?)

    Sure, this does seem like a good additional simplification. Added *Assert and dropped & to avoid use-after-free this would cause (std::move is just a type-cast and wouldn’t extend the return value lifetime after the Assert)


    MarcoFalke commented at 11:36 am on August 2, 2022:
    Sure, but now this creates a copy without the std::move, right?

    MarcoFalke commented at 12:58 pm on August 2, 2022:

    If yes, maybe use the same you used in the fuzz test:

    GetScriptForDestination(*Assert(op_dest))?


    ryanofsky commented at 3:32 pm on August 2, 2022:

    re: #25721 (review)

    Sure, but now this creates a copy without the std::move, right?

    If yes, maybe use the same you used in the fuzz test:

    Yes it does, inlined now

  15. in src/qt/walletcontroller.cpp:396 in 42f4f7d126 outdated
    392@@ -393,8 +393,8 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri
    393     QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
    394         auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)};
    395 
    396-        m_error_message = wallet ? bilingual_str{} : wallet.GetError();
    397-        if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(wallet.ReleaseObj());
    398+        m_error_message = wallet ? bilingual_str{} : util::ErrorString(wallet);
    


    MarcoFalke commented at 2:37 pm on August 1, 2022:
    0        m_error_message = util::ErrorString(wallet);
    

    nit?


    ryanofsky commented at 5:02 pm on August 1, 2022:

    re: #25721 (review)

    nit?

    Thanks, added simplification

  16. in src/util/result.h:50 in 42f4f7d126 outdated
    75+    Result(Error error, Result<OT>&& other) : m_variant{std::move(std::get<0>(other.m_variant))} {}
    76+
    77+    //! std::optional methods, so functions returning optional<T> can change to
    78+    //! return Result<T> with minimal changes to existing code, and vice versa.
    79+    bool has_value() const { return m_variant.index() == 1; }
    80+    const T& value() const { assert(*this); return std::get<1>(m_variant); }
    


    MarcoFalke commented at 2:40 pm on August 1, 2022:
    Any reason to change this to have several ; on one line, when clang-format doesn’t like that? Also if you kept this as return std::get<T>(m_variant);, the diff would be smaller by one line.

    ryanofsky commented at 5:02 pm on August 1, 2022:

    re: #25721 (review)

    Any reason to change this to have several ; on one line, when clang-format doesn’t like that?

    It’s easier to see what the methods supports if you can look down the left column and see the method names and arguments and return values. The actual method bodies are trivial and probably not helpful to someone trying to use the class, so this convention puts the useful information all in one place instead of alternating useful and useless information and making declarations difficult to skim.

    I actually started using this convention because I saw clang-format unwrap lines similarly in other places. We do have AllowShortFunctionsOnASingleLine: All enabled, so I’m not sure why it would not be kicking in here, but I didn’t look into it.

    Also if you kept this as return std::get<T>(m_variant);, the diff would be smaller by one line.

    Motivation for changing get<T> to get<1> is to resolve ambiguity here if T is a bilingual_str, in which case get<T> would not compile. Also it seems more direct and possibly more efficient at compile time to retrieve the variant by index and not rely on template type comparisons.

  17. in src/test/util/wallet.cpp:23 in 42f4f7d126 outdated
    20@@ -21,9 +21,9 @@ std::string getnewaddress(CWallet& w)
    21 {
    22     constexpr auto output_type = OutputType::BECH32;
    23     auto op_dest = w.GetNewDestination(output_type, "");
    


    MarcoFalke commented at 2:46 pm on August 1, 2022:
    Same: Use Assert?

    ryanofsky commented at 5:03 pm on August 1, 2022:

    re: #25721 (review)

    Same: Use Assert?

    Thanks, added this simplification

  18. in src/util/result.h:17 in 42f4f7d126 outdated
    16+namespace util {
    17+
    18+struct Error { bilingual_str message; };
    19+
    20+//! The util::Result class provides a standard way for functions to return error
    21+//! messages in addition to optional result values.
    


    MarcoFalke commented at 2:50 pm on August 1, 2022:
    0//! messages either or result values.
    

    This reads like “and”, but should be “xor”, no?


    ryanofsky commented at 5:03 pm on August 1, 2022:

    re: #25721 (review)

    This reads like “and”, but should be “xor”, no?

    I kind of did mean “and” because it does let functions return both, just not both simultaneously. But I agree “either or” works and could be clearer, so updated.

  19. in src/util/result.h:40 in 42f4f7d126 outdated
    36-class BResult {
    37+class Result {
    38 private:
    39     std::variant<bilingual_str, T> m_variant;
    40 
    41+    template <typename FT>
    


    MarcoFalke commented at 3:12 pm on August 1, 2022:
    0    template <typename OT>
    

    nit: Shouldn’t this be named OT, as it is used in the move-constructor copying the error from Result<OT>?


    ryanofsky commented at 5:03 pm on August 1, 2022:

    re: #25721 (review)

    nit: Shouldn’t this be named OT, as it is used in the move-constructor copying the error from Result<OT>?

    Hmm, the friend declaration is saying any Result<FT> is a friend of the Result<T>. This is regardless of whether the Result<FT> is ever moved from. The friend declaration is needed by the move-constructor but it doesn’t have any direct relationship to the move constructor and could be used by any method. I could change OT to FT on just this line because the word “other” kind of makes sense for this parameter even if it isn’t referencing the “other” move constructor argument. But that would make this friend declaration inconsistent with the friend declaration for ErrorString below where there is no “other”. FT for friend type just seems like the straightforward naming.


    MarcoFalke commented at 12:11 pm on August 2, 2022:

    I didn’t read your reply, but now it is unused and can be removed:

     0diff --git a/src/util/result.h b/src/util/result.h
     1index d038ffe133..cddc8a0819 100644
     2--- a/src/util/result.h
     3+++ b/src/util/result.h
     4@@ -34,8 +34,6 @@ class Result {
     5 private:
     6     std::variant<bilingual_str, T> m_variant;
     7 
     8-    template <typename FT>
     9-    friend class Result;
    10     template <typename FT>
    11     friend bilingual_str ErrorString(const Result<FT>& result);
    12 
    

    ryanofsky commented at 3:37 pm on August 2, 2022:

    re: #25721 (review)

    I didn’t read your reply, but now it is unused and can be removed:

    Nice catch. It’s gone

  20. in src/util/result.h:45 in 42f4f7d126 outdated
    70-
    71-    explicit operator bool() const { return HasRes(); }
    72+    Result(T obj) : m_variant{std::move(obj)} {}
    73+    Result(Error error) : m_variant{std::move(error.message)} {}
    74+    template <typename OT>
    75+    Result(Error error, Result<OT>&& other) : m_variant{std::move(std::get<0>(other.m_variant))} {}
    


    MarcoFalke commented at 3:27 pm on August 1, 2022:
    Looks like this drops error.message, but I guess that’s fine?

    MarcoFalke commented at 3:41 pm on August 1, 2022:
    Maybe assert(error.message.empty()) for now?

    ryanofsky commented at 5:03 pm on August 1, 2022:

    re: #25721 (review)

    Looks like this drops error.message, but I guess that’s fine?

    It is ok because error.message is always empty right now and #25665 is supposed to allow combining error messages so it can be non-empty. But since this constructor is only used one place right now, it seems easier and less confusing to drop it, so latest push does that.

  21. in src/util/result.h:49 in 42f4f7d126 outdated
    74+    template <typename OT>
    75+    Result(Error error, Result<OT>&& other) : m_variant{std::move(std::get<0>(other.m_variant))} {}
    76+
    77+    //! std::optional methods, so functions returning optional<T> can change to
    78+    //! return Result<T> with minimal changes to existing code, and vice versa.
    79+    bool has_value() const { return m_variant.index() == 1; }
    


    MarcoFalke commented at 3:28 pm on August 1, 2022:
    Any reason to not leave this as-is? std::holds_alternative<T>(m_variant);

    ryanofsky commented at 5:03 pm on August 1, 2022:

    re: #25721 (review)

    Any reason to not leave this as-is? std::holds_alternative<T>(m_variant);

    It’s just less direct and ambiguous if T is a bilingual_str.

  22. in src/util/result.h:53 in 42f4f7d126 outdated
    78+    //! return Result<T> with minimal changes to existing code, and vice versa.
    79+    bool has_value() const { return m_variant.index() == 1; }
    80+    const T& value() const { assert(*this); return std::get<1>(m_variant); }
    81+    T& value() { assert(*this); return std::get<1>(m_variant); }
    82+    template <typename U>
    83+    T value_or(const U& default_value) const { return has_value() ? value() : default_value; }
    


    MarcoFalke commented at 3:33 pm on August 1, 2022:

    This doesn’t compile, so my recommendation would be to remove dead code and only add it when it is needed.

    0./util/result.h:53:69: error: call to implicitly-deleted copy constructor of 'const result_tests::NoCopy'
    1    T value_or(const U& default_value) const { return has_value() ? value() : default_value; }
    2                                                                    ^~~~~~~
    3test/result_tests.cpp:74:27: note: in instantiation of function template specialization 'util::Result<result_tests::NoCopy>::value_or<int>' requested here
    4    BOOST_CHECK_EQUAL(obj.value_or(1), 5);
    5                          ^
    6test/result_tests.cpp:14:26: note: copy constructor of 'NoCopy' is implicitly deleted because field 'm_n' has a deleted copy constructor
    7    std::unique_ptr<int> m_n;
    8                         ^
    
     0diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
     1index 5118571e23..bfd5672045 100644
     2--- a/src/test/result_tests.cpp
     3+++ b/src/test/result_tests.cpp
     4@@ -68,4 +68,11 @@ BOOST_AUTO_TEST_CASE(check_returned)
     5     ExpectFail(NoCopyFn(5, false), Untranslated("nocopy 5 error."));
     6 }
     7 
     8+BOOST_AUTO_TEST_CASE(check_value_or)
     9+{
    10+    auto obj{NoCopyFn(5, true)};
    11+    BOOST_CHECK_EQUAL(obj.value_or(1), 5);
    12+    obj=NoCopyFn(5, false);
    13+    BOOST_CHECK_EQUAL(obj.value_or(1), 1);
    14+}
    15 BOOST_AUTO_TEST_SUITE_END()
    16diff --git a/src/util/result.h b/src/util/result.h
    17index b9e490025b..71aec57237 100644
    18--- a/src/util/result.h
    19+++ b/src/util/result.h
    20@@ -49,8 +49,6 @@ public:
    21     bool has_value() const { return m_variant.index() == 1; }
    22     const T& value() const { assert(*this); return std::get<1>(m_variant); }
    23     T& value() { assert(*this); return std::get<1>(m_variant); }
    24-    template <typename U>
    25-    T value_or(const U& default_value) const { return has_value() ? value() : default_value; }
    26     operator bool() const { return has_value(); }
    27     const T* operator->() const { return &value(); }
    28     const T& operator*() const { return value(); }
    

    ryanofsky commented at 5:04 pm on August 1, 2022:

    re: #25721 (review)

    This doesn’t compile, so my recommendation would be to remove dead code and only add it when it is needed.

    Added unit test to cover the value_or method instead of removing the method. There was a problem with move-only types which is also fixed

  23. in src/util/result.h:54 in 42f4f7d126 outdated
    79+    bool has_value() const { return m_variant.index() == 1; }
    80+    const T& value() const { assert(*this); return std::get<1>(m_variant); }
    81+    T& value() { assert(*this); return std::get<1>(m_variant); }
    82+    template <typename U>
    83+    T value_or(const U& default_value) const { return has_value() ? value() : default_value; }
    84+    operator bool() const { return has_value(); }
    


    MarcoFalke commented at 3:37 pm on August 1, 2022:
    why remove explicit?

    ryanofsky commented at 7:04 pm on August 1, 2022:

    re: #25721 (review)

    why remove explicit?

    Added back, wasn’t intentional

  24. MarcoFalke approved
  25. MarcoFalke commented at 3:40 pm on August 1, 2022: member
    looks good, but doesn’t compile in many places
  26. in src/wallet/test/coinselector_tests.cpp:78 in 42f4f7d126 outdated
    74@@ -75,8 +75,8 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
    75     tx.vout[nInput].nValue = nValue;
    76     if (spendable) {
    77         auto op_dest = wallet.GetNewDestination(OutputType::BECH32, "");
    78-        assert(op_dest.HasRes());
    79-        tx.vout[nInput].scriptPubKey = GetScriptForDestination(op_dest.GetObj());
    80+        assert(op_dest);
    


    MarcoFalke commented at 3:46 pm on August 1, 2022:
    Could move the Assert and * into the previous line? (Might need a std::move)

    ryanofsky commented at 5:04 pm on August 1, 2022:

    re: #25721 (review)

    Could move the Assert and * into the previous line? (Might need a std::move)

    Sure, switched to Assert

  27. in src/wallet/test/fuzz/notifications.cpp:78 in 42f4f7d126 outdated
    76         } else {
    77             op_dest = wallet->GetNewChangeDestination(type);
    78         }
    79-        assert(op_dest.HasRes());
    80-        return GetScriptForDestination(op_dest.GetObj());
    81+        assert(op_dest);
    


    MarcoFalke commented at 3:47 pm on August 1, 2022:
    Could move the Assert down by one line?

    ryanofsky commented at 5:04 pm on August 1, 2022:

    re: #25721 (review)

    Could move the Assert down by one line?

    Thanks, switched to Assert

  28. MarcoFalke commented at 3:48 pm on August 1, 2022: member
    (Feel free to ignore the feedback)
  29. MarcoFalke commented at 3:48 pm on August 1, 2022: member

    42f4f7d126f6729c4924b0630f67d171f4d0ac9b 🖌

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     342f4f7d126f6729c4924b0630f67d171f4d0ac9b  🖌
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUhJAAwAq6deLBiOO2WBQPKh16i4of8/CxKg0btdMYGdzxfdExEG8Dm27whTumz/
     8pDjAMeCpUlVuqYeR/iOrjfmkPXMXsOTWoKMXR2+RGQGTazobq7LQH2aZj5BRDnh0
     9zQBBpQ2X1BNQioLb45Wik63Rg/RbPX2s9hvNxXOL2OUCBqXJr0Hm1ZgxEd9/vsMe
    10a4ieXXLSJ5+ecc4DpZILj+ulVo4BCTRLnGZz+p7dRvDtzM62OQcxmUWt1u0mwYVf
    11gqYiqbEnQYcU2uLhKv1VTBdTpzWQYVALWTvZS+2Bbibt8tVpwJ+auDy8erWHZTZh
    12HKWnPPX5bb2UiHEnkEnJzuef8bGGBZE7WyNhaX6v4l7+LUWxh649xz7iqET8/+Ip
    13PbXfBoyk1pQ9tQo5MEJPwiFAP4xSSHJCjcvrXFFOUIt6iW5U1ANpUP03yzeRnkBe
    14E8O97B5lb6Z8b5Cr+xWYVHFntw4HiBk4tvls9imI/9qkGQxNQMAUKOqEYktpVZ5z
    15ZcC2Ugbr
    16=TSsI
    17-----END PGP SIGNATURE-----
    
  30. ryanofsky force-pushed on Aug 1, 2022
  31. ryanofsky commented at 7:30 pm on August 1, 2022: contributor

    Thanks for reviews!

    Updated 42f4f7d126f6729c4924b0630f67d171f4d0ac9b -> e0289b1cdfe80644cb7045f74e6bd63562e092f8 (pr/bresult-del.4 -> pr/bresult-del.5, compare) with suggestions

    re: #25721#pullrequestreview-1056186962

    maybe the changes can be split in two or more commits.

    I’m not so sure there is a way to do this that’s a clear improvement. It would be possible to split by adding the new result interface and changing the old result interface to wrap the new interface in one commit, then deleting the old interface and changing usages to call the new interface in a second commit. This would split up the PR but also make it a little more complicated. Wouldn’t oppose this, just not sure it would be worth it

  32. ryanofsky force-pushed on Aug 2, 2022
  33. ryanofsky commented at 4:02 am on August 2, 2022: contributor
    Rebased e0289b1cdfe80644cb7045f74e6bd63562e092f8 -> 3262acf70a9fdd6b4191812f928ed374dfcf32e1 (pr/bresult-del.5 -> pr/bresult-del.6, compare) due to silent conflict with #24584
  34. in src/wallet/spend.cpp:1084 in 3262acf70a outdated
    1086         TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
    1087         CCoinControl tmp_cc = coin_control;
    1088         tmp_cc.m_avoid_partial_spends = true;
    1089-        auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
    1090+        auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
    1091         // Helper optional class for now
    


    MarcoFalke commented at 12:13 pm on August 2, 2022:
    remove this line?

    ryanofsky commented at 3:02 pm on August 2, 2022:

    re: #25721 (review)

    remove this line?

    Good catch, removed

  35. in src/wallet/test/coinselector_tests.cpp:77 in 3262acf70a outdated
    73@@ -74,9 +74,8 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
    74     tx.vout.resize(nInput + 1);
    75     tx.vout[nInput].nValue = nValue;
    76     if (spendable) {
    77-        auto op_dest = wallet.GetNewDestination(OutputType::BECH32, "");
    78-        assert(op_dest.HasRes());
    79-        tx.vout[nInput].scriptPubKey = GetScriptForDestination(op_dest.GetObj());
    80+        auto op_dest = *(Assert(wallet.GetNewDestination(OutputType::BECH32, "")));
    


    MarcoFalke commented at 12:17 pm on August 2, 2022:

    Same: this also creates a copy without a std::move?

    If yes, maybe use the same you used in the fuzz test:

    GetScriptForDestination(*Assert(op_dest))?


    ryanofsky commented at 3:03 pm on August 2, 2022:

    re: #25721 (review)

    Same: this also creates a copy without a std::move?

    Thanks inlined to avoid copy.

  36. in src/test/result_tests.cpp:60 in 3262acf70a outdated
    55+
    56+template<typename T>
    57+void ExpectResult(const util::Result<T>& result, bool success, const bilingual_str& str)
    58+{
    59+    BOOST_CHECK_EQUAL(bool(result), success);
    60+    BOOST_CHECK_EQUAL(ErrorString(result), str);
    


    MarcoFalke commented at 12:24 pm on August 2, 2022:
    could avoid adl?

    ryanofsky commented at 3:02 pm on August 2, 2022:

    re: #25721 (review)

    could avoid adl?

    Fixed

  37. in src/util/result.h:54 in 3262acf70a outdated
    79+    const T& value() const LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
    80+    T& value() LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
    81+    explicit operator bool() const { return has_value(); }
    82+    const T* operator->() const { return &value(); }
    83+    const T& operator*() const LIFETIMEBOUND { return value(); }
    84+    T* operator->() { return &value(); }
    


    MarcoFalke commented at 12:46 pm on August 2, 2022:

    Was about to ask to add LIFETIMEBOUND, but for some reason it doesn’t do anything for -> :man_shrugging:

     0diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
     1index 5737434b12..25de1eb6bc 100644
     2--- a/src/test/result_tests.cpp
     3+++ b/src/test/result_tests.cpp
     4@@ -89,7 +89,10 @@ BOOST_AUTO_TEST_CASE(check_value_or)
     5 {
     6     BOOST_CHECK_EQUAL(IntFn(10, true).value_or(20), 10);
     7     BOOST_CHECK_EQUAL(IntFn(10, false).value_or(20), 20);
     8-    BOOST_CHECK_EQUAL(NoCopyFn(10, true).value_or(20), 10);
     9+    const auto& a{NoCopyFn(10, true)->m_n};
    10+    BOOST_CHECK_EQUAL(*a, 10);
    11+    const auto& b{NoCopyFn(10, true).value().m_n};
    12+    BOOST_CHECK_EQUAL(*b, 10);
    13     BOOST_CHECK_EQUAL(NoCopyFn(10, false).value_or(20), 20);
    14 }
    15 
    16diff --git a/src/util/result.h b/src/util/result.h
    17index d038ffe133..cc1947e860 100644
    18--- a/src/util/result.h
    19+++ b/src/util/result.h
    20@@ -49,9 +47,9 @@ public:
    21     const T& value() const LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
    22     T& value() LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
    23     explicit operator bool() const { return has_value(); }
    24-    const T* operator->() const { return &value(); }
    25+    const T* operator->() const LIFETIMEBOUND { return &value(); }
    26     const T& operator*() const LIFETIMEBOUND { return value(); }
    27-    T* operator->() { return &value(); }
    28+    T* operator->() LIFETIMEBOUND { return &value(); }
    29     T& operator*() LIFETIMEBOUND { return value(); }
    30     template <class U>
    31     constexpr T value_or(U&& default_value) const& { return has_value() ? value() : std::forward<U>(default_value); }
    

    ryanofsky commented at 3:04 pm on August 2, 2022:

    re: #25721 (review)

    Was about to ask to add LIFETIMEBOUND, but for some reason it doesn’t do anything for -> man_shrugging

    Oh, I just omitted it because I didn’t know LIFETIMEBOUND worked for pointers. Seems correct to add even if it doesn’t produce any diagnostics for now though, so I added it.

  38. in src/util/result.h:59 in 3262acf70a outdated
    84+    T* operator->() { return &value(); }
    85+    T& operator*() LIFETIMEBOUND { return value(); }
    86+    template <class U>
    87+    constexpr T value_or(U&& default_value) const& { return has_value() ? value() : std::forward<U>(default_value); }
    88+    template <class U>
    89+    constexpr T value_or(U&& default_value) && { return has_value() ? std::move(**this) : std::forward<U>(default_value); }
    


    MarcoFalke commented at 12:49 pm on August 2, 2022:
    0    constexpr T value_or(U&& default_value) && { return has_value() ? std::move(value()) : std::forward<U>(default_value); }
    

    for symmetry with the previous line and to avoid one more function call


    ryanofsky commented at 3:04 pm on August 2, 2022:

    re: #25721 (review)

    for symmetry with the previous line and to avoid one more function call

    Nice, thanks. I copied this code from https://en.cppreference.com/w/cpp/utility/optional/value_or and was a little careless with fixups

  39. MarcoFalke approved
  40. MarcoFalke commented at 12:50 pm on August 2, 2022: member

    ACK 3262acf70a9fdd6b4191812f928ed374dfcf32e1 🍕

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 3262acf70a9fdd6b4191812f928ed374dfcf32e1 🍕
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUjeSwv/WOfsnvZzsh0ls1W5nwhWVihAvZgqSDvwLDwjhIUroZAbxicGcR4+nMH3
     88j/Ni2gs4mSYL3PDMOMYj0UgNalPtD41izoTFV/oEfoM1sT/1ZV0b6GtpzmNH+pR
     9PyuzQlGEFZSOyjHVKzQDfi6Io+1f9s4NLEPcP6KfzmNr6NaQYUCKQ2w59WVTlk/b
    10ELCJnE7DHAMamOF4zY6uvuiVx9SaUiM3cXjaUAZ6a1G3ccvgccGkFJNZwrXRkwKr
    11D1H7czDFaF5uyEMl/MJldPqmTztDGjj+vOOmOOYhSIAsMmiCgdoG/PFudKf1ple0
    12cVQYBS1Z2Z/aDHbk44rFzXw0eITgb69AMTwmU1iSOw5gzl4/Ejv8b0q0FTX/l/b2
    133G4SjdP5oq1gmCjfzITeU9JxgqcKhSb83sp/LInsbg6KFAI7zP0KnluoNGK3o+NY
    14hgjGzcScF6+pULwZjdweCVW+7JtefZMhwAFYle45+gVzaJ2otL6SZrThBRKuJWi3
    15kndV8T/O
    16=xb3E
    17-----END PGP SIGNATURE-----
    
  41. ryanofsky force-pushed on Aug 2, 2022
  42. ryanofsky commented at 3:48 pm on August 2, 2022: contributor

    Very helpful review!

    Updated 3262acf70a9fdd6b4191812f928ed374dfcf32e1 -> 6777df621a8c3deef033fcf815b297ee4bf3ee0f (pr/bresult-del.6 -> pr/bresult-del.7, compare) with suggested changes

  43. MarcoFalke commented at 3:55 pm on August 2, 2022: member

    ACK 6777df621a8c3deef033fcf815b297ee4bf3ee0f 🏏

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 6777df621a8c3deef033fcf815b297ee4bf3ee0f 🏏
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUi6Rgv/WA9wbfJG1xh/y8U4qZQRSFhfIOMqcDjrvC8EdxHFYf+F7obHU/UZJ+F5
     83HN5IYXLO6ipZ5av9UT5bHmIbuUipeEJTPb2/6kqc+n03Vb8kS/+puVqJUQYLl2q
     96U/GBuZ/N+wErXYR9ck+1S2lB+N85+/TVdysIXf8DIs26Y6V+zvWoyM5ahBHnWYw
    10rEF2FxMJ40ShEWi2Ov41PAh/xn6N3qBPhFoNHYuEY6EehXEwavsUV1DTxSqXuMoQ
    11l4sFUZvD++KWl5WpZEmr/J7diTr9NRAgERgJ67CskhnZ3j+zykAXeoqU0I8Yhd/f
    12/KEddaPmPRJgS3MIa6wN7dX2vkKnKyu9pBJnfekyhWmndGu2ZIPDBDZD/ELO8ndF
    13+avMWRDH0tiCqShDUWMCcpgheogqtMlWZBAcbci7aQUJ9JOFeRfQSqwR5OzAkTWK
    14JzB4rcQ+HV8V92lcBU0PpNaGWNsqxmb8n8gjsI0fnNrtx4obvdiyOlJfebsToIky
    15OZiqWv/2
    16=HEva
    17-----END PGP SIGNATURE-----
    
  44. in src/test/result_tests.cpp:34 in 6777df621a outdated
    29+    return *a.m_n == *b.m_n;
    30+}
    31+
    32+std::ostream& operator<<(std::ostream& os, const NoCopy& o)
    33+{
    34+    if (o.m_n) os << "NoCopy(" << *o.m_n << ")"; else os << "NoCopy(nullptr)";
    


    MarcoFalke commented at 4:06 pm on August 2, 2022:

    nit: nullptr is dead code, otherwise the above operator== would be UB. So if you retouch:

    0os << "NoCopy(" << *o.m_n << ")";
    

    Also: clang-format for me:

      0diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
      1index 847f68121d..6d688f7b74 100644
      2--- a/src/test/result_tests.cpp
      3+++ b/src/test/result_tests.cpp
      4@@ -18,8 +18,7 @@ inline std::ostream& operator<<(std::ostream& os, const bilingual_str& s)
      5 
      6 BOOST_AUTO_TEST_SUITE(result_tests)
      7 
      8-struct NoCopy
      9-{
     10+struct NoCopy {
     11     NoCopy(int n) : m_n{std::make_unique<int>(n)} {}
     12     std::unique_ptr<int> m_n;
     13 };
     14@@ -31,7 +30,10 @@ bool operator==(const NoCopy& a, const NoCopy& b)
     15 
     16 std::ostream& operator<<(std::ostream& os, const NoCopy& o)
     17 {
     18-    if (o.m_n) os << "NoCopy(" << *o.m_n << ")"; else os << "NoCopy(nullptr)";
     19+    if (o.m_n)
     20+        os << "NoCopy(" << *o.m_n << ")";
     21+    else
     22+        os << "NoCopy(nullptr)";
     23     return os;
     24 }
     25 
     26@@ -53,14 +55,14 @@ util::Result<NoCopy> NoCopyFn(int i, bool success)
     27     return {util::Error{Untranslated(strprintf("nocopy %i error.", i))}};
     28 }
     29 
     30-template<typename T>
     31+template <typename T>
     32 void ExpectResult(const util::Result<T>& result, bool success, const bilingual_str& str)
     33 {
     34     BOOST_CHECK_EQUAL(bool(result), success);
     35     BOOST_CHECK_EQUAL(util::ErrorString(result), str);
     36 }
     37 
     38-template<typename T, typename... Args>
     39+template <typename T, typename... Args>
     40 void ExpectSuccess(const util::Result<T>& result, const bilingual_str& str, Args&&... args)
     41 {
     42     ExpectResult(result, true, str);
     43@@ -69,7 +71,7 @@ void ExpectSuccess(const util::Result<T>& result, const bilingual_str& str, Args
     44     BOOST_CHECK_EQUAL(&result.value(), &*result);
     45 }
     46 
     47-template<typename T, typename... Args>
     48+template <typename T, typename... Args>
     49 void ExpectFail(const util::Result<T>& result, const bilingual_str& str)
     50 {
     51     ExpectResult(result, false, str);
     52diff --git a/src/util/result.h b/src/util/result.h
     53index 8f100b7933..a87627a589 100644
     54--- a/src/util/result.h
     55+++ b/src/util/result.h
     56@@ -12,7 +12,9 @@
     57 
     58 namespace util {
     59 
     60-struct Error { bilingual_str message; };
     61+struct Error {
     62+    bilingual_str message;
     63+};
     64 
     65 //! The util::Result class provides a standard way for functions to return
     66 //! either error messages or result values.
     67@@ -29,8 +31,9 @@ struct Error { bilingual_str message; };
     68 //! `std::optional<T>` can be updated to return `util::Result<T>` and return
     69 //! error strings usually just replacing `return std::nullopt;` with `return
     70 //! util::Error{error_string};`.
     71-template<class T>
     72-class Result {
     73+template <class T>
     74+class Result
     75+{
     76 private:
     77     std::variant<bilingual_str, T> m_variant;
     78 
     79@@ -44,17 +47,31 @@ public:
     80     //! std::optional methods, so functions returning optional<T> can change to
     81     //! return Result<T> with minimal changes to existing code, and vice versa.
     82     bool has_value() const { return m_variant.index() == 1; }
     83-    const T& value() const LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
     84-    T& value() LIFETIMEBOUND { assert(*this); return std::get<1>(m_variant); }
     85+    const T& value() const LIFETIMEBOUND
     86+    {
     87+        assert(*this);
     88+        return std::get<1>(m_variant);
     89+    }
     90+    T& value() LIFETIMEBOUND
     91+    {
     92+        assert(*this);
     93+        return std::get<1>(m_variant);
     94+    }
     95     explicit operator bool() const { return has_value(); }
     96     const T* operator->() const LIFETIMEBOUND { return &value(); }
     97     const T& operator*() const LIFETIMEBOUND { return value(); }
     98     T* operator->() LIFETIMEBOUND { return &value(); }
     99     T& operator*() LIFETIMEBOUND { return value(); }
    100     template <class U>
    101-    T value_or(U&& default_value) const& { return has_value() ? value() : std::forward<U>(default_value); }
    102+    T value_or(U&& default_value) const&
    103+    {
    104+        return has_value() ? value() : std::forward<U>(default_value);
    105+    }
    106     template <class U>
    107-    T value_or(U&& default_value) && { return has_value() ? std::move(value()) : std::forward<U>(default_value); }
    108+    T value_or(U&& default_value) &&
    109+    {
    110+        return has_value() ? std::move(value()) : std::forward<U>(default_value);
    111+    }
    112 };
    113 
    114 template <typename T>
    

    ryanofsky commented at 5:07 pm on August 2, 2022:

    re: #25721 (review)

    nit: nullptr is dead code, otherwise the above operator== would be UB. So if you retouch:

    Thanks, applied all suggestions

  45. ryanofsky force-pushed on Aug 2, 2022
  46. ryanofsky commented at 5:08 pm on August 2, 2022: contributor
    Updated 6777df621a8c3deef033fcf815b297ee4bf3ee0f -> c654ec55f88c980bb085e4096435d69e97a09663 (pr/bresult-del.7 -> pr/bresult-del.8, compare) with more complete commit description and suggestions from last review Updated c654ec55f88c980bb085e4096435d69e97a09663 -> 7b249b3a163effc08c9faca841647c936d22ee7a (pr/bresult-del.8 -> pr/bresult-del.9, compare) with a few more cleanups
  47. ryanofsky force-pushed on Aug 2, 2022
  48. in src/util/result.h:49 in 7b249b3a16 outdated
    60-    const T& GetObj() const {
    61-        assert(HasRes());
    62-        return std::get<T>(m_variant);
    63+    //! std::optional methods, so functions returning optional<T> can change to
    64+    //! return Result<T> with minimal changes to existing code, and vice versa.
    65+    bool has_value() const { return m_variant.index() == 1; }
    


    MarcoFalke commented at 5:32 pm on August 2, 2022:

    ryanofsky commented at 2:55 pm on August 3, 2022:
  49. in src/util/result.h:50 in 7b249b3a16 outdated
    61-        assert(HasRes());
    62-        return std::get<T>(m_variant);
    63+    //! std::optional methods, so functions returning optional<T> can change to
    64+    //! return Result<T> with minimal changes to existing code, and vice versa.
    65+    bool has_value() const { return m_variant.index() == 1; }
    66+    const T& value() const LIFETIMEBOUND
    


    MarcoFalke commented at 5:32 pm on August 2, 2022:
    same?

    ryanofsky commented at 2:57 pm on August 3, 2022:

    re: #25721 (review)

    same?

    Can throw bad_variant_access according to https://en.cppreference.com/w/cpp/utility/variant/get. The equivalent std::optional method can also throw https://en.cppreference.com/w/cpp/utility/optional/value


    MarcoFalke commented at 4:00 pm on August 3, 2022:
    I don’t think it can throw after our assert, can it?
  50. in src/util/result.h:55 in 7b249b3a16 outdated
    67+    {
    68+        assert(has_value());
    69+        return std::get<1>(m_variant);
    70     }
    71-    T ReleaseObj()
    72+    T& value() LIFETIMEBOUND
    


    MarcoFalke commented at 5:32 pm on August 2, 2022:
    same?

    ryanofsky commented at 2:59 pm on August 3, 2022:

    re: #25721 (review)

    same?

    Same as above, variant get can throw

  51. in src/util/result.h:70 in 7b249b3a16 outdated
    91+    template <class U>
    92+    T value_or(U&& default_value) &&
    93+    {
    94+        return has_value() ? std::move(value()) : std::forward<U>(default_value);
    95+    }
    96+    explicit operator bool() const { return has_value(); }
    


    MarcoFalke commented at 5:32 pm on August 2, 2022:
    Same?

    ryanofsky commented at 2:59 pm on August 3, 2022:

    re: #25721 (review)

    Same?

    Thanks added noexcept

  52. in src/util/result.h:71 in 7b249b3a16 outdated
    92+    T value_or(U&& default_value) &&
    93+    {
    94+        return has_value() ? std::move(value()) : std::forward<U>(default_value);
    95+    }
    96+    explicit operator bool() const { return has_value(); }
    97+    const T* operator->() const LIFETIMEBOUND { return &value(); }
    


    MarcoFalke commented at 5:33 pm on August 2, 2022:

    ryanofsky commented at 3:04 pm on August 3, 2022:

    re: #25721 (review)

    Same, per https://en.cppreference.com/w/cpp/utility/optional/operator*

    I guess this is a difference between std::optional and std::variant. It doesn’t seem like there is a way to get the address of an object inside a variant that is noexcept. it would be possible to make this noexcept in followup #25665 which removes the std::variant.


    MarcoFalke commented at 4:01 pm on August 3, 2022:
    It should be possible, given our assert, no?
  53. MarcoFalke commented at 5:34 pm on August 2, 2022: member
    Some nits, but please don’t take them or I might leave more
  54. ryanofsky commented at 5:46 pm on August 2, 2022: contributor

    Some nits, but please don’t take them or I might leave more

    Ok, will skip noexcept stuff for now unless there is another push. If I rebase #25665 on top of this PR, that would be another chance to make noexcept or constexpr or similar improvements.

  55. in src/wallet/spend.cpp:847 in 7b249b3a16 outdated
    843@@ -844,11 +844,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
    844     // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
    845     // provided one
    846     if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
    847-        return strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB));
    848+        return {util::Error{strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB))}};
    


    furszy commented at 3:44 am on August 3, 2022:

    What is the reason behind the extra brackets?

    Could just return util::Error{_("something bad")};

    (same for the others in this file)


    ryanofsky commented at 1:42 pm on August 3, 2022:

    re: #25721 (review)

    What is the reason behind the extra brackets?

    Good catch. Brackets aren’t necessary here so I removed them. In general, brackets are useful after #25665 to call multi-argument constructors. They are used to construct failure values:

    0return {util::Error{_("Incorrect or no genesis block found. Wrong datadir for network?")},
    1        ChainstateLoadError::FAILURE_INCOMPATIBLE_DB};
    

    And to chain multiple errors and warnings:

    0return {util::Error{"Error 1."}, util::Error{"Error 2."}, util::Warning{"Warning."}, std::move(chained_result)};
    

    And to call value constructors with more than 1 argument (since values are constructed in-place and there is no longer any requirement for them to be copyable or movable).

  56. in src/util/result.h:44 in 7b249b3a16 outdated
    51+    friend bilingual_str ErrorString(const Result<FT>& result);
    52 
    53-    /* Whether the function succeeded or not */
    54-    bool HasRes() const { return std::holds_alternative<T>(m_variant); }
    55+public:
    56+    Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
    


    furszy commented at 4:07 am on August 3, 2022:

    styling nit: what about creating an enum for the indexes?

    0enum { ERR=0, VAL=1 };
    1// then
    2std::in_place_index_t<VAL>{} 
    

    ryanofsky commented at 1:42 pm on August 3, 2022:

    re: #25721 (review)

    0enum { ERR=0, VAL=1 };
    1// then
    2std::in_place_index_t<VAL>{} 
    

    #25665 should drop the std::variant entirely making this moot, but using enum for this seems more indirect and fragile since nothing keeps enum and variant declarations lined up. I’m not against adding this, but would prefer not to unless there is more demand

  57. furszy commented at 4:08 am on August 3, 2022: member

    Concept ACK, pretty cool stuff. Will review it deeper in the coming days.

    Have to say that would have loved to talk about some of this stuff on the initial PR and/or via DM. Including the thrashing to the current result class name. But well, no hard feelings.

  58. refactor: Replace BResult with util::Result
    Rename `BResult` class to `util::Result` and update the class interface to be
    more compatible with `std::optional` and with a full-featured result class
    implemented in https://github.com/bitcoin/bitcoin/pull/25665. Motivation for
    this change is to update existing `BResult` usages now so they don't have to
    change later when more features are added in #25665.
    
    This change makes the following improvements originally implemented in #25665:
    
    - More explicit API. Drops potentially misleading `BResult` constructor that
      treats any bilingual string argument as an error. Adds `util::Error`
      constructor so it is never ambiguous when a result is being assigned an error
      or non-error value.
    
    - Better type compatibility. Supports `util::Result<bilingual_str>` return
      values to hold translated messages which are not errors.
    
    - More standard and consistent API. `util::Result` supports most of the same
      operators and methods as `std::optional`. `BResult` had a less familiar
      interface with `HasRes`/`GetObj`/`ReleaseObj` methods. The Result/Res/Obj
      naming was also not internally consistent.
    
    - Better code organization. Puts `src/util/` code in the `util::` namespace so
      naming reflects code organization and it is obvious where the class is coming
      from. Drops "B" from name because it is undocumented what it stands for
      (bilingual?)
    
    - Has unit tests.
    a23cca56c0
  59. ryanofsky force-pushed on Aug 3, 2022
  60. ryanofsky commented at 3:44 pm on August 3, 2022: contributor

    Rebased 7b249b3a163effc08c9faca841647c936d22ee7a -> a23cca56c0a7f4a267915b4beba3af3454c51603 (pr/bresult-del.9 -> pr/bresult-del.10, compare) due to silent conflict with #25272

    re: #25721#pullrequestreview-1059661095

    Have to say that would have loved to talk about some of this stuff on the initial PR and/or via DM. Including the thrashing to the current result class name. But well, no hard feelings.

    Thanks. I did bring up all of the issues I saw with the result class in the original PR, including the name. But I didn’t want to get bogged down, and in general I think it’s more productive to iterate on designs across PRs than to have back and forth debates in PR comments. Iterating across PRs puts PR authors in a position to propose unified designs, and avoid problems of design-by-committtee, or intractable disagreements, or compromises that split things down the middle and don’t leave anybody happy. Better to give priority to PR authors and just take turns making improvements. Also, iterating on designs with actual PRs instead of PR comments centers code changes over verbal descriptions, which I think leads to better decisions in the end.

  61. in src/test/result_tests.cpp:71 in a23cca56c0
    66+    BOOST_CHECK_EQUAL(result.value(), T{std::forward<Args>(args)...});
    67+    BOOST_CHECK_EQUAL(&result.value(), &*result);
    68+}
    69+
    70+template <typename T, typename... Args>
    71+void ExpectFail(const util::Result<T>& result, const bilingual_str& str)
    


    jonatack commented at 11:53 am on August 5, 2022:
    Add static for the non-template functions in this test file?

    MarcoFalke commented at 1:36 pm on August 5, 2022:
    template should imply inline, which again implies that this can’t be used in another translation unit, but correct me if I am wrong.
  62. in src/bench/wallet_loading.cpp:49 in a23cca56c0
    44@@ -45,11 +45,8 @@ static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
    45 
    46 static void AddTx(CWallet& wallet)
    47 {
    48-    const auto& dest = wallet.GetNewDestination(OutputType::BECH32, "");
    49-    assert(dest.HasRes());
    50-
    51     CMutableTransaction mtx;
    52-    mtx.vout.push_back({COIN, GetScriptForDestination(dest.GetObj())});
    53+    mtx.vout.push_back({COIN, GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")))});
    


    jonatack commented at 11:56 am on August 5, 2022:
    Add util/check.h include header for Assert
  63. in src/interfaces/wallet.h:91 in a23cca56c0
    87@@ -88,7 +88,7 @@ class Wallet
    88     virtual std::string getWalletName() = 0;
    89 
    90     // Get a new address.
    91-    virtual BResult<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0;
    92+    virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0;
    


    jonatack commented at 12:06 pm on August 5, 2022:

    While touching this line here and in the override function in src/wallet/interfaces.cpp

    0    virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) = 0;
    

    jonatack commented at 6:13 am on August 9, 2022:
    Picked up in #25616.
  64. in src/wallet/test/coinselector_tests.cpp:77 in a23cca56c0
    73@@ -74,9 +74,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
    74     tx.vout.resize(nInput + 1);
    75     tx.vout[nInput].nValue = nValue;
    76     if (spendable) {
    77-        auto op_dest = wallet.GetNewDestination(OutputType::BECH32, "");
    78-        assert(op_dest.HasRes());
    79-        tx.vout[nInput].scriptPubKey = GetScriptForDestination(op_dest.GetObj());
    80+        tx.vout[nInput].scriptPubKey = GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")));
    


    jonatack commented at 12:22 pm on August 5, 2022:
    Add util/check.h include header for Assert
  65. in src/wallet/test/fuzz/notifications.cpp:78 in a23cca56c0
    76         } else {
    77             op_dest = wallet->GetNewChangeDestination(type);
    78         }
    79-        assert(op_dest.HasRes());
    80-        return GetScriptForDestination(op_dest.GetObj());
    81+        return GetScriptForDestination(*Assert(op_dest));
    


    jonatack commented at 12:23 pm on August 5, 2022:

    Add util/check.h include header for Assert

    Can drop the temporary here, if desired

    0     // Add tx to wallet
    1     const auto& op_dest = wallet.GetNewDestination(OutputType::BECH32M, "");
    2     BOOST_ASSERT(op_dest);
    3-    const CTxDestination& dest = *op_dest;
    4 
    5     CMutableTransaction mtx;
    6-    mtx.vout.push_back({COIN, GetScriptForDestination(dest)});
    7+    mtx.vout.push_back({COIN, GetScriptForDestination(*op_dest)});
    

    jonatack commented at 6:12 am on August 9, 2022:
    Picked up in #25616.
  66. in src/wallet/scriptpubkeyman.cpp:1773 in a23cca56c0
    1771     } else {
    1772-        error = op_dest.GetError();
    1773+        error = util::ErrorString(op_dest);
    1774     }
    1775-    return op_dest.HasRes();
    1776+    return bool(op_dest);
    


    jonatack commented at 12:28 pm on August 5, 2022:

    pico-nit

    0    return bool{op_dest};
    

    MarcoFalke commented at 1:38 pm on August 5, 2022:
    or just has_value (from HasRes)?

    jonatack commented at 6:12 am on August 9, 2022:
    Picked up in #25616.
  67. jonatack commented at 12:31 pm on August 5, 2022: contributor

    ACK a23cca56c0a7f4a267915b4beba3af3454c51603

    If you retouch, suggest running the clang-format script on these changes for indentation fixups: git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v

  68. MarcoFalke added this to the milestone 24.0 on Aug 5, 2022
  69. MarcoFalke commented at 1:33 pm on August 5, 2022: member

    ACK a23cca56c0a7f4a267915b4beba3af3454c51603 🏵

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK a23cca56c0a7f4a267915b4beba3af3454c51603 🏵
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUibEwwAtRdeVzFNlJvBUQma8DTkES+vTFqwFFtrgLjyySE7Vhj1zch85AEseH+8
     8JbezZlkYhBZJmxhCvZxPd7i50Ol9DLQM3yJNSwIMIpxaTJicKxD0YIcFYl3qAA1D
     9FUnXa5XWt8ZtdX0CNUtUYJaY63kKVQhX8ln5Yukrkh9NtPttpNyqVMSOnCDY7w/A
    10fLbge5LbQDcQEuxZ38dkh0fx/aUJuB7IknZ8x+KEFaUuoBz5XZQM76gIOjoDYZff
    11QA1rm6jPZ7HZ1HhmgrDabTisSV3Y9mgqyuKvwr4sPM/TfxerSmX2n5lj30uaXlC4
    12ek829uZyzzOvvKdSbvKIHJ0S87WOi8br0ta6bFfScZmCw9fFP3ts15ROo8X8ERYE
    13DNzQ2EyZL1XXKC4mAdr6WfTyQ42q4YAILUTkoN++6yBYWJgO90sFdZ5NRSbZyHIz
    14rDqlFjlWRONL0ieHqlJKzKSJq4TPSC0ewvrKPHiBsmOg3rVum93ZJ/u03+39Ahws
    15EBA0XoCZ
    16=UnbR
    17-----END PGP SIGNATURE-----
    
  70. MarcoFalke merged this on Aug 5, 2022
  71. MarcoFalke closed this on Aug 5, 2022

  72. sidhujag referenced this in commit 1be33625a0 on Aug 5, 2022
  73. bitcoin locked this on Aug 9, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-18 21:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me