From bbfa799f5130891fdb9632175bc254f5d01c3481 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 5 Jan 2024 19:12:09 +0800 Subject: [PATCH] multi: add more bitcoind versions to the `BackendVersion` This commit adds bitcoind version 22.0 and 25.0 to our `BackendVersion` set to handle the `testmempoolaccept` RPC calls. A unit test is added to make sure the parser works as expected. --- go.mod | 1 + go.sum | 16 +------- rpcclient/chain.go | 7 ++-- rpcclient/chain_test.go | 14 +++++-- rpcclient/infrastructure.go | 52 ++++++++++++++++++++++++-- rpcclient/infrastructure_test.go | 64 ++++++++++++++++++++++++++++++++ rpcclient/rawtransactions.go | 8 ++-- 7 files changed, 131 insertions(+), 31 deletions(-) create mode 100644 rpcclient/infrastructure_test.go diff --git a/go.mod b/go.mod index 2440ecfc9..0f52b5644 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/decred/dcrd/lru v1.0.0 + github.com/gorilla/websocket v1.5.0 github.com/jessevdk/go-flags v1.4.0 github.com/jrick/logrotate v1.0.0 github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 diff --git a/go.sum b/go.sum index ed490dc45..14ab5af62 100644 --- a/go.sum +++ b/go.sum @@ -84,20 +84,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/utreexo/utreexo v0.0.0-20240130053814-4aa282fe3804 h1:9uJDD7lEbhQ/JQhdIPVJ2yk8tLh8nvwNz87shyUe+RQ= -github.com/utreexo/utreexo v0.0.0-20240130053814-4aa282fe3804/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.0.0-20240207085148-754fd0816976 h1:1r3hZAaf7zhLd/hT4wYB8PkYOLylgCDlJaxS8MRitZA= -github.com/utreexo/utreexo v0.0.0-20240207085148-754fd0816976/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.1.0 h1:ddbIk/yU7sqZ/7Q2XoZhaeWqMBRwhHXaoFRvKYx7uLo= -github.com/utreexo/utreexo v0.1.0/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.1.2 h1:KLC8rlwPep3w9sYapEgDROYUBNmLzsO5aTPTorBJhJc= -github.com/utreexo/utreexo v0.1.2/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.1.3 h1:Z7tj8DTZNHd927ZWT7NSKx14+Dk6BoMeDPhDOmFlibo= -github.com/utreexo/utreexo v0.1.3/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.1.4 h1:jygjZscJEzab7woP7aB6YWUKjhsV5Mrbjj873inhwR8= -github.com/utreexo/utreexo v0.1.4/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= -github.com/utreexo/utreexo v0.1.5 h1:nnG2VvwDYPkXCSRicV15eAbh2vvTp/g4Pot3vlseGdQ= -github.com/utreexo/utreexo v0.1.5/go.mod h1:RT9JpZADhLr2YJVBgp48tmUxVeAHaAbOSr6p6nAEJpI= github.com/utreexo/utreexo v0.2.1 h1:xycdaHK+HhDZO5MY6Clq7YeXEDguzar1GrAYqIJ1gvs= github.com/utreexo/utreexo v0.2.1/go.mod h1:xIu3cTtT0jNdntc1qJhVyQV/RX03Sk9gFD3UAzALvuU= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -113,6 +99,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -129,6 +116,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/rpcclient/chain.go b/rpcclient/chain.go index 9b29218d5..de9305b20 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -440,17 +440,16 @@ func unmarshalPartialGetBlockChainInfoResult(res []byte) (*btcjson.GetBlockChain func unmarshalGetBlockChainInfoResultSoftForks(chainInfo *btcjson.GetBlockChainInfoResult, version BackendVersion, res []byte) error { - switch version { // Versions of bitcoind on or after v0.19.0 use the unified format. - case BitcoindPost19: + if version > BitcoindPre19 { var softForks btcjson.UnifiedSoftForks if err := json.Unmarshal(res, &softForks); err != nil { return err } chainInfo.UnifiedSoftForks = &softForks + } else { - // All other versions use the original format. - default: + // All other versions use the original format. var softForks btcjson.SoftForks if err := json.Unmarshal(res, &softForks); err != nil { return err diff --git a/rpcclient/chain_test.go b/rpcclient/chain_test.go index e32d547ce..4357f08b1 100644 --- a/rpcclient/chain_test.go +++ b/rpcclient/chain_test.go @@ -1,6 +1,12 @@ package rpcclient -import "testing" +import ( + "testing" + + "github.com/gorilla/websocket" +) + +var upgrader = websocket.Upgrader{} // TestUnmarshalGetBlockChainInfoResult ensures that the SoftForks and // UnifiedSoftForks fields of GetBlockChainInfoResult are properly unmarshaled @@ -22,7 +28,7 @@ func TestUnmarshalGetBlockChainInfoResultSoftForks(t *testing.T) { }, { name: "bitcoind >= 0.19.0 with separate softforks", - version: BitcoindPost19, + version: BitcoindPre22, res: []byte(`{"softforks": [{"version": 2}]}`), compatible: false, }, @@ -34,7 +40,7 @@ func TestUnmarshalGetBlockChainInfoResultSoftForks(t *testing.T) { }, { name: "bitcoind >= 0.19.0 with unified softforks", - version: BitcoindPost19, + version: BitcoindPre22, res: []byte(`{"softforks": {"segwit": {"type": "bip9"}}}`), compatible: true, }, @@ -76,7 +82,7 @@ func TestUnmarshalGetBlockChainInfoResultSoftForks(t *testing.T) { // If the version is compatible with the response, we // should expect to see the proper softforks field set. - if test.version == BitcoindPost19 && + if test.version == BitcoindPre22 && info.SoftForks != nil { t.Fatal("expected SoftForks to be empty") } diff --git a/rpcclient/infrastructure.go b/rpcclient/infrastructure.go index f928fe589..2b9c07474 100644 --- a/rpcclient/infrastructure.go +++ b/rpcclient/infrastructure.go @@ -114,14 +114,45 @@ const ( // BitcoindPre19 represents a bitcoind version before 0.19.0. BitcoindPre19 BackendVersion = iota - // BitcoindPost19 represents a bitcoind version equal to or greater than - // 0.19.0. - BitcoindPost19 + // BitcoindPre22 represents a bitcoind version equal to or greater than + // 0.19.0 and smaller than 22.0.0. + BitcoindPre22 + + // BitcoindPre25 represents a bitcoind version equal to or greater than + // 22.0.0 and smaller than 25.0.0. + BitcoindPre25 + + // BitcoindPre25 represents a bitcoind version equal to or greater than + // 25.0.0. + BitcoindPost25 // Btcd represents a catch-all btcd version. Btcd ) +// String returns a human-readable backend version. +func (b BackendVersion) String() string { + switch b { + case BitcoindPre19: + return "bitcoind 0.19 and below" + + case BitcoindPre22: + return "bitcoind v0.19.0-v22.0.0" + + case BitcoindPre25: + return "bitcoind v22.0.0-v25.0.0" + + case BitcoindPost25: + return "bitcoind v25.0.0 and above" + + case Btcd: + return "btcd" + + default: + return "unknown" + } +} + // Client represents a Bitcoin RPC client which allows easy access to the // various RPC methods available on a Bitcoin RPC server. Each of the wrapper // functions handle the details of converting the passed and return types to and @@ -1544,6 +1575,12 @@ const ( // bitcoind19Str is the string representation of bitcoind v0.19.0. bitcoind19Str = "0.19.0" + // bitcoind22Str is the string representation of bitcoind v22.0.0. + bitcoind22Str = "22.0.0" + + // bitcoind25Str is the string representation of bitcoind v25.0.0. + bitcoind25Str = "25.0.0" + // bitcoindVersionPrefix specifies the prefix included in every bitcoind // version exposed through GetNetworkInfo. bitcoindVersionPrefix = "/Satoshi:" @@ -1565,8 +1602,15 @@ func parseBitcoindVersion(version string) BackendVersion { switch { case version < bitcoind19Str: return BitcoindPre19 + + case version < bitcoind22Str: + return BitcoindPre22 + + case version < bitcoind25Str: + return BitcoindPre25 + default: - return BitcoindPost19 + return BitcoindPost25 } } diff --git a/rpcclient/infrastructure_test.go b/rpcclient/infrastructure_test.go new file mode 100644 index 000000000..e97fa275c --- /dev/null +++ b/rpcclient/infrastructure_test.go @@ -0,0 +1,64 @@ +package rpcclient + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestParseBitcoindVersion checks that the correct version from bitcoind's +// `getnetworkinfo` RPC call is parsed. +func TestParseBitcoindVersion(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + rpcVersion string + parsedVersion BackendVersion + }{ + { + name: "parse version 0.19 and below", + rpcVersion: "/Satoshi:0.18.0/", + parsedVersion: BitcoindPre19, + }, + { + name: "parse version 0.19", + rpcVersion: "/Satoshi:0.19.0/", + parsedVersion: BitcoindPre22, + }, + { + name: "parse version 0.19 - 22.0", + rpcVersion: "/Satoshi:0.20.1/", + parsedVersion: BitcoindPre22, + }, + { + name: "parse version 22.0", + rpcVersion: "/Satoshi:22.0.0/", + parsedVersion: BitcoindPre25, + }, + { + name: "parse version 22.0 - 25.0", + rpcVersion: "/Satoshi:23.0.0/", + parsedVersion: BitcoindPre25, + }, + { + name: "parse version 25.0", + rpcVersion: "/Satoshi:25.0.0/", + parsedVersion: BitcoindPost25, + }, + { + name: "parse version 25.0 and above", + rpcVersion: "/Satoshi:26.0.0/", + parsedVersion: BitcoindPost25, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + version := parseBitcoindVersion(tc.rpcVersion) + require.Equal(t, tc.parsedVersion, version) + }) + } +} diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index ccf11a2c0..0cad8c1f7 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -359,9 +359,8 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut } var cmd *btcjson.SendRawTransactionCmd - switch version { // Starting from bitcoind v0.19.0, the MaxFeeRate field should be used. - case BitcoindPost19: + if version > BitcoindPre19 { // Using a 0 MaxFeeRate is interpreted as a maximum fee rate not // being enforced by bitcoind. var maxFeeRate int32 @@ -369,9 +368,8 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut maxFeeRate = defaultMaxFeeRate } cmd = btcjson.NewBitcoindSendRawTransactionCmd(txHex, maxFeeRate) - - // Otherwise, use the AllowHighFees field. - default: + } else { + // Otherwise, use the AllowHighFees field. cmd = btcjson.NewSendRawTransactionCmd(txHex, &allowHighFees) }