From ffcda0f629ec79a96c41a1c7ccd4fa760d71fbe2 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 15 Aug 2025 08:37:51 +0200 Subject: [PATCH] rpcclient: add bitcoind version dependent error matching Fixes #2404. If different versions of bitcoind return different error strings, we need a way to match those as well. --- rpcclient/errors.go | 28 +++++++++++++++++++++++++++- rpcclient/errors_test.go | 8 ++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/rpcclient/errors.go b/rpcclient/errors.go index 928881f1..7bd40796 100644 --- a/rpcclient/errors.go +++ b/rpcclient/errors.go @@ -338,6 +338,23 @@ func (r BitcoindRPCErr) Error() string { return "unknown error" } +// BitcoindErrMap is a map of additional errors bitcoind can throw that are +// version dependent (e.g. versions up to v29 return the error as specified in +// `Error()` above, while versions v30 and beyond return the error as mapped +// here. We add a new map for errors that were simply renamed but have the same +// semantic meaning. New errors should be added above as new error constants. +var BitcoindErrMap = map[string]error{ + // The error message was changed in + // https://github.com/bitcoin/bitcoin/pull/33050 which will be included + // in bitcoind v30.0 and beyond. + "mempool script verify flag failed": ErrNonMandatoryScriptVerifyFlag, + + // The error message was changed in + // https://github.com/bitcoin/bitcoin/pull/33183 which will also be + // included in bitcoind v30.0 and beyond. + "block script verify flag failed": ErrScriptVerifyFlag, +} + // BtcdErrMap takes the errors returned from btcd's `testmempoolaccept` and // `sendrawtransaction` RPCs and map them to the errors defined above, which // are results from calling either `testmempoolaccept` or `sendrawtransaction` @@ -480,7 +497,7 @@ var BtcdErrMap = map[string]error{ // // NOTE: we assume neutrino shares the same error strings as btcd. func MapRPCErr(rpcErr error) error { - // Iterate the map and find the matching error. + // Iterate the btcd error map and find the matching error. for btcdErr, err := range BtcdErrMap { // Match it against btcd's error first. if matchErrStr(rpcErr, btcdErr) { @@ -488,6 +505,15 @@ func MapRPCErr(rpcErr error) error { } } + // Also check the bitcoind error map, which is used for bitcoind version + // dependent errors. + for bitcoindErr, err := range BitcoindErrMap { + // Match it against bitcoind's error. + if matchErrStr(rpcErr, bitcoindErr) { + return err + } + } + // If not found, try to match it against bitcoind's error. for i := uint32(0); i < uint32(errSentinel); i++ { err := BitcoindRPCErr(i) diff --git a/rpcclient/errors_test.go b/rpcclient/errors_test.go index e074622b..0b5428a8 100644 --- a/rpcclient/errors_test.go +++ b/rpcclient/errors_test.go @@ -61,6 +61,14 @@ func TestMatchErrStr(t *testing.T) { matchStr: "missingorspent", matched: false, }, + { + name: "new bitcoind v30 error", + bitcoindErr: errors.New( + "mempool-script-verify-flag-failed", + ), + matchStr: "mempool script verify flag failed", + matched: true, + }, } for _, tc := range testCases {