Add bchain method GetChainInfo with extended information about backend

pull/56/head
Martin Boehm 2018-09-14 14:48:43 +02:00
parent 14a06888c7
commit 635733574c
5 changed files with 102 additions and 27 deletions

View File

@ -132,9 +132,9 @@ func (c *blockChainWithMetrics) GetSubversion() string {
return c.b.GetSubversion()
}
func (c *blockChainWithMetrics) GetBlockChainInfo() (v string, err error) {
defer func(s time.Time) { c.observeRPCLatency("GetBlockChainInfo", s, err) }(time.Now())
return c.b.GetBlockChainInfo()
func (c *blockChainWithMetrics) GetChainInfo() (v *bchain.ChainInfo, err error) {
defer func(s time.Time) { c.observeRPCLatency("GetChainInfo", s, err) }(time.Now())
return c.b.GetChainInfo()
}
func (c *blockChainWithMetrics) GetBestBlockHash() (v string, err error) {

View File

@ -11,6 +11,7 @@ import (
"math/big"
"net"
"net/http"
"strconv"
"time"
"github.com/btcsuite/btcd/wire"
@ -102,10 +103,11 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
// and if successful it connects to ZeroMQ and creates mempool handler
func (b *BitcoinRPC) GetChainInfoAndInitializeMempool(bc bchain.BlockChain) (string, error) {
// try to connect to block chain and get some info
chainName, err := bc.GetBlockChainInfo()
ci, err := bc.GetChainInfo()
if err != nil {
return "", err
}
chainName := ci.Chain
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
if err != nil {
@ -217,10 +219,30 @@ type CmdGetBlockChainInfo struct {
type ResGetBlockChainInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Warnings string `json:"warnings"`
} `json:"result"`
}
// getnetworkinfo
type CmdGetNetworkInfo struct {
Method string `json:"method"`
}
type ResGetNetworkInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Version int `json:"version"`
Subversion string `json:"subversion"`
ProtocolVersion int `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
} `json:"result"`
}
@ -386,21 +408,52 @@ func (b *BitcoinRPC) GetBestBlockHeight() (uint32, error) {
return res.Result, nil
}
// GetBlockChainInfo returns the name of the block chain: main/test/regtest.
func (b *BitcoinRPC) GetBlockChainInfo() (string, error) {
// GetChainInfo returns information about the connected backend
func (b *BitcoinRPC) GetChainInfo() (*bchain.ChainInfo, error) {
glog.V(1).Info("rpc: getblockchaininfo")
res := ResGetBlockChainInfo{}
req := CmdGetBlockChainInfo{Method: "getblockchaininfo"}
err := b.Call(&req, &res)
resCi := ResGetBlockChainInfo{}
err := b.Call(&CmdGetBlockChainInfo{Method: "getblockchaininfo"}, &resCi)
if err != nil {
return "", err
return nil, err
}
if res.Error != nil {
return "", res.Error
if resCi.Error != nil {
return nil, resCi.Error
}
return res.Result.Chain, nil
glog.V(1).Info("rpc: getnetworkinfo")
resNi := ResGetNetworkInfo{}
err = b.Call(&CmdGetNetworkInfo{Method: "getnetworkinfo"}, &resNi)
if err != nil {
return nil, err
}
if resNi.Error != nil {
return nil, resNi.Error
}
rv := &bchain.ChainInfo{
Bestblockhash: resCi.Result.Bestblockhash,
Blocks: resCi.Result.Blocks,
Chain: resCi.Result.Chain,
Difficulty: resCi.Result.Difficulty,
Headers: resCi.Result.Headers,
SizeOnDisk: resCi.Result.SizeOnDisk,
Subversion: resNi.Result.Subversion,
Timeoffset: resNi.Result.Timeoffset,
}
if resNi.Result.Version > 0 {
rv.Version = strconv.Itoa(resNi.Result.Version)
}
if resNi.Result.ProtocolVersion > 0 {
rv.ProtocolVersion = strconv.Itoa(resNi.Result.ProtocolVersion)
}
if len(resCi.Result.Warnings) > 0 {
rv.Warnings = resCi.Result.Warnings + " "
}
if resCi.Result.Warnings != resNi.Result.Warnings {
rv.Warnings += resNi.Result.Warnings
}
return rv, nil
}
func isErrBlockNotFound(err *bchain.RPCError) bool {
@ -454,7 +507,7 @@ func (b *BitcoinRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
// GetBlock returns block with given hash.
func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
var err error
if hash == "" && height > 0 {
if hash == "" {
hash, err = b.GetBlockHash(height)
if err != nil {
return nil, err
@ -483,7 +536,7 @@ func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error)
return block, nil
}
// getBlockWithoutHeader is an optimization - it does not call GetBlockHeader to get prev, next hashes
// GetBlockWithoutHeader is an optimization - it does not call GetBlockHeader to get prev, next hashes
// instead it sets to header only block hash and height passed in parameters
func (b *BitcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
data, err := b.GetBlockRaw(hash)

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"math/big"
"strconv"
"sync"
"time"
@ -258,16 +259,23 @@ func (b *EthereumRPC) GetSubversion() string {
return ""
}
// GetBlockChainInfo returns the NetworkID of the ethereum network
func (b *EthereumRPC) GetBlockChainInfo() (string, error) {
// GetChainInfo returns information about the connected backend
func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
id, err := b.client.NetworkID(ctx)
if err != nil {
return "", err
return nil, err
}
return id.String(), nil
rv := &bchain.ChainInfo{}
idi := int(id.Uint64())
if idi == 1 {
rv.Chain = "mainnet"
} else {
rv.Chain = "testnet " + strconv.Itoa(idi)
}
// TODO - return more information about the chain
return rv, nil
}
func (b *EthereumRPC) getBestHeader() (*ethtypes.Header, error) {

View File

@ -72,7 +72,7 @@ func NewTest(coin string, factory TestChainFactoryFunc) (*Test, error) {
}
}
_, err = cli.GetBlockChainInfo()
_, err = cli.GetChainInfo()
if err != nil && isNetError(err) {
connected = false
}

View File

@ -103,6 +103,20 @@ type MempoolEntry struct {
Depends []string `json:"depends"`
}
type ChainInfo struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Version string `json:"version"`
Subversion string `json:"subversion"`
ProtocolVersion string `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
}
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
@ -135,8 +149,8 @@ type BlockChain interface {
GetNetworkName() string
GetSubversion() string
GetCoinName() string
GetChainInfo() (*ChainInfo, error)
// requests
GetBlockChainInfo() (string, error)
GetBestBlockHash() (string, error)
GetBestBlockHeight() (uint32, error)
GetBlockHash(height uint32) (string, error)