Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpcclient: implement getwalletinfo command #1638

Merged
merged 1 commit into from
Sep 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
rpcclient: implement getwalletinfo command
  • Loading branch information
onyb committed Sep 21, 2020
commit 7377f00847169ff52bd2a804b71b279800c2a5db
54 changes: 54 additions & 0 deletions btcjson/walletsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package btcjson

import (
"encoding/json"
"fmt"

"github.com/btcsuite/btcd/txscript"
)

Expand Down Expand Up @@ -150,6 +152,58 @@ type GetTransactionResult struct {
Hex string `json:"hex"`
}

type ScanningOrFalse struct {
Value interface{}
}

type ScanProgress struct {
Duration int `json:"duration"`
Progress float64 `json:"progress"`
}

// MarshalJSON implements the json.Marshaler interface
func (h ScanningOrFalse) MarshalJSON() ([]byte, error) {
return json.Marshal(h.Value)
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (h *ScanningOrFalse) UnmarshalJSON(data []byte) error {
var unmarshalled interface{}
if err := json.Unmarshal(data, &unmarshalled); err != nil {
return err
}

switch v := unmarshalled.(type) {
case bool:
h.Value = v
case map[string]interface{}:
h.Value = ScanProgress{
Duration: int(v["duration"].(float64)),
Progress: v["progress"].(float64),
}
default:
return fmt.Errorf("invalid scanning value: %v", unmarshalled)
}

return nil
}

// GetWalletInfoResult models the result of the getwalletinfo command.
type GetWalletInfoResult struct {
WalletName string `json:"walletname"`
WalletVersion int `json:"walletversion"`
TransactionCount int `json:"txcount"`
KeyPoolOldest int `json:"keypoololdest"`
KeyPoolSize int `json:"keypoolsize"`
KeyPoolSizeHDInternal *int `json:"keypoolsize_hd_internal,omitempty"`
UnlockedUntil *int `json:"unlocked_until,omitempty"`
PayTransactionFee float64 `json:"paytxfee"`
HDSeedID *string `json:"hdseedid,omitempty"`
PrivateKeysEnabled bool `json:"private_keys_enabled"`
AvoidReuse bool `json:"avoid_reuse"`
Scanning ScanningOrFalse `json:"scanning"`
}

// InfoWalletResult models the data returned by the wallet server getinfo
// command.
type InfoWalletResult struct {
Expand Down
47 changes: 47 additions & 0 deletions btcjson/walletsvrresults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,50 @@ func TestGetAddressInfoResult(t *testing.T) {
}
}
}

// TestGetWalletInfoResult ensures that custom unmarshalling of
// GetWalletInfoResult works as intended.
func TestGetWalletInfoResult(t *testing.T) {
t.Parallel()

tests := []struct {
name string
result string
want GetWalletInfoResult
}{
{
name: "GetWalletInfoResult - not scanning",
result: `{"scanning":false}`,
want: GetWalletInfoResult{
Scanning: ScanningOrFalse{Value: false},
},
},
{
name: "GetWalletInfoResult - scanning",
result: `{"scanning":{"duration":10,"progress":1.0}}`,
want: GetWalletInfoResult{
Scanning: ScanningOrFalse{
Value: ScanProgress{Duration: 10, Progress: 1.0},
},
},
},
}

t.Logf("Running %d tests", len(tests))
for i, test := range tests {
var out GetWalletInfoResult
err := json.Unmarshal([]byte(test.result), &out)
if err != nil {
t.Errorf("Test #%d (%s) unexpected error: %v", i,
test.name, err)
continue
}

if !reflect.DeepEqual(out, test.want) {
t.Errorf("Test #%d (%s) unexpected unmarshalled data - "+
"got %v, want %v", i, test.name, spew.Sdump(out),
spew.Sdump(test.want))
continue
}
}
}
26 changes: 18 additions & 8 deletions rpcclient/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,6 @@ func ExampleClient_DeriveAddresses() {
}

func ExampleClient_GetAddressInfo() {
connCfg = &ConnConfig{
Host: "localhost:18332",
User: "user",
Pass: "pass",
HTTPPostMode: true,
DisableTLS: true,
}

client, err := New(connCfg, nil)
if err != nil {
panic(err)
Expand All @@ -106,3 +98,21 @@ func ExampleClient_GetAddressInfo() {
fmt.Println(*info.HDKeyPath) // m/49'/1'/0'/0/4
fmt.Println(info.Embedded.Address) // tb1q3x2h2kh57wzg7jz00jhwn0ycvqtdk2ane37j27
}

func ExampleClient_GetWalletInfo() {
client, err := New(connCfg, nil)
if err != nil {
panic(err)
}
defer client.Shutdown()

info, err := client.GetWalletInfo()
if err != nil {
panic(err)
}

fmt.Println(info.WalletVersion) // 169900
fmt.Println(info.TransactionCount) // 22
fmt.Println(*info.HDSeedID) // eb44e4e9b864ef17e7ba947da746375b000f5d94
fmt.Println(info.Scanning.Value) // false
}
36 changes: 35 additions & 1 deletion rpcclient/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2573,10 +2573,44 @@ func (c *Client) WalletProcessPsbt(
return c.WalletProcessPsbtAsync(psbt, sign, sighashType, bip32Derivs).Receive()
}

// FutureGetWalletInfoResult is a future promise to deliver the result of an
// GetWalletInfoAsync RPC invocation (or an applicable error).
type FutureGetWalletInfoResult chan *response

// Receive waits for the response promised by the future and returns the result
// of wallet state info.
func (r FutureGetWalletInfoResult) Receive() (*btcjson.GetWalletInfoResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}

var getWalletInfoResult btcjson.GetWalletInfoResult
err = json.Unmarshal(res, &getWalletInfoResult)
if err != nil {
return nil, err
}
return &getWalletInfoResult, nil
}

// GetWalletInfoAsync 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 GetWalletInfo for the blocking version and more details.
func (c *Client) GetWalletInfoAsync() FutureGetWalletInfoResult {
cmd := btcjson.NewGetWalletInfoCmd()
return c.sendCmd(cmd)
}

// GetWalletInfo returns various wallet state info.
func (c *Client) GetWalletInfo() (*btcjson.GetWalletInfoResult, error) {
return c.GetWalletInfoAsync().Receive()
}

// TODO(davec): Implement
// backupwallet (NYI in btcwallet)
// encryptwallet (Won't be supported by btcwallet since it's always encrypted)
// getwalletinfo (NYI in btcwallet or btcjson)
// listaddressgroupings (NYI in btcwallet)
// listreceivedbyaccount (NYI in btcwallet)

Expand Down