rpcserver: implement the getblockchaininfo RPC call

This commit is contained in:
Olaoluwa Osuntokun 2016-11-02 17:17:00 -07:00
parent ec1c93ecc0
commit 7b0380cdd3
No known key found for this signature in database
GPG key ID: 9CC5B105D03521A2
3 changed files with 158 additions and 10 deletions

4
glide.lock generated
View file

@ -1,10 +1,10 @@
hash: 8f89ba1940f8798b8a0449810532e3f0bc552ed97d907bc3447a8941a2ea3a4a
updated: 2016-10-26T22:53:00.0848822-05:00
updated: 2016-11-11T17:21:09.070085014-08:00
imports:
- name: github.com/btcsuite/btclog
version: 73889fb79bd687870312b6e40effcecffbd57d30
- name: github.com/btcsuite/btcrpcclient
version: 2b780d16b042054d07aa322146194118fd7f7b81
version: c6e1d711da0db56803309479a5deabb02b816e88
- name: github.com/btcsuite/btcutil
version: aa9087a7efc961fbd253d4ae9c8b7a318749c273
subpackages:

View file

@ -144,6 +144,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"getbestblock": handleGetBestBlock,
"getbestblockhash": handleGetBestBlockHash,
"getblock": handleGetBlock,
"getblockchaininfo": handleGetBlockChainInfo,
"getblockcount": handleGetBlockCount,
"getblockhash": handleGetBlockHash,
"getblockheader": handleGetBlockHeader,
@ -226,14 +227,13 @@ var rpcAskWallet = map[string]struct{}{
// Commands that are currently unimplemented, but should ultimately be.
var rpcUnimplemented = map[string]struct{}{
"estimatefee": {},
"estimatepriority": {},
"getblockchaininfo": {},
"getchaintips": {},
"getnetworkinfo": {},
"invalidateblock": {},
"preciousblock": {},
"reconsiderblock": {},
"estimatefee": {},
"estimatepriority": {},
"getchaintips": {},
"getnetworkinfo": {},
"invalidateblock": {},
"preciousblock": {},
"reconsiderblock": {},
}
// Commands that are available to a limited user
@ -1121,6 +1121,127 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
return blockReply, nil
}
// softForkStatus converts a ThresholdState state into a human readable string
// corresponding to the particular state.
func softForkStatus(state blockchain.ThresholdState) (string, error) {
switch state {
case blockchain.ThresholdDefined:
return "defined", nil
case blockchain.ThresholdStarted:
return "started", nil
case blockchain.ThresholdLockedIn:
return "lockedin", nil
case blockchain.ThresholdActive:
return "active", nil
case blockchain.ThresholdFailed:
return "failed", nil
default:
return "", fmt.Errorf("unknown deployment state: %v", state)
}
}
// handleGetBlockChainInfo implements the getblockchaininfo command.
func handleGetBlockChainInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
// Obtain a snapshot of the current best known blockchain state. We'll
// populate the response to this call primarily from this snapshot.
chainSnapshot := s.chain.BestSnapshot()
chainInfo := &btcjson.GetBlockChainInfoResult{
Chain: activeNetParams.Name,
Blocks: chainSnapshot.Height,
Headers: chainSnapshot.Height,
BestBlockHash: chainSnapshot.Hash.String(),
Difficulty: getDifficultyRatio(chainSnapshot.Bits),
MedianTime: chainSnapshot.MedianTime.Unix(),
Pruned: false,
Bip9SoftForks: make(map[string]*btcjson.Bip9SoftForkDescription),
}
// Next, populate the response with information describing the current
// status of soft-forks deployed via the super-majority block
// signalling mechanism.
height := chainSnapshot.Height
chainInfo.SoftForks = []*btcjson.SoftForkDescription{
{
ID: "bip34",
Version: 2,
Reject: struct {
Status bool `json:"status"`
}{
Status: height >= activeNetParams.BIP0034Height,
},
},
{
ID: "bip66",
Version: 3,
Reject: struct {
Status bool `json:"status"`
}{
Status: height >= activeNetParams.BIP0066Height,
},
},
{
ID: "bip65",
Version: 4,
Reject: struct {
Status bool `json:"status"`
}{
Status: height >= activeNetParams.BIP0065Height,
},
},
}
// Finally, query the BIP0009 version bits state for all currently
// defined BIP0009 soft-fork deployments.
for deployment, deploymentDetails := range activeNetParams.Deployments {
// Map the integer deployment ID into a human readable
// fork-name.
var forkName string
switch deployment {
case chaincfg.DeploymentTestDummy:
forkName = "dummy"
default:
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInternal.Code,
Message: fmt.Sprintf("Unknown deployment %v "+
"detected", deployment),
}
}
// Query the chain for the current status of the deployment as
// identified by its deployment ID.
deploymentStatus, err := s.chain.ThresholdState(uint32(deployment))
if err != nil {
context := "Failed to obtain deployment status"
return nil, internalRPCError(err.Error(), context)
}
// Attempt to convert the current deployment status into a
// human readable string. If the status is unrecognized, then a
// non-nil error is returned.
statusString, err := softForkStatus(deploymentStatus)
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInternal.Code,
Message: fmt.Sprintf("unknown deployment status: %v",
deploymentStatus),
}
}
// Finally, populate the soft-fork description with all the
// information gathered above.
chainInfo.Bip9SoftForks[forkName] = &btcjson.Bip9SoftForkDescription{
Status: strings.ToLower(statusString),
Bit: deploymentDetails.BitNumber,
StartTime: int64(deploymentDetails.StartTime),
Timeout: int64(deploymentDetails.ExpireTime),
}
}
return chainInfo, nil
}
// handleGetBlockCount implements the getblockcount command.
func handleGetBlockCount(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
best := s.chain.BestSnapshot()

View file

@ -156,6 +156,32 @@ var helpDescsEnUS = map[string]string{
"getblock--condition1": "verbose=true",
"getblock--result0": "Hex-encoded bytes of the serialized block",
// GetBlockChainInfoCmd help.
"getblockchaininfo--synopsis": "Returns information about the current blockchain state and the status of any active soft-fork deployments.",
// GetBlockChainInfoResult help.
"getblockchaininforesult-chain": "The name of the chain the daemon is on (testnet, mainnet, etc)",
"getblockchaininforesult-blocks": "The number of blocks in the best known chain",
"getblockchaininforesult-headers": "The number of headers that we've gathered for in the best known chain",
"getblockchaininforesult-bestblockhash": "The block hash for the latest block in the main chain",
"getblockchaininforesult-difficulty": "The current chain difficulty",
"getblockchaininforesult-mediantime": "The median time from the PoV of the best block in the chain",
"getblockchaininforesult-verificationprogress": "An estimate for how much of the best chain we've verified",
"getblockchaininforesult-pruned": "A bool that indicates if the node is pruned or not",
"getblockchaininforesult-pruneheight": "The lowest block retained in the current pruned chain",
"getblockchaininforesult-chainwork": "The total cumulative work in the best chain",
"getblockchaininforesult-softforks": "The status of the super-majority soft-forks",
"getblockchaininforesult-bip9_softforks": "JSON object describing active BIP0009 deployments",
"getblockchaininforesult-bip9_softforks--key": "bip9_softforks",
"getblockchaininforesult-bip9_softforks--value": "An object describing a particular BIP009 deployment",
"getblockchaininforesult-bip9_softforks--desc": "The status of any defined BIP0009 soft-fork deployments",
// SoftForkDescription help.
"softforkdescription-reject": "The current activation status of the softfork",
"softforkdescription-version": "The block version that signals enforcement of this softfork",
"softforkdescription-id": "The string identifier for the soft fork",
"-status": "A bool which indicates if the soft fork is active",
// TxRawResult help.
"txrawresult-hex": "Hex-encoded transaction",
"txrawresult-txid": "The hash of the transaction",
@ -599,6 +625,7 @@ var rpcResultTypes = map[string][]interface{}{
"getblockhash": {(*string)(nil)},
"getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)},
"getblocktemplate": {(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil},
"getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)},
"getconnectioncount": {(*int32)(nil)},
"getcurrentnet": {(*uint32)(nil)},
"getdifficulty": {(*float64)(nil)},