diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index d66478c305..1292e46c89 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -882,6 +882,19 @@ func NewVerifyTxOutProofCmd(proof string) *VerifyTxOutProofCmd { } } +// GetDescriptorInfoCmd defines the getdescriptorinfo JSON-RPC command. +type GetDescriptorInfoCmd struct { + Descriptor string +} + +// NewGetDescriptorInfoCmd returns a new instance which can be used to issue a +// getdescriptorinfo JSON-RPC command. +func NewGetDescriptorInfoCmd(descriptor string) *GetDescriptorInfoCmd { + return &GetDescriptorInfoCmd{ + Descriptor: descriptor, + } +} + func init() { // No special flags for commands in this file. flags := UsageFlag(0) @@ -937,4 +950,5 @@ func init() { MustRegisterCmd("verifychain", (*VerifyChainCmd)(nil), flags) MustRegisterCmd("verifymessage", (*VerifyMessageCmd)(nil), flags) MustRegisterCmd("verifytxoutproof", (*VerifyTxOutProofCmd)(nil), flags) + MustRegisterCmd("getdescriptorinfo", (*GetDescriptorInfoCmd)(nil), flags) } diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index e2b5025727..9aeac49ecb 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -1302,6 +1302,17 @@ func TestChainSvrCmds(t *testing.T) { Proof: "test", }, }, + { + name: "getdescriptorinfo", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getdescriptorinfo", "123") + }, + staticCmd: func() interface{} { + return btcjson.NewGetDescriptorInfoCmd("123") + }, + marshalled: `{"jsonrpc":"1.0","method":"getdescriptorinfo","params":["123"],"id":1}`, + unmarshalled: &btcjson.GetDescriptorInfoCmd{Descriptor: "123"}, + }, } t.Logf("Running %d tests", len(tests)) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index a96319b235..482e3d72d8 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -730,3 +730,12 @@ func (f *FundRawTransactionResult) UnmarshalJSON(data []byte) error { f.ChangePosition = rawRes.ChangePosition return nil } + +// GetDescriptorInfoResult models the data from the getdescriptorinfo command. +type GetDescriptorInfoResult struct { + Descriptor string `json:"descriptor"` // descriptor in canonical form, without private keys + Checksum string `json:"checksum"` // checksum for the input descriptor + IsRange bool `json:"isrange"` // whether the descriptor is ranged + IsSolvable bool `json:"issolvable"` // whether the descriptor is solvable + HasPrivateKeys bool `json:"hasprivatekeys"` // whether the descriptor has at least one private key +} diff --git a/rpcclient/chain.go b/rpcclient/chain.go index 9f0c6c684d..c0c6a15922 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -1224,3 +1224,44 @@ func (c *Client) GetBlockStatsAsync(hashOrHeight interface{}, stats *[]string) F func (c *Client) GetBlockStats(hashOrHeight interface{}, stats *[]string) (*btcjson.GetBlockStatsResult, error) { return c.GetBlockStatsAsync(hashOrHeight, stats).Receive() } + +// FutureGetDescriptorInfoResult is a future promise to deliver the result of a +// GetDescriptorInfoAsync RPC invocation (or an applicable error). +type FutureGetDescriptorInfoResult chan *response + +// Receive waits for the response promised by the future and returns the analysed +// info of the descriptor. +func (r FutureGetDescriptorInfoResult) Receive() (*btcjson.GetDescriptorInfoResult, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + var descriptorInfo btcjson.GetDescriptorInfoResult + err = json.Unmarshal(res, &descriptorInfo) + if err != nil { + return nil, err + } + return &descriptorInfo, nil +} + +// GetDescriptorInfoAsync returns an instance of a type that can be used to get +// the result of the RPC at some future time by invoking the Receive function on +// the returned instance. +// +// See GetDescriptorInfo for the blocking version and more details. +func (c *Client) GetDescriptorInfoAsync(descriptor string) FutureGetDescriptorInfoResult { + cmd := btcjson.NewGetDescriptorInfoCmd(descriptor) + return c.sendCmd(cmd) +} + +// GetDescriptorInfo returns the analysed info of a descriptor string, by invoking the +// getdescriptorinfo RPC. +// +// Use this function to analyse a descriptor string, or compute the checksum +// for a descriptor without one. +// +// See btcjson.GetDescriptorInfoResult for details about the result. +func (c *Client) GetDescriptorInfo(descriptor string) (*btcjson.GetDescriptorInfoResult, error) { + return c.GetDescriptorInfoAsync(descriptor).Receive() +} diff --git a/rpcclient/example_test.go b/rpcclient/example_test.go new file mode 100644 index 0000000000..c2c5290596 --- /dev/null +++ b/rpcclient/example_test.go @@ -0,0 +1,31 @@ +package rpcclient + +import ( + "fmt" +) + +func ExampleClient_GetDescriptorInfo() { + connCfg := &ConnConfig{ + Host: "localhost:8332", + User: "yourrpcuser", + Pass: "yourrpcpass", + HTTPPostMode: true, + DisableTLS: true, + } + client, err := New(connCfg, nil) + if err != nil { + log.Error(err) + return + } + defer client.Shutdown() + + descriptorInfo, err := client.GetDescriptorInfo( + "wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)") + if err != nil { + log.Error(err) + return + } + + fmt.Printf("%+v\n", descriptorInfo) + // &{Descriptor:wpkh([d34db33f/84'/0'/0']0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#n9g43y4k Checksum:qwlqgth7 IsRange:false IsSolvable:true HasPrivateKeys:false} +}