8000 refactor: introduce generic 'Result' class and connect it to CreateTransaction and GetNewDestination by furszy · Pull Request #25218 · bitcoin/bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

refactor: introduce generic 'Result' class and connect it to CreateTransaction and GetNewDestination #25218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 12, 2022

Conversation

furszy
Copy link
Member
@furszy furszy commented May 25, 2022

Based on a common function signature pattern that we have all around the sources:

bool doSomething(arg1, arg2, arg3, arg4, &result_obj, &error_string) {
    // do something...
    if (error) {
        error_string = "something bad happened";
        return false;
    }

    result = goodResult;
    return true;
}

Introduced a generic class BResult that encapsulate the function boolean result, the result object (in case of having it) and, in case of failure, the string error reason.

Obtaining in this way cleaner function signatures and removing boilerplate code:

BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
    // do something...
    if (error) return "something bad happened";

    return goodResult;
}

Same cleanup applies equally to the function callers' side as well. There is no longer need to add the error string and the result object declarations before calling the function:

Before:

Obj result_obj;
std::string error_string;
if (!doSomething(arg1, arg2, arg3, arg4, result_obj, error_string)) {
    LogPrintf("Error: %s", error_string);
}
return result_obj;

Now:

BResult<Obj> op_res = doSomething(arg1, arg2, arg3, arg4);
if (!op_res) {
    LogPrintf("Error: %s", op_res.GetError());
}
return op_res.GetObjResult();

Initial Implementation:

Have connected this new concept to two different flows for now:

  1. The CreateTransaction flow. --> 7ba2b87
  2. The GetNewDestination flow. --> bcee091

Happy note: even when introduced a new class into the sources, the amount of lines removed is almost equal to added ones :).

Extra note: this work is an extended version (and a decoupling) of the work that is inside #24845 (which does not contain the GetNewDestination changes nor the inclusion of the FeeCalculation field inside CreatedTransactionResult).

@furszy furszy changed the title wallet: introduce generic 'Result' classes and connect it to CreateTransaction and GetNewDestination wallet: introduce generic 'Result' classes and connect it to CreateTransaction and GetNewDestination May 25, 2022
@furszy furszy force-pushed the 2022_generic_result branch from 914e095 to a19f1dc Compare May 25, 2022 22:32
@furszy furszy changed the title wallet: introduce generic 'Result' classes and connect it to CreateTransaction and GetNewDestination refactor: introduce generic 'Result' classes and connect it to CreateTransaction and GetNewDestination May 26, 2022
@theStack
Copy link
Contributor

Concept ACK

@DrahtBot
Copy link
Contributor
DrahtBot commented May 26, 2022

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #25526 (wallet: avoid double keypool TopUp() calls on descriptor wallets by furszy)
  • #25297 (WIP, wallet: speedup transactions sync, rescan and load not flushing to db constantly 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)
  • #25234 (bench: add benchmark for wallet 'AvailableCoins' function. by furszy)
  • #24897 ([Draft / POC] Silent Payments by w0xlt)
  • #23444 (fuzz: Add regression test for wallet crash by MarcoFalke)
  • #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.

@furszy
Copy link
Member Author
furszy commented May 27, 2022

rebased, conflicts solved.

@furszy furszy force-pushed the 2022_generic_result branch from d9ffeab to 043714c Compare May 27, 2022 13:23
@furszy furszy changed the title refactor: introduce generic 'Result' classes and connect it to CreateTransaction and GetNewDestination refactor: introduce generic 'Result' classes and connect them to CreateTransaction and GetNewDestination May 28, 2022
Copy link
Contributor
@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach ACK

@ryanofsky
Copy link
Contributor

This basically seems like a good design.

In the simple case, you call a function and it can either succeed or fail, and if it fails it will provide an error string. In this case, the function returns OperationResult which contains the information packaged up in a standard format.

In the slightly more complicated case, the function has a return value. Maybe it's an informational return value, or maybe it's a return value with details about errors if the caller needs to handle different errors in different ways. Either way, CallResult<T> can package up the result type with the error string, and return the information a standard format.

Some design questions / things I'm not sure about:

  • Can OperationResult bool m_res member be dropped? It seems like just having a single std::optional<bilingual_str> m_error member without the bool would provide a more minimal and unambiguous version of that class. Treating nullopt case as success, and non-nullopt case as error would avoid the need for the bool.

  • Maybe OperationResult type should be replaced with CallResult<void>, just have one result class instead of two classes

  • Maybe result classes should provide a standard way to chain errors. If some inner function returns an error string, the caller might want to add its own error string placing the error in context. I think we also have some wallet code that returns lists of warnings and lists of errors, so it's not clear if this result classes here would want to expand to handle this kind of thing, or they should just focus on simple cases.

