Skip to content
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

Add err match in the package chain #937

Merged
merged 3 commits into from
Jul 6, 2024

Conversation

yyforyongyu
Copy link
Collaborator

@yyforyongyu yyforyongyu commented Jul 3, 2024

Implemented the idea suggested by @Roasbeef here, we now handle the error mapping separately.

I really like this approach, as the chain backend handling is now independent of btcd. Image a case where bitcoind updates its error str someday, instead of going through the update chain btcd -> btcwallet -> lnd, we can now just update via btcwallet -> lnd. Think it's also nice to move rpcclient to btcwallet since it's a chain backend multiplexer, future PR tho.

The original PR when this was added to btcd: btcsuite/btcd#2138

This commit moves the defined errors from
[btcd/rpcclient/errors.go](https://github.com/btcsuite/btcd/blob/d881c686e61db35e332fb0309178152dac589b03/rpcclient/errors.go)
to here so it's easier to manage error matching for different backends.
@yyforyongyu yyforyongyu force-pushed the add-err-match branch 2 times, most recently from ecd01d4 to bc151ce Compare July 4, 2024 05:42
@saubyk
Copy link

saubyk commented Jul 4, 2024

cc @bhandras for review

@saubyk
Copy link

saubyk commented Jul 4, 2024

cc: @ziggie1984 for review

Copy link
Contributor

@bhandras bhandras left a comment

Choose a reason for hiding this comment

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

LGTM 🧇

chain/btcd.go Outdated

// If the backend is older than v0.24.2, we will try to match the error
// to the older version of `btcd`.
for btcdErr, matchedErr := range BtcdErrMapPre2402 {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: it could be slightly cleaner if we move this loop inside if !backend.SupportTestMempoolAccept() so that if the version is >= v0.24.2 we just return the error at the end.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah was thinking about not nesting ifs, but I guess it's cleaner so now changed.

Copy link
Contributor

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

Looks good thank you for this fix, had some questions.

}

// MapRPCErr takes an error returned from calling RPC methods from various
// chain backend and map it to an defined error here.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: various chain backends

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

cool fixed

@@ -815,3 +815,22 @@ out:
close(s.dequeueNotification)
s.wg.Done()
}

// MapRPCErr takes an error returned from calling RPC methods from various
// chain backend and map it to an defined error here. It uses the `BtcdErrMap`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: and maps it (because it relates to the error ?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea totally, now fixed!

@@ -477,6 +477,52 @@ var BtcdErrMap = map[string]error{
"max-fee-exceeded": ErrMaxFeeExceeded,
}

// BtcdErrMapPre2402 defines the error mapping for btcd versions prior to
// 0.24.2 - all the errors changed in this commit have been defined here to
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: Why did we remove this errors for the newest versions ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

they are not removed, instead, in this commit they are changed so it's easier to do error matching, as they are more "unique".

// - https://github.com/bitcoin/bitcoin/blob/master/test/functional/mempool_dust.py
// - https://github.com/bitcoin/bitcoin/blob/master/test/functional/mempool_limit.py
// - https://github.com/bitcoin/bitcoin/blob/master/src/validation.cpp
func (r RPCErr) Error() string {
Copy link
Contributor

@ziggie1984 ziggie1984 Jul 5, 2024

Choose a reason for hiding this comment

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

Q: I wonder why we don't name this error in particular bitcoind error, because it reflects the errors of this particular backend ? Calling it rpcerr, I always think this is a generalized error ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah originally it was named BitcoindRPCErr, but in reality this functions as the generalized error - when we use it in lnd, we don't check for backends, but just check against, say, chain.ErrMempoolConflict.

Ideally, we can define another set of errors and put them in a map similar to BtcdErrMap, keyed by the error string returned from bitcoind and valued by the RPCErr, which brings more symmetry. However, unless we have a very different error string returned from the chain, there's no point in doing so as in the current design, we always use the error string defined in bitcoind. In other words, this Error() needs to return something that's human-readable, and we decide to use the error string from bitcoind.

// are results from calling either `testmempoolaccept` or `sendrawtransaction`
// in `bitcoind`.
//
// Errors not mapped in `btcd`:
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: Do you mean these are particular btcd errros which exist only in btcd or the other way around ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

so these errors can be returned from btcd, but they are not mapped. so yeah they only exist in btcd.

// `CheckTransactionInputs`.
// - errors from `CalcSequenceLock`.
//
// NOTE: This is not an exhaustive list of errors, but it covers the
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm I am still a bit surprised why we are moving the error definition to the btcwallet pkg, imo they fit better into the btcd pkg, especially the btcd errors should be defined there anyways because its the official client?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

IMO it's better here. First of all, this set of newly defined error types are not btcd errors, they are RPC errors, returned by either calling sendrawtransaction or in the reject-reason field in a response returned by testmempoolaccept. When in lnd, we don't care about the specific backend, rather, we just want to get a defined error and act on it.

This means whether it's btcd, bitcoind, or neutrino, we should have a place to catch the implementation-specific errors, and "translate" them into a uniformized RPC error. chain is a good place to perform this task as it acts like a backend-multiplexer - it provides a standardized interface chain.Interface, and handles the implementation-specific logic here.

On the other hand, btcd should just be, well, btcd, an independent implementation, that's oblivious about how neutrino or bitcoind handles stuff, which is why in addition to this error handling, I also think the btcd/rpcclient should be moved here. The overall design is, that btcwallet provides multi-backend handling, and btcd just being a protocol implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Great explanation thank you

}

// If not matched, return the original error wrapped.
return fmt.Errorf("%w: %v", ErrUndefined, rpcErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: Shouldn't we wrap it the other way around or even both ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ErrUndefined is the defined type tho, so in lnd when we see chain.ErrUndefined we know it's an undefined error. On the other hand rpcErr won't have a type in this case, also we cannot use more than one %w in fmt.Errorf unfortunately.

This commit adds a new interface method `MapRPCErr` and use it in
`TestMempoolAccept` and `SendRawTransaction`.
Copy link
Contributor

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

LGTM 🔥

@yyforyongyu yyforyongyu merged commit e391a1c into btcsuite:master Jul 6, 2024
3 checks passed
@yyforyongyu yyforyongyu deleted the add-err-match branch July 6, 2024 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants