rpcclient: add deriveaddresses RPC command

This commit is contained in:
Anirudha Bose 2020-09-13 09:47:39 +02:00 committed by John C. Vernaleo
parent 42782bba18
commit c693bd8bc5
5 changed files with 164 additions and 41 deletions

View file

@ -80,6 +80,47 @@ func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]fl
}
}
// DecodeRawTransactionCmd defines the decoderawtransaction JSON-RPC command.
type DecodeRawTransactionCmd struct {
HexTx string
}
// NewDecodeRawTransactionCmd returns a new instance which can be used to issue
// a decoderawtransaction JSON-RPC command.
func NewDecodeRawTransactionCmd(hexTx string) *DecodeRawTransactionCmd {
return &DecodeRawTransactionCmd{
HexTx: hexTx,
}
}
// DecodeScriptCmd defines the decodescript JSON-RPC command.
type DecodeScriptCmd struct {
HexScript string
}
// NewDecodeScriptCmd returns a new instance which can be used to issue a
// decodescript JSON-RPC command.
func NewDecodeScriptCmd(hexScript string) *DecodeScriptCmd {
return &DecodeScriptCmd{
HexScript: hexScript,
}
}
// DeriveAddressesCmd defines the deriveaddresses JSON-RPC command.
type DeriveAddressesCmd struct {
Descriptor string
Range *DescriptorRange
}
// NewDeriveAddressesCmd returns a new instance which can be used to issue a
// deriveaddresses JSON-RPC command.
func NewDeriveAddressesCmd(descriptor string, descriptorRange *DescriptorRange) *DeriveAddressesCmd {
return &DeriveAddressesCmd{
Descriptor: descriptor,
Range: descriptorRange,
}
}
// ChangeType defines the different output types to use for the change address
// of a transaction built by the node.
type ChangeType string
@ -124,32 +165,6 @@ func NewFundRawTransactionCmd(serializedTx []byte, opts FundRawTransactionOpts,
}
}
// DecodeRawTransactionCmd defines the decoderawtransaction JSON-RPC command.
type DecodeRawTransactionCmd struct {
HexTx string
}
// NewDecodeRawTransactionCmd returns a new instance which can be used to issue
// a decoderawtransaction JSON-RPC command.
func NewDecodeRawTransactionCmd(hexTx string) *DecodeRawTransactionCmd {
return &DecodeRawTransactionCmd{
HexTx: hexTx,
}
}
// DecodeScriptCmd defines the decodescript JSON-RPC command.
type DecodeScriptCmd struct {
HexScript string
}
// NewDecodeScriptCmd returns a new instance which can be used to issue a
// decodescript JSON-RPC command.
func NewDecodeScriptCmd(hexScript string) *DecodeScriptCmd {
return &DecodeScriptCmd{
HexScript: hexScript,
}
}
// GetAddedNodeInfoCmd defines the getaddednodeinfo JSON-RPC command.
type GetAddedNodeInfoCmd struct {
DNS bool
@ -467,6 +482,19 @@ func NewGetConnectionCountCmd() *GetConnectionCountCmd {
return &GetConnectionCountCmd{}
}
// 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,
}
}
// GetDifficultyCmd defines the getdifficulty JSON-RPC command.
type GetDifficultyCmd struct{}
@ -956,28 +984,16 @@ 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)
MustRegisterCmd("addnode", (*AddNodeCmd)(nil), flags)
MustRegisterCmd("createrawtransaction", (*CreateRawTransactionCmd)(nil), flags)
MustRegisterCmd("fundrawtransaction", (*FundRawTransactionCmd)(nil), flags)
MustRegisterCmd("decoderawtransaction", (*DecodeRawTransactionCmd)(nil), flags)
MustRegisterCmd("decodescript", (*DecodeScriptCmd)(nil), flags)
MustRegisterCmd("deriveaddresses", (*DeriveAddressesCmd)(nil), flags)
MustRegisterCmd("fundrawtransaction", (*FundRawTransactionCmd)(nil), flags)
MustRegisterCmd("getaddednodeinfo", (*GetAddedNodeInfoCmd)(nil), flags)
MustRegisterCmd("getbestblockhash", (*GetBestBlockHashCmd)(nil), flags)
MustRegisterCmd("getblock", (*GetBlockCmd)(nil), flags)
@ -993,6 +1009,7 @@ func init() {
MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags)
MustRegisterCmd("getchaintxstats", (*GetChainTxStatsCmd)(nil), flags)
MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags)
MustRegisterCmd("getdescriptorinfo", (*GetDescriptorInfoCmd)(nil), flags)
MustRegisterCmd("getdifficulty", (*GetDifficultyCmd)(nil), flags)
MustRegisterCmd("getgenerate", (*GetGenerateCmd)(nil), flags)
MustRegisterCmd("gethashespersec", (*GetHashesPerSecCmd)(nil), flags)
@ -1027,5 +1044,4 @@ func init() {
MustRegisterCmd("verifychain", (*VerifyChainCmd)(nil), flags)
MustRegisterCmd("verifymessage", (*VerifyMessageCmd)(nil), flags)
MustRegisterCmd("verifytxoutproof", (*VerifyTxOutProofCmd)(nil), flags)
MustRegisterCmd("getdescriptorinfo", (*GetDescriptorInfoCmd)(nil), flags)
}