No need to resolve these questions to merge the PR, I think. Can add result classes now, and experiment with using them, and add/remove features as needed.

@laanwj
Copy link
Member
laanwj commented Jun 16, 2022

Concept ACK. I like this rust-inspired idea.
One additional idea might be to parametrize Result on both the result and error type (in case it is not always a string).

@maflcko
Copy link
Member
maflcko commented Jun 17, 2022

I also wonder why this needs three members and 6 constructors. Can this be implemented in less code by just using a std::variant with two types?

Going to the extreme, with just two lines of code:

template <typename Obj, typename Err>
using CallResult = std::variant<Obj, Err>;

achow101 added a commit that referenced this pull request Jun 17, 2022
…everal code cleanups.

fd5c996 wallet: GetAvailableBalance, remove double walk-through every available coin (furszy)
162d4ad wallet: add 'only_spendable' filter to AvailableCoins (furszy)
cdf185c wallet: remove unused IsSpentKey(hash, index) method (furszy)
4b83bf8 wallet: avoid extra IsSpentKey -> GetWalletTx lookups (furszy)
3d8a282 wallet: decouple IsSpentKey(scriptPubKey) from IsSpentKey(hash, n) (furszy)
a06fa94 wallet: IsSpent, 'COutPoint' arg instead of (hash, index) (furszy)
91902b7 wallet: IsLockedCoin, 'COutPoint' arg instead of (hash, index) (furszy)
9472ca0 wallet: AvailableCoins, don't call 'wtx.tx->vout[i]' multiple times (furszy)
4ce235e wallet: return 'CoinsResult' struct in `AvailableCoins` (furszy)

Pull request description:

  This started in #24845<
8000
/a> but grew out of scope of it.

  So, points tackled:

  1) Avoid extra `GetWalletTx` lookups inside `AvailableCoins -> IsSpentKey`.
      `IsSpentKey` was receiving the tx hash and index to internally lookup the tx inside the wallet's map. As all the `IsSpentKey` function callers already have the wtx available, them can provide the `scriptPubKey` directly.

  2) Most of the time, we call `Wallet::AvailableCoins`, and later on the process, skip the non-spendable coins from the result in subsequent for-loops. So to speedup the process: introduced the ability to filter by "only_spendable" coins inside `Wallet::AvailableCoins` directly.
  (the non-spendable coins skip examples are inside `AttemptSelection->GroupOutputs` and `GetAvailableBalance`).

  4) Refactored `AvailableCoins` in several ways:

     a) Now it will return a new struct `CoinsResult` instead of receiving the vCoins vector reference (which was being cleared at the beginning of the method anyway). --> this is coming from #24845 but cherry-picked it here too to make the following commits look nicer.

     b) Unified all the 'wtx.tx->vout[I]' calls into a single call (coming from this comment #24699 (comment)).

  5) The wallet `IsLockedCoin` and `IsSpent` methods now accept an `OutPoint` instead of a hash:index. Which let me cleanup a bunch of extra code.

  6) Speeded up the wallet 'GetAvailableBalance': filtering `AvailableCoins` by spendable outputs only and using the 'AvailableCoins' retrieved `total_amount` instead of looping over all the retrieved coins once more.

  -------------------------------------------------------

  Side topic, all this process will look even nicer with #25218

ACKs for top commit:
  achow101:
    ACK fd5c996
  brunoerg:
    crACK fd5c996
  w0xlt:
    Code Review ACK fd5c996

Tree-SHA512: 376a85476f907f4f7d1fc3de74b3dbe159b8cc24687374d8739711ad202ea07a33e86f4e66dece836da3ae6985147119fe584f6e672f11d0450ba6bd165b3220
@furszy
Copy link
Member Author
furszy commented Jul 8, 2022

Thanks @w0xlt for the review!

The CI has an error, but the error message does not match the current PR code.
wallet.GetNewDestination(OutputType::BECH32, "", destination, error); was replaced in 26288ac

Good eye. Seems that it's a silent conflict with master due #24924 merge. Going to rebase it once more.

@furszy furszy force-pushed the 2022_generic_result branch from 26288ac to 2ad9f01 Compare July 8, 2022 12:31
@furszy
Copy link
Member Author
furszy commented Jul 8, 2022

All green now, ready to go.

furszy added 4 commits July 8, 2022 11:18
Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.

This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
return object and another ref for the error string. We can simply return a 'BResult<Obj>'.

Example of what we currently have:
```
bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
    do something...
    if (error) {
        error_string = "something bad happened";
        return false;
    }

    result = goodResult;
    return true;
}
```

Example of what we will get with this commit:
```
BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
    do something...
    if (error) return {"something happened"};

    // good
    return {goodResult};
}
```

