rpcclient: Implement importmulti JSON-RPC client command
This commit is contained in:
parent
d2c0123bef
commit
fffe4a909b
5 changed files with 550 additions and 11 deletions
|
@ -7,6 +7,11 @@
|
||||||
|
|
||||||
package btcjson
|
package btcjson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// AddMultisigAddressCmd defines the addmutisigaddress JSON-RPC command.
|
// AddMultisigAddressCmd defines the addmutisigaddress JSON-RPC command.
|
||||||
type AddMultisigAddressCmd struct {
|
type AddMultisigAddressCmd struct {
|
||||||
NRequired int
|
NRequired int
|
||||||
|
@ -686,6 +691,208 @@ func NewWalletPassphraseChangeCmd(oldPassphrase, newPassphrase string) *WalletPa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimestampOrNow defines a type to represent a timestamp value in seconds,
|
||||||
|
// since epoch.
|
||||||
|
//
|
||||||
|
// The value can either be a integer, or the string "now".
|
||||||
|
//
|
||||||
|
// NOTE: Interpretation of the timestamp value depends upon the specific
|
||||||
|
// JSON-RPC command, where it is used.
|
||||||
|
type TimestampOrNow struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface for TimestampOrNow
|
||||||
|
func (t TimestampOrNow) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(t.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface for TimestampOrNow
|
||||||
|
func (t *TimestampOrNow) UnmarshalJSON(data []byte) error {
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case float64:
|
||||||
|
t.Value = int(v)
|
||||||
|
case string:
|
||||||
|
if v != "now" {
|
||||||
|
return fmt.Errorf("invalid timestamp value: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
t.Value = v
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid timestamp value: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptPubKeyAddress represents an address, to be used in conjunction with
|
||||||
|
// ScriptPubKey.
|
||||||
|
type ScriptPubKeyAddress struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptPubKey represents a script (as a string) or an address
|
||||||
|
// (as a ScriptPubKeyAddress).
|
||||||
|
type ScriptPubKey struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface for ScriptPubKey
|
||||||
|
func (s ScriptPubKey) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(s.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface for ScriptPubKey
|
||||||
|
func (s *ScriptPubKey) UnmarshalJSON(data []byte) error {
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case string:
|
||||||
|
s.Value = v
|
||||||
|
case map[string]interface{}:
|
||||||
|
s.Value = ScriptPubKeyAddress{Address: v["address"].(string)}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid scriptPubKey value: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DescriptorRange specifies the limits of a ranged Descriptor.
|
||||||
|
//
|
||||||
|
// Descriptors are typically ranged when specified in the form of generic HD
|
||||||
|
// chain paths.
|
||||||
|
// Example of a ranged descriptor: pkh(tpub.../*)
|
||||||
|
//
|
||||||
|
// The value can be an int to specify the end of the range, or the range
|
||||||
|
// itself, as []int{begin, end}.
|
||||||
|
type DescriptorRange struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface for DescriptorRange
|
||||||
|
func (r DescriptorRange) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(r.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface for DescriptorRange
|
||||||
|
func (r *DescriptorRange) UnmarshalJSON(data []byte) error {
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case float64:
|
||||||
|
r.Value = int(v)
|
||||||
|
case []interface{}:
|
||||||
|
if len(v) != 2 {
|
||||||
|
return fmt.Errorf("expected [begin,end] integer range, got: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
r.Value = []int{
|
||||||
|
int(v[0].(float64)),
|
||||||
|
int(v[1].(float64)),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid descriptor range value: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportMultiRequest defines the request struct to be passed to the
|
||||||
|
// ImportMultiCmd, as an array.
|
||||||
|
type ImportMultiRequest struct {
|
||||||
|
// Descriptor to import, in canonical form. If using Descriptor, do not
|
||||||
|
// also provide ScriptPubKey, RedeemScript, WitnessScript, PubKeys, or Keys.
|
||||||
|
Descriptor *string `json:"desc,omitempty"`
|
||||||
|
|
||||||
|
// Script/address to import. Should not be provided if using Descriptor.
|
||||||
|
ScriptPubKey *ScriptPubKey `json:"scriptPubKey,omitempty"`
|
||||||
|
|
||||||
|
// Creation time of the key in seconds since epoch (Jan 1 1970 GMT), or
|
||||||
|
// the string "now" to substitute the current synced blockchain time.
|
||||||
|
//
|
||||||
|
// The timestamp of the oldest key will determine how far back blockchain
|
||||||
|
// rescans need to begin for missing wallet transactions.
|
||||||
|
//
|
||||||
|
// Specifying "now" bypasses scanning. Useful for keys that are known to
|
||||||
|
// never have been used.
|
||||||
|
//
|
||||||
|
// Specifying 0 scans the entire blockchain.
|
||||||
|
Timestamp TimestampOrNow `json:"timestamp"`
|
||||||
|
|
||||||
|
// Allowed only if the ScriptPubKey is a P2SH or P2SH-P2WSH
|
||||||
|
// address/scriptPubKey.
|
||||||
|
RedeemScript *string `json:"redeemscript,omitempty"`
|
||||||
|
|
||||||
|
// Allowed only if the ScriptPubKey is a P2SH-P2WSH or P2WSH
|
||||||
|
// address/scriptPubKey.
|
||||||
|
WitnessScript *string `json:"witnessscript,omitempty"`
|
||||||
|
|
||||||
|
// Array of strings giving pubkeys to import. They must occur in P2PKH or
|
||||||
|
// P2WPKH scripts. They are not required when the private key is also
|
||||||
|
// provided (see Keys).
|
||||||
|
PubKeys *[]string `json:"pubkeys,omitempty"`
|
||||||
|
|
||||||
|
// Array of strings giving private keys to import. The corresponding
|
||||||
|
// public keys must occur in the output or RedeemScript.
|
||||||
|
Keys *[]string `json:"keys,omitempty"`
|
||||||
|
|
||||||
|
// If the provided Descriptor is ranged, this specifies the end
|
||||||
|
// (as an int) or the range (as []int{begin, end}) to import.
|
||||||
|
Range *DescriptorRange `json:"range,omitempty"`
|
||||||
|
|
||||||
|
// States whether matching outputs should be treated as not incoming
|
||||||
|
// payments (also known as change).
|
||||||
|
Internal *bool `json:"internal,omitempty"`
|
||||||
|
|
||||||
|
// States whether matching outputs should be considered watchonly.
|
||||||
|
//
|
||||||
|
// If an address/script is imported without all of the private keys
|
||||||
|
// required to spend from that address, set this field to true.
|
||||||
|
//
|
||||||
|
// If all the private keys are provided and the address/script is
|
||||||
|
// spendable, set this field to false.
|
||||||
|
WatchOnly *bool `json:"watchonly,omitempty"`
|
||||||
|
|
||||||
|
// Label to assign to the address. Only allowed when Internal is false.
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// States whether imported public keys should be added to the keypool for
|
||||||
|
// when users request new addresses. Only allowed when wallet private keys
|
||||||
|
// are disabled.
|
||||||
|
KeyPool *bool `json:"keypool,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportMultiRequest defines the options struct, provided to the
|
||||||
|
// ImportMultiCmd as a pointer argument.
|
||||||
|
type ImportMultiOptions struct {
|
||||||
|
Rescan bool `json:"rescan"` // Rescan the blockchain after all imports
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportMultiCmd defines the importmulti JSON-RPC command.
|
||||||
|
type ImportMultiCmd struct {
|
||||||
|
Requests []ImportMultiRequest
|
||||||
|
Options *ImportMultiOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewImportMultiCmd returns a new instance which can be used to issue
|
||||||
|
// an importmulti JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
|
// for optional parameters will use the default value.
|
||||||
|
func NewImportMultiCmd(requests []ImportMultiRequest, options *ImportMultiOptions) *ImportMultiCmd {
|
||||||
|
return &ImportMultiCmd{
|
||||||
|
Requests: requests,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// The commands in this file are only usable with a wallet server.
|
// The commands in this file are only usable with a wallet server.
|
||||||
flags := UFWalletOnly
|
flags := UFWalletOnly
|
||||||
|
@ -709,6 +916,7 @@ func init() {
|
||||||
MustRegisterCmd("getreceivedbyaddress", (*GetReceivedByAddressCmd)(nil), flags)
|
MustRegisterCmd("getreceivedbyaddress", (*GetReceivedByAddressCmd)(nil), flags)
|
||||||
MustRegisterCmd("gettransaction", (*GetTransactionCmd)(nil), flags)
|
MustRegisterCmd("gettransaction", (*GetTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("getwalletinfo", (*GetWalletInfoCmd)(nil), flags)
|
MustRegisterCmd("getwalletinfo", (*GetWalletInfoCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("importmulti", (*ImportMultiCmd)(nil), flags)
|
||||||
MustRegisterCmd("importprivkey", (*ImportPrivKeyCmd)(nil), flags)
|
MustRegisterCmd("importprivkey", (*ImportPrivKeyCmd)(nil), flags)
|
||||||
MustRegisterCmd("keypoolrefill", (*KeyPoolRefillCmd)(nil), flags)
|
MustRegisterCmd("keypoolrefill", (*KeyPoolRefillCmd)(nil), flags)
|
||||||
MustRegisterCmd("listaccounts", (*ListAccountsCmd)(nil), flags)
|
MustRegisterCmd("listaccounts", (*ListAccountsCmd)(nil), flags)
|
||||||
|
|
|
@ -1243,6 +1243,258 @@ func TestWalletSvrCmds(t *testing.T) {
|
||||||
NewPassphrase: "new",
|
NewPassphrase: "new",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with descriptor + options",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp.
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{Descriptor: btcjson.String("123"), Timestamp: btcjson.TimestampOrNow{Value: 0}},
|
||||||
|
},
|
||||||
|
`{"rescan": true}`,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{Descriptor: btcjson.String("123"), Timestamp: btcjson.TimestampOrNow{Value: 0}},
|
||||||
|
}
|
||||||
|
options := btcjson.ImportMultiOptions{Rescan: true}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, &options)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"desc":"123","timestamp":0}],{"rescan":true}],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Options: &btcjson.ImportMultiOptions{Rescan: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with descriptor + no options",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp.
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
WatchOnly: btcjson.Bool(false),
|
||||||
|
Internal: btcjson.Bool(true),
|
||||||
|
Label: btcjson.String("aaa"),
|
||||||
|
KeyPool: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
WatchOnly: btcjson.Bool(false),
|
||||||
|
Internal: btcjson.Bool(true),
|
||||||
|
Label: btcjson.String("aaa"),
|
||||||
|
KeyPool: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"desc":"123","timestamp":0,"internal":true,"watchonly":false,"label":"aaa","keypool":false}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
WatchOnly: btcjson.Bool(false),
|
||||||
|
Internal: btcjson.Bool(true),
|
||||||
|
Label: btcjson.String("aaa"),
|
||||||
|
KeyPool: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with descriptor + string timestamp",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp.
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: "now"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{Descriptor: btcjson.String("123"), Timestamp: btcjson.TimestampOrNow{Value: "now"}},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"desc":"123","timestamp":"now"}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{Descriptor: btcjson.String("123"), Timestamp: btcjson.TimestampOrNow{Value: "now"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with scriptPubKey script",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp and scriptPubKey
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: "script"},
|
||||||
|
RedeemScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
PubKeys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: "script"},
|
||||||
|
RedeemScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
PubKeys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"scriptPubKey":"script","timestamp":0,"redeemscript":"123","pubkeys":["aaa"]}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: "script"},
|
||||||
|
RedeemScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
PubKeys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with scriptPubKey address",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp and scriptPubKey
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: btcjson.ScriptPubKeyAddress{Address: "addr"}},
|
||||||
|
WitnessScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Keys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: btcjson.ScriptPubKeyAddress{Address: "addr"}},
|
||||||
|
WitnessScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Keys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"scriptPubKey":{"address":"addr"},"timestamp":0,"witnessscript":"123","keys":["aaa"]}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
ScriptPubKey: &btcjson.ScriptPubKey{Value: btcjson.ScriptPubKeyAddress{Address: "addr"}},
|
||||||
|
WitnessScript: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Keys: &[]string{"aaa"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with ranged (int) descriptor",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp.
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: 7},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: 7},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"desc":"123","timestamp":0,"range":7}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: 7},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "importmulti with ranged (slice) descriptor",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"importmulti",
|
||||||
|
// Cannot use a native string, due to special types like timestamp.
|
||||||
|
[]btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: []int{1, 7}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: []int{1, 7}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return btcjson.NewImportMultiCmd(requests, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"importmulti","params":[[{"desc":"123","timestamp":0,"range":[1,7]}]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.ImportMultiCmd{
|
||||||
|
Requests: []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String("123"),
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0},
|
||||||
|
Range: &btcjson.DescriptorRange{Value: []int{1, 7}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Running %d tests", len(tests))
|
t.Logf("Running %d tests", len(tests))
|
||||||
|
|
|
@ -173,3 +173,14 @@ type GetBalancesResult struct {
|
||||||
Mine BalanceDetailsResult `json:"mine"`
|
Mine BalanceDetailsResult `json:"mine"`
|
||||||
WatchOnly *BalanceDetailsResult `json:"watchonly"`
|
WatchOnly *BalanceDetailsResult `json:"watchonly"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImportMultiResults is a slice that models the result of the importmulti command.
|
||||||
|
//
|
||||||
|
// Each item in the slice contains the execution result corresponding to the input
|
||||||
|
// requests of type btcjson.ImportMultiRequest, passed to the ImportMulti[Async]
|
||||||
|
// function.
|
||||||
|
type ImportMultiResults []struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Error *RPCError `json:"error,omitempty"`
|
||||||
|
Warnings *[]string `json:"warnings,omitempty"`
|
||||||
|
}
|
||||||
|
|
|
@ -2,30 +2,60 @@ package rpcclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var connCfg = &ConnConfig{
|
||||||
|
Host: "localhost:8332",
|
||||||
|
User: "yourrpcuser",
|
||||||
|
Pass: "yourrpcpass",
|
||||||
|
HTTPPostMode: true,
|
||||||
|
DisableTLS: true,
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleClient_GetDescriptorInfo() {
|
func ExampleClient_GetDescriptorInfo() {
|
||||||
connCfg := &ConnConfig{
|
|
||||||
Host: "localhost:8332",
|
|
||||||
User: "yourrpcuser",
|
|
||||||
Pass: "yourrpcpass",
|
|
||||||
HTTPPostMode: true,
|
|
||||||
DisableTLS: true,
|
|
||||||
}
|
|
||||||
client, err := New(connCfg, nil)
|
client, err := New(connCfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
panic(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer client.Shutdown()
|
defer client.Shutdown()
|
||||||
|
|
||||||
descriptorInfo, err := client.GetDescriptorInfo(
|
descriptorInfo, err := client.GetDescriptorInfo(
|
||||||
"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)")
|
"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
panic(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%+v\n", descriptorInfo)
|
fmt.Printf("%+v\n", descriptorInfo)
|
||||||
// &{Descriptor:wpkh([d34db33f/84'/0'/0']0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#n9g43y4k Checksum:qwlqgth7 IsRange:false IsSolvable:true HasPrivateKeys:false}
|
// &{Descriptor:wpkh([d34db33f/84'/0'/0']0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#n9g43y4k Checksum:qwlqgth7 IsRange:false IsSolvable:true HasPrivateKeys:false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleClient_ImportMulti() {
|
||||||
|
client, err := New(connCfg, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer client.Shutdown()
|
||||||
|
|
||||||
|
requests := []btcjson.ImportMultiRequest{
|
||||||
|
{
|
||||||
|
Descriptor: btcjson.String(
|
||||||
|
"pkh([f34db33f/44'/0'/0']xpub6Cc939fyHvfB9pPLWd3bSyyQFvgKbwhidca49jGCM5Hz5ypEPGf9JVXB4NBuUfPgoHnMjN6oNgdC9KRqM11RZtL8QLW6rFKziNwHDYhZ6Kx/0/*)#ed7px9nu"),
|
||||||
|
Range: &btcjson.DescriptorRange{Value: []int{0, 100}},
|
||||||
|
Timestamp: btcjson.TimestampOrNow{Value: 0}, // scan from genesis
|
||||||
|
WatchOnly: btcjson.Bool(true),
|
||||||
|
KeyPool: btcjson.Bool(false),
|
||||||
|
Internal: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
opts := &btcjson.ImportMultiOptions{Rescan: true}
|
||||||
|
|
||||||
|
resp, err := client.ImportMulti(requests, opts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(resp[0].Success)
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|
|
@ -2203,6 +2203,44 @@ func (c *Client) ImportAddressRescan(address string, account string, rescan bool
|
||||||
return c.ImportAddressRescanAsync(address, account, rescan).Receive()
|
return c.ImportAddressRescanAsync(address, account, rescan).Receive()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FutureImportMultiResult is a future promise to deliver the result of an
|
||||||
|
// ImportMultiAsync RPC invocation (or an applicable error).
|
||||||
|
type FutureImportMultiResult chan *response
|
||||||
|
|
||||||
|
// Receive waits for the response promised by the future and returns the result
|
||||||
|
// of importing multiple addresses/scripts.
|
||||||
|
func (r FutureImportMultiResult) Receive() (btcjson.ImportMultiResults, error) {
|
||||||
|
res, err := receiveFuture(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var importMultiResults btcjson.ImportMultiResults
|
||||||
|
err = json.Unmarshal(res, &importMultiResults)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return importMultiResults, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportMultiAsync 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 ImportMulti for the blocking version and more details.
|
||||||
|
func (c *Client) ImportMultiAsync(requests []btcjson.ImportMultiRequest, options *btcjson.ImportMultiOptions) FutureImportMultiResult {
|
||||||
|
cmd := btcjson.NewImportMultiCmd(requests, options)
|
||||||
|
return c.sendCmd(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportMulti imports addresses/scripts, optionally rescanning the blockchain
|
||||||
|
// from the earliest creation time of the imported scripts.
|
||||||
|
//
|
||||||
|
// See btcjson.ImportMultiRequest for details on the requests parameter.
|
||||||
|
func (c *Client) ImportMulti(requests []btcjson.ImportMultiRequest, options *btcjson.ImportMultiOptions) (btcjson.ImportMultiResults, error) {
|
||||||
|
return c.ImportMultiAsync(requests, options).Receive()
|
||||||
|
}
|
||||||
|
|
||||||
// FutureImportPrivKeyResult is a future promise to deliver the result of an
|
// FutureImportPrivKeyResult is a future promise to deliver the result of an
|
||||||
// ImportPrivKeyAsync RPC invocation (or an applicable error).
|
// ImportPrivKeyAsync RPC invocation (or an applicable error).
|
||||||
type FutureImportPrivKeyResult chan *response
|
type FutureImportPrivKeyResult chan *response
|
||||||
|
|
Loading…
Add table
Reference in a new issue