View file

@ -220,6 +220,51 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
unmarshalled: &btcjson.DecodeScriptCmd{HexScript: "00"},
},
{
name: "deriveaddresses no range",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("deriveaddresses", "00")
},
staticCmd: func() interface{} {
return btcjson.NewDeriveAddressesCmd("00", nil)
},
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00"],"id":1}`,
unmarshalled: &btcjson.DeriveAddressesCmd{Descriptor: "00"},
},
{
name: "deriveaddresses int range",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd(
"deriveaddresses", "00", btcjson.DescriptorRange{Value: 2})
},
staticCmd: func() interface{} {
return btcjson.NewDeriveAddressesCmd(
"00", &btcjson.DescriptorRange{Value: 2})
},
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",2],"id":1}`,
unmarshalled: &btcjson.DeriveAddressesCmd{
Descriptor: "00",
Range: &btcjson.DescriptorRange{Value: 2},
},
},
{
name: "deriveaddresses slice range",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd(
"deriveaddresses", "00",
btcjson.DescriptorRange{Value: []int{0, 2}},
)
},
staticCmd: func() interface{} {
return btcjson.NewDeriveAddressesCmd(
"00", &btcjson.DescriptorRange{Value: []int{0, 2}})
},
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",[0,2]],"id":1}`,
unmarshalled: &btcjson.DeriveAddressesCmd{
Descriptor: "00",
Range: &btcjson.DescriptorRange{Value: []int{0, 2}},
},
},
{
name: "getaddednodeinfo",
newCmd: func() (interface{}, error) {

View file

@ -764,3 +764,6 @@ type GetDescriptorInfoResult struct {
IsSolvable bool `json:"issolvable"` // whether the descriptor is solvable
HasPrivateKeys bool `json:"hasprivatekeys"` // whether the descriptor has at least one private key
}
// DeriveAddressesResult models the data from the deriveaddresses command.
type DeriveAddressesResult []string

View file

@ -1263,6 +1263,45 @@ func (c *Client) GetBlockStats(hashOrHeight interface{}, stats *[]string) (*btcj
return c.GetBlockStatsAsync(hashOrHeight, stats).Receive()
}
// FutureDeriveAddressesResult is a future promise to deliver the result of an
// DeriveAddressesAsync RPC invocation (or an applicable error).
type FutureDeriveAddressesResult chan *response
// Receive waits for the response promised by the future and derives one or more addresses
// corresponding to the given output descriptor.
func (r FutureDeriveAddressesResult) Receive() (*btcjson.DeriveAddressesResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
var deriveAddressesResult btcjson.DeriveAddressesResult
err = json.Unmarshal(res, &deriveAddressesResult)
if err != nil {
return nil, err
}
return &deriveAddressesResult, nil
}
// DeriveAddressesAsync 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 DeriveAddresses for the blocking version and more details.
func (c *Client) DeriveAddressesAsync(descriptor string, descriptorRange *btcjson.DescriptorRange) FutureDeriveAddressesResult {
cmd := btcjson.NewDeriveAddressesCmd(descriptor, descriptorRange)
return c.sendCmd(cmd)
}
// DeriveAddresses derives one or more addresses corresponding to an output
// descriptor. If a ranged descriptor is used, the end or the range
// (in [begin,end] notation) to derive must be specified.
func (c *Client) DeriveAddresses(descriptor string, descriptorRange *btcjson.DescriptorRange) (*btcjson.DeriveAddressesResult, error) {
return c.DeriveAddressesAsync(descriptor, descriptorRange).Receive()
}
// FutureGetDescriptorInfoResult is a future promise to deliver the result of a
// GetDescriptorInfoAsync RPC invocation (or an applicable error).
type FutureGetDescriptorInfoResult chan *response
@ -1276,10 +1315,12 @@ func (r FutureGetDescriptorInfoResult) Receive() (*btcjson.GetDescriptorInfoResu
}
var descriptorInfo btcjson.GetDescriptorInfoResult
err = json.Unmarshal(res, &descriptorInfo)
if err != nil {
return nil, err
}
return &descriptorInfo, nil
}

View file

@ -59,3 +59,21 @@ func ExampleClient_ImportMulti() {
fmt.Println(resp[0].Success)
// true
}
func ExampleClient_DeriveAddresses() {
client, err := New(connCfg, nil)
if err != nil {
panic(err)
}
defer client.Shutdown()
addrs, err := client.DeriveAddresses(
"pkh([f34db33f/44'/0'/0']xpub6Cc939fyHvfB9pPLWd3bSyyQFvgKbwhidca49jGCM5Hz5ypEPGf9JVXB4NBuUfPgoHnMjN6oNgdC9KRqM11RZtL8QLW6rFKziNwHDYhZ6Kx/0/*)#ed7px9nu",
&btcjson.DescriptorRange{Value: []int{0, 2}})
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", addrs)
// &[14NjenDKkGGq1McUgoSkeUHJpW3rrKLbPW 1Pn6i3cvdGhqbdgNjXHfbaYfiuviPiymXj 181x1NbgGYKLeMXkDdXEAqepG75EgU8XtG]
}