This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
pre-function-call error string and result object declarations to pass the references to the function.
@furszy furszy force-pushed the 2022_generic_result branch from 2ad9f01 to 111ea3a Compare July 8, 2022 14:23
@furszy
Copy link
Member Author
furszy commented Jul 8, 2022

Rebased once more to include the recently merged #25337 here as well.

w0xlt
w0xlt 8000 approved these changes Jul 8, 2022
Copy link
Contributor
@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK 111ea3a

Copy link
Contributor
@theStack theStack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 111ea3a

@achow101
Copy link
Member

ACK 111ea3a

Copy link
Member
@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review ACK 111ea3a 🎏

Show signature

Signature:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

review ACK 111ea3ab711414236f8678566a7884d48619b2d8 🎏
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
pUjrYAv9ELJ7MVWMc6ec+xuvKeVMTZllPyJE0En9XpOhlJO5/icp4mlsxbVZeAN9
9Hr5KE5gDE1YFWsBfIj/SAFVLURDx0vwZkCwcxqD8IsZL7PzZN8wUrnvJVgnL8FD
ul16AsIY7iy7JJabgdfBKOcSP8TMzma3xmKRZdOHtXwy33krjvVRT9fIj+04Lb3R
R3ODVlNZg4SQY3oZPBG06XhkBoSroU4mrYnE6BEYWG1iEYlJQ1n3Ivx9qNwweGWt
EDtHF9idu/pZJXS8aVzXZLjaLq/ALoLzvy9mtHVUv+OqOQ/Cvj/jfzhfm5CancE7
idf0Ku0bEO7NvxBQ90MUudnVZb3DSOcWpPZOGOv2lYdFq96eYF0TXPe8527NsM6O
CGikleM5JmI0Do/RAzvASiJmdnktFspCVXnl8Pto1I62LdMJDwnRKVU4/itvMyAn
swH8m6dRuX/Kn8bbzSdHKvCxx5fACxAyp2/sa/BD1IEkLq1VUFWrkbBu7PSw7QC4
K4XqkLYm
=SbFr
-----END PGP SIGNATURE-----

A3E2
bool HasRes() const { return std::holds_alternative<T>(m_variant); }

/* In case of success, the result object */
const T& GetObj() const {
Copy link
Member
@maflcko maflcko Jul 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be good to add a mutable getter, so that the result can be de-capsulated by the caller

Edit: Fixed in #25594

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also LIFETIMEBOUND?

}

/* In case of failure, the error cause */
const bilingual_str& GetError() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be annotated with LIFETIMEBOUND as it is returning a pointer to internal memory?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diff to reproduce use-after-free with asan:

diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index fda56ccff7..2abf2db298 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -4,6 +4,7 @@
 
 #include <util/system.h>
 
+#include <util/result.h>
 #include <clientversion.h>
 #include <fs.h>
 #include <hash.h> // For Hash()
@@ -2659,6 +2660,13 @@ BOOST_AUTO_TEST_CASE(message_hash)
     BOOST_CHECK_NE(message_hash1, signature_hash);
 }
 
+BOOST_AUTO_TEST_CASE(bresult)
+{
+  const auto& long_str{"Looooooooooooooooooooooooooooooooooooooooooooooooong string"};
+  const auto& err{BResult<int>{Untranslated(long_str)}.GetError()};
+  BOOST_CHECK_EQUAL(err.original, long_str);
+}
+
 BOOST_AUTO_TEST_CASE(remove_prefix)
 {
     BOOST_CHECK_EQUAL(RemovePrefix("./util/system.h", "./"), "util/system.h");

With the warning added:

diff --git a/src/util/result.h b/src/util/result.h
index dcf5edaa5b..18364b3c6e 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -6,6 +6,8 @@
 #define BITCOIN_UTIL_RESULT_H
 
 #include <util/translation.h>
+#include <attributes.h>
+
 #include <variant>
 
 /*
@@ -32,7 +34,7 @@ public:
     }
 
     /* In case of failure, the error cause */
-    const bilingual_str& GetError() const {
+    const bilingual_str& GetError() const LIFETIMEBOUND {
         assert(!HasRes());
         return std::get<bilingual_str>(m_variant);
     }

Results in:

test/util_tests.cpp:2666:19: warning: temporary bound to local reference 'err' will be destroyed at the end of the full-expression [-Wdangling]
  const auto& err{BResult<int>{Untranslated(long_str)}.GetError()};
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.



@@ -964,7 +962,7 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
feeCalc.est.fail.start, feeCalc.est.fail.end,
(feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0,
feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut);
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use {} to clarify that this is not a function and to enable narrowing warnings for the int types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MarcoFalke Use {} where? You mean CreatedTransactionResult{tx, nFeeRet, nChangePosInOut, feeCalc} instead of current version?


auto& newTx = transaction.getWtx();
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while touching this line: clang-tidy named args are of the format /*sign=*/

std::optional<CreatedTransactionResult> txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, error2, tmp_cc, sign);
auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
// Helper optional class for now
std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes() ? std::make_optional(res_tx_grouped.GetObj()) : std::nullopt};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit could use std::move here, if the mutable BResult interface is implemented

Comment on lines +50 to +51
const auto& dest = wallet.GetNewDestination(OutputType::BECH32, "");
assert(dest.HasRes());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could write shorter as const CTxDestination& dest{Assert(wallet.GetNewDestination(OutputType::BECH32, "")).GetObj()};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually nvm. This would likely be a use-after-free.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there could be a ReleaseObj helper to obtain the ownership?

@maflcko maflcko merged commit 316afb1 into bitcoin:master Jul 12, 2022
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jul 12, 2022
* (in case of success) or propagating the error cause.
*/
template<class T>
class BResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does that B means at the beginning of class name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comes from "Bilingual". The story behind it is in the last paragraph of this comment: #25218 (comment)

@@ -964,7 +962,7 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
feeCalc.est.fail.start, feeCalc.est.fail.end,
(feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0,
feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut);
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MarcoFalke Use {} where? You mean CreatedTransactionResult{tx, nFeeRet, nChangePosInOut, feeCalc} instead of current version?

@Riahiamirreza
Copy link
Contributor

I think this PR can have Good first review label. For someone like me which is very new to the project, understanding the concept and implementation of this PR was easy (relative to other PRs).

@maflcko
Copy link
Member
maflcko commented Aug 2, 2022

There is a follow-up in case anyone wants to review it: #25721

maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Aug 10, 2022
…om `GetReservedDestination` methods

76b3c37 refactor: wallet: return util::Result from `GetReservedDestination` methods (Sebastian Falbesoner)

Pull request description:

  This PR is a follow-up to #25218, as suggested in comment bitcoin/bitcoin#25218 (comment). The interfaces of the methods `ReserveDestination::GetReservedDestination`, `{Legacy,Descriptor,}ScriptPubKeyMan::GetReservedDestination` are improved by returning `util::Result<CTxDestination>` instead of `bool` in order to get rid of the two `CTxDestination&` and `bilingual_str&` out-parameters.

ACKs for top commit:
  furszy:
    ACK 76b3c37

Tree-SHA512: bf15560a88d645bcf8768024013d36012cd65caaa4a613e8a055dfd8f29cb4a219c19084606992bad177920cdca3a732ec168e9b9526f9295491f2cf79cc6815
@furszy furszy deleted the 2022_generic_result branch May 27, 2023 01:51
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Dec 15, 2023
Summary:
> Useful to encapsulate the function result object (in case of having it) or, in case of failure, the failure reason.
>
> This let us clean lot of boilerplate code, as now instead of returning a boolean and having to add a ref arg for the
> return object and another ref for the error string. We can simply return a 'BResult<Obj>'.
>
> Example of what we currently have:
> ```
> bool doSomething(arg1, arg2, arg3, arg4, &result, &error_string) {
>     do something...
>     if (error) {
>         error_string = "something bad happened";
>         return false;
>     }
>
>     result = goodResult;
>     return true;
> }
> ```
>
> Example of what we will get with this commit:
> ```
> BResult<Obj> doSomething(arg1, arg2, arg3, arg4) {
>     do something...
>     if (error) return {"something happened"};
>
>     // good
>     return {goodResult};
> }
> ```
>
> This allows a similar boilerplate cleanup on the function callers side as well. They don't have to add the extra
> pre-function-call error string and result object declarations to pass the references to the function.

bitcoin/bitcoin@7a45c33

----

> Prepare BResult for non-copyable types

bitcoin/bitcoin@fa8de09

----

> 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 bitcoin/bitcoin#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.

bitcoin/bitcoin@a23cca5

----

> util: Add void support to util::Result
>
> A minimal (but hacky) way to add support for void to Result
> originally posted bitcoin/bitcoin#27632 (comment)

bitcoin/bitcoin@5f49cb1

----

This is a partial backport of [[bitcoin/bitcoin#25218 | core#25218]], [[bitcoin/bitcoin#25594 | core#25594]], [[bitcoin/bitcoin#25721 | core#25721]] and [[bitcoin/bitcoin#25977 | core#25977]]

The wallet use cases in the first 3 pull requests are not yet applicable to Bitcoin ABC due to missing dependencies.
The `std::optional<bilingual_str>` use cases from [[bitcoin/bitcoin#25977 | core#25977]] will be backported in their own diff.

Test Plan: `ninja && ninja check`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D14991
@bitcoin bitcoin locked and limited conversation to collaborators May 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0