diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go
index 031eafd6..90ab70ec 100644
--- a/btcjson/chainsvrcmds.go
+++ b/btcjson/chainsvrcmds.go
@@ -191,6 +191,50 @@ func NewGetBlockHeaderCmd(hash string, verbose *bool) *GetBlockHeaderCmd {
 	}
 }
 
+// HashOrHeight defines a type that can be used as hash_or_height value in JSON-RPC commands.
+type HashOrHeight struct {
+	Value interface{}
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (h HashOrHeight) MarshalJSON() ([]byte, error) {
+	return json.Marshal(h.Value)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface
+func (h *HashOrHeight) UnmarshalJSON(data []byte) error {
+	var unmarshalled interface{}
+	if err := json.Unmarshal(data, &unmarshalled); err != nil {
+		return err
+	}
+
+	switch v := unmarshalled.(type) {
+	case float64:
+		h.Value = int(v)
+	case string:
+		h.Value = v
+	default:
+		return fmt.Errorf("invalid hash_or_height value: %v", unmarshalled)
+	}
+
+	return nil
+}
+
+// GetBlockStatsCmd defines the getblockstats JSON-RPC command.
+type GetBlockStatsCmd struct {
+	HashOrHeight HashOrHeight
+	Stats        *[]string
+}
+
+// NewGetBlockStatsCmd returns a new instance which can be used to issue a
+// getblockstats JSON-RPC command. Either height or hash must be specified.
+func NewGetBlockStatsCmd(hashOrHeight HashOrHeight, stats *[]string) *GetBlockStatsCmd {
+	return &GetBlockStatsCmd{
+		HashOrHeight: hashOrHeight,
+		Stats:        stats,
+	}
+}
+
 // TemplateRequest is a request object as defined in BIP22
 // (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an
 // pointer argument to GetBlockTemplateCmd.
@@ -798,6 +842,7 @@ func init() {
 	MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags)
 	MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags)
 	MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags)
+	MustRegisterCmd("getblockstats", (*GetBlockStatsCmd)(nil), flags)
 	MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags)
 	MustRegisterCmd("getcfilter", (*GetCFilterCmd)(nil), flags)
 	MustRegisterCmd("getcfilterheader", (*GetCFilterHeaderCmd)(nil), flags)
diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go
index a861af1a..dca23328 100644
--- a/btcjson/chainsvrcmds_test.go
+++ b/btcjson/chainsvrcmds_test.go
@@ -228,6 +228,60 @@ func TestChainSvrCmds(t *testing.T) {
 				Verbose: btcjson.Bool(true),
 			},
 		},
+		{
+			name: "getblockstats height",
+			newCmd: func() (interface{}, error) {
+				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123})
+			},
+			staticCmd: func() interface{} {
+				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, nil)
+			},
+			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123],"id":1}`,
+			unmarshalled: &btcjson.GetBlockStatsCmd{
+				HashOrHeight: btcjson.HashOrHeight{Value: 123},
+			},
+		},
+		{
+			name: "getblockstats hash",
+			newCmd: func() (interface{}, error) {
+				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"})
+			},
+			staticCmd: func() interface{} {
+				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, nil)
+			},
+			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef"],"id":1}`,
+			unmarshalled: &btcjson.GetBlockStatsCmd{
+				HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
+			},
+		},
+		{
+			name: "getblockstats height optional stats",
+			newCmd: func() (interface{}, error) {
+				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123}, []string{"avgfee", "maxfee"})
+			},
+			staticCmd: func() interface{} {
+				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, &[]string{"avgfee", "maxfee"})
+			},
+			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123,["avgfee","maxfee"]],"id":1}`,
+			unmarshalled: &btcjson.GetBlockStatsCmd{
+				HashOrHeight: btcjson.HashOrHeight{Value: 123},
+				Stats:        &[]string{"avgfee", "maxfee"},
+			},
+		},
+		{
+			name: "getblockstats hash optional stats",
+			newCmd: func() (interface{}, error) {
+				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"}, []string{"avgfee", "maxfee"})
+			},
+			staticCmd: func() interface{} {
+				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, &[]string{"avgfee", "maxfee"})
+			},
+			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef",["avgfee","maxfee"]],"id":1}`,
+			unmarshalled: &btcjson.GetBlockStatsCmd{
+				HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
+				Stats:        &[]string{"avgfee", "maxfee"},
+			},
+		},
 		{
 			name: "getblocktemplate",
 			newCmd: func() (interface{}, error) {
diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go
index a3a26c89..8cd716d4 100644
--- a/btcjson/chainsvrresults.go
+++ b/btcjson/chainsvrresults.go
@@ -24,6 +24,38 @@ type GetBlockHeaderVerboseResult struct {
 	NextHash      string  `json:"nextblockhash,omitempty"`
 }
 
+// GetBlockStatsResult models the data from the getblockstats command.
+type GetBlockStatsResult struct {
+	AverageFee         int64   `json:"avgfee"`
+	AverageFeeRate     int64   `json:"avgfeerate"`
+	AverageTxSize      int64   `json:"avgtxsize"`
+	FeeratePercentiles []int64 `json:"feerate_percentiles"`
+	Hash               string  `json:"blockhash"`
+	Height             int64   `json:"height"`
+	Ins                int64   `json:"ins"`
+	MaxFee             int64   `json:"maxfee"`
+	MaxFeeRate         int64   `json:"maxfeerate"`
+	MaxTxSize          int64   `json:"maxtxsize"`
+	MedianFee          int64   `json:"medianfee"`
+	MedianTime         int64   `json:"mediantime"`
+	MedianTxSize       int64   `json:"mediantxsize"`
+	MinFee             int64   `json:"minfee"`
+	MinFeeRate         int64   `json:"minfeerate"`
+	MinTxSize          int64   `json:"mintxsize"`
+	Outs               int64   `json:"outs"`
+	SegWitTotalSize    int64   `json:"swtotal_size"`
+	SegWitTotalWeight  int64   `json:"swtotal_weight"`
+	SegWitTxs          int64   `json:"swtxs"`
+	Subsidy            int64   `json:"subsidy"`
+	Time               int64   `json:"time"`
+	TotalOut           int64   `json:"total_out"`
+	TotalSize          int64   `json:"total_size"`
+	TotalWeight        int64   `json:"total_weight"`
+	Txs                int64   `json:"txs"`
+	UTXOIncrease       int64   `json:"utxo_increase"`
+	UTXOSizeIncrease   int64   `json:"utxo_size_inc"`
+}
+
 // GetBlockVerboseResult models the data from the getblock command when the
 // verbose flag is set to 1.  When the verbose flag is set to 0, getblock returns a
 // hex-encoded string. When the verbose flag is set to 1, getblock returns an object
diff --git a/rpcclient/chain.go b/rpcclient/chain.go
index c656a19a..707978ca 100644
--- a/rpcclient/chain.go
+++ b/rpcclient/chain.go
@@ -1037,3 +1037,44 @@ func (c *Client) GetCFilterHeader(blockHash *chainhash.Hash,
 	filterType wire.FilterType) (*wire.MsgCFHeaders, error) {
 	return c.GetCFilterHeaderAsync(blockHash, filterType).Receive()
 }
+
+// FutureGetBlockStatsResult is a future promise to deliver the result of a
+// GetBlockStatsAsync RPC invocation (or an applicable error).
+type FutureGetBlockStatsResult chan *response
+
+// Receive waits for the response promised by the future and returns statistics
+// of a block at a certain height.
+func (r FutureGetBlockStatsResult) Receive() (*btcjson.GetBlockStatsResult, error) {
+	res, err := receiveFuture(r)
+	if err != nil {
+		return nil, err
+	}
+
+	var blockStats btcjson.GetBlockStatsResult
+	err = json.Unmarshal(res, &blockStats)
+	if err != nil {
+		return nil, err
+	}
+
+	return &blockStats, nil
+}
+
+// GetBlockStatsAsync 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 GetBlockStats or the blocking version and more details.
+func (c *Client) GetBlockStatsAsync(hashOrHeight interface{}, stats *[]string) FutureGetBlockStatsResult {
+	if hash, ok := hashOrHeight.(*chainhash.Hash); ok {
+		hashOrHeight = hash.String()
+	}
+
+	cmd := btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: hashOrHeight}, stats)
+	return c.sendCmd(cmd)
+}
+
+// GetBlockStats returns block statistics. First argument specifies height or hash of the target block.
+// Second argument allows to select certain stats to return.
+func (c *Client) GetBlockStats(hashOrHeight interface{}, stats *[]string) (*btcjson.GetBlockStatsResult, error) {
+	return c.GetBlockStatsAsync(hashOrHeight, stats).Receive()
+}