diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 22552e7bcd..c0f4638084 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -225,6 +225,15 @@ func NewGetBlockChainInfoCmd() *GetBlockChainInfoCmd { return &GetBlockChainInfoCmd{} } +// GetIndexInfoCmd defines the getindexinfo JSON-RPC command. +type GetIndexInfoCmd struct{} + +// NewGetIndexInfoCmd returns a new instance which can be used to issue a +// getindexinfo JSON-RPC command. +func NewGetIndexInfoCmd() *GetIndexInfoCmd { + return &GetIndexInfoCmd{} +} + // GetBlockCountCmd defines the getblockcount JSON-RPC command. type GetBlockCountCmd struct{} diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 433bdda8eb..c39d023fc8 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -242,6 +242,16 @@ type GetBlockChainInfoResult struct { *UnifiedSoftForks } +// GetIndexInfoResult models the data returned from the getindexinfo command. +type GetIndexInfoResult struct { + *TxIndex `json:"txindex,omitempty"` +} + +type TxIndex struct { + Synced bool `json:"synced"` + BestBlockHeight int32 `json:"best_block_height"` +} + // GetBlockFilterResult models the data returned from the getblockfilter // command. type GetBlockFilterResult struct { diff --git a/rpcclient/chain.go b/rpcclient/chain.go index c8562b8e65..a44379ea0f 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -507,6 +507,59 @@ func (c *Client) GetBlockChainInfo() (*btcjson.GetBlockChainInfoResult, error) { return c.GetBlockChainInfoAsync().Receive() } +// FutureGetIndexInfoResult is a promise to deliver the result of a +// GetIndexInfoAsync RPC invocation (or an applicable error). +type FutureGetIndexInfoResult struct { + client *Client + Response chan *Response +} + +// unmarshalPartialGetIndexInfoResult unmarshals the response into an +// instance of GetIndexInfoResult without populating the SoftForks and +// UnifiedSoftForks fields. +func unmarshalPartialGetIndexInfoResult(res []byte) (*btcjson.GetIndexInfoResult, error) { + var indexInfo btcjson.GetIndexInfoResult + if err := json.Unmarshal(res, &indexInfo); err != nil { + return nil, err + } + return &indexInfo, nil +} + +// Receive waits for the Response promised by the future and returns chain info +// result provided by the server. +func (r FutureGetIndexInfoResult) Receive() (*btcjson.GetIndexInfoResult, error) { + res, err := ReceiveFuture(r.Response) + if err != nil { + return nil, err + } + indexInfo, err := unmarshalPartialGetIndexInfoResult(res) + if err != nil { + return nil, err + } + + return indexInfo, nil +} + +// GetIndexInfoAsync 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 GetIndexInfo for the blocking version and more details. +func (c *Client) GetIndexInfoAsync() FutureGetIndexInfoResult { + cmd := btcjson.NewGetIndexInfoCmd() + return FutureGetIndexInfoResult{ + client: c, + Response: c.SendCmd(cmd), + } +} + +// GetIndexInfo returns information related to the processing state of +// various chain-specific details such as the current difficulty from the tip +// of the main chain. +func (c *Client) GetIndexInfo() (*btcjson.GetIndexInfoResult, error) { + return c.GetIndexInfoAsync().Receive() +} + // FutureGetBlockFilterResult is a future promise to deliver the result of a // GetBlockFilterAsync RPC invocation (or an applicable error). type FutureGetBlockFilterResult chan *Response diff --git a/rpcclient/chain_test.go b/rpcclient/chain_test.go index ad1fb7aa2a..6d3e0315a9 100644 --- a/rpcclient/chain_test.go +++ b/rpcclient/chain_test.go @@ -103,6 +103,64 @@ func TestUnmarshalGetBlockChainInfoResultSoftForks(t *testing.T) { } } +// TestUnmarshalGetIndexInfoResult ensures that the Txindex of GetIndexInfoResult +// are properly unmarshaled. +func TestUnmarshalGetIndexInfoResult(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + res []byte + enabled bool + blockHeight int32 + }{ + { + name: "txindex synced and best block height valid", + res: []byte(`{"txindex": {"synced": true, "best_block_height": 3522710}}`), + enabled: true, + blockHeight: 3522710, + }, + { + name: "txindex not enabled", + res: []byte(`{}`), + enabled: false, + blockHeight: 0, + }, + } + + for _, test := range tests { + success := t.Run(test.name, func(t *testing.T) { + // We'll start by unmarshalling the JSON into a struct. + // The SoftForks and UnifiedSoftForks field should not + // be set yet, as they are unmarshaled within a + // different function. + info, err := unmarshalPartialGetIndexInfoResult(test.res) + if err != nil { + t.Fatal(err) + } + + if test.enabled { + if info.TxIndex == nil { + t.Fatalf("unable to unmarshal txindex: %v", err) + } + if info.TxIndex.Synced == false { + t.Fatalf("expected TxIndex.Synced to be true") + } + if info.TxIndex.BestBlockHeight != test.blockHeight { + t.Fatalf("expected TxIndex.BestBlockHeight to be equal") + } + } else { + if info.TxIndex != nil { + t.Fatalf("expected TxIndex to be empty") + } + } + }) + if !success { + return + } + } +} + func TestFutureGetBlockCountResultReceiveErrors(t *testing.T) { responseChan := FutureGetBlockCountResult(make(chan *Response)) response := Response{