Skip to content

Commit

Permalink
rpcclient: add deriveaddresses RPC command
Browse files Browse the repository at this point in the history
  • Loading branch information
onyb authored and jcvernaleo committed Sep 14, 2020
1 parent 42782bb commit c693bd8
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 41 deletions.
98 changes: 57 additions & 41 deletions btcjson/chainsvrcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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{}

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
}
45 changes: 45 additions & 0 deletions btcjson/chainsvrcmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions btcjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
41 changes: 41 additions & 0 deletions rpcclient/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand Down
18 changes: 18 additions & 0 deletions rpcclient/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}

0 comments on commit c693bd8

Please sign in to comment.