Add bchain method GetChainInfo with extended information about backend

This commit is contained in:
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() return c.b.GetSubversion()
} }
func (c *blockChainWithMetrics) GetBlockChainInfo() (v string, err error) { func (c *blockChainWithMetrics) GetChainInfo() (v *bchain.ChainInfo, err error) {
defer func(s time.Time) { c.observeRPCLatency("GetBlockChainInfo", s, err) }(time.Now()) defer func(s time.Time) { c.observeRPCLatency("GetChainInfo", s, err) }(time.Now())
return c.b.GetBlockChainInfo() return c.b.GetChainInfo()
} }
func (c *blockChainWithMetrics) GetBestBlockHash() (v string, err error) { func (c *blockChainWithMetrics) GetBestBlockHash() (v string, err error) {

View File

@ -11,6 +11,7 @@ import (
"math/big" "math/big"
"net" "net"
"net/http" "net/http"
"strconv"
"time" "time"
"github.com/btcsuite/btcd/wire" "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 // and if successful it connects to ZeroMQ and creates mempool handler
func (b *BitcoinRPC) GetChainInfoAndInitializeMempool(bc bchain.BlockChain) (string, error) { func (b *BitcoinRPC) GetChainInfoAndInitializeMempool(bc bchain.BlockChain) (string, error) {
// try to connect to block chain and get some info // try to connect to block chain and get some info
chainName, err := bc.GetBlockChainInfo() ci, err := bc.GetChainInfo()
if err != nil { if err != nil {
return "", err return "", err
} }
chainName := ci.Chain
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler) mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
if err != nil { if err != nil {
@ -217,10 +219,30 @@ type CmdGetBlockChainInfo struct {
type ResGetBlockChainInfo struct { type ResGetBlockChainInfo struct {
Error *bchain.RPCError `json:"error"` Error *bchain.RPCError `json:"error"`
Result struct { Result struct {
Chain string `json:"chain"` Chain string `json:"chain"`
Blocks int `json:"blocks"` Blocks int `json:"blocks"`
Headers int `json:"headers"` Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"` 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"` } `json:"result"`
} }
@ -386,21 +408,52 @@ func (b *BitcoinRPC) GetBestBlockHeight() (uint32, error) {
return res.Result, nil return res.Result, nil
} }
// GetBlockChainInfo returns the name of the block chain: main/test/regtest. // GetChainInfo returns information about the connected backend
func (b *BitcoinRPC) GetBlockChainInfo() (string, error) { func (b *BitcoinRPC) GetChainInfo() (*bchain.ChainInfo, error) {
glog.V(1).Info("rpc: getblockchaininfo") glog.V(1).Info("rpc: getblockchaininfo")
res := ResGetBlockChainInfo{} resCi := ResGetBlockChainInfo{}
req := CmdGetBlockChainInfo{Method: "getblockchaininfo"} err := b.Call(&CmdGetBlockChainInfo{Method: "getblockchaininfo"}, &resCi)
err := b.Call(&req, &res)
if err != nil { if err != nil {
return "", err return nil, err
} }
if res.Error != nil { if resCi.Error != nil {
return "", res.Error 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 { 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. // GetBlock returns block with given hash.
func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
var err error var err error
if hash == "" && height > 0 { if hash == "" {
hash, err = b.GetBlockHash(height) hash, err = b.GetBlockHash(height)
if err != nil { if err != nil {
return nil, err return nil, err
@ -483,7 +536,7 @@ func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error)
return block, nil 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 // instead it sets to header only block hash and height passed in parameters
func (b *BitcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) { func (b *BitcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
data, err := b.GetBlockRaw(hash) data, err := b.GetBlockRaw(hash)

View File

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big" "math/big"
"strconv"
"sync" "sync"
"time" "time"
@ -258,16 +259,23 @@ func (b *EthereumRPC) GetSubversion() string {
return "" return ""
} }
// GetBlockChainInfo returns the NetworkID of the ethereum network // GetChainInfo returns information about the connected backend
func (b *EthereumRPC) GetBlockChainInfo() (string, error) { func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.timeout) ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel() defer cancel()
id, err := b.client.NetworkID(ctx) id, err := b.client.NetworkID(ctx)
if err != nil { 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) { 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) { if err != nil && isNetError(err) {
connected = false connected = false
} }

View File

@ -103,6 +103,20 @@ type MempoolEntry struct {
Depends []string `json:"depends"` 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 { type RPCError struct {
Code int `json:"code"` Code int `json:"code"`
Message string `json:"message"` Message string `json:"message"`
@ -135,8 +149,8 @@ type BlockChain interface {
GetNetworkName() string GetNetworkName() string
GetSubversion() string GetSubversion() string
GetCoinName() string GetCoinName() string
GetChainInfo() (*ChainInfo, error)
// requests // requests
GetBlockChainInfo() (string, error)
GetBestBlockHash() (string, error) GetBestBlockHash() (string, error)
GetBestBlockHeight() (uint32, error) GetBestBlockHeight() (uint32, error)
GetBlockHash(height uint32) (string, error) GetBlockHash(height uint32) (string, error)