Implement 'getblockstats' JSON-RPC command
This commit is contained in:
parent
8b1be46463
commit
cfcf4fb762
4 changed files with 172 additions and 0 deletions
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue