diff --git a/glide.lock b/glide.lock index 4733aee70..8319cebea 100644 --- a/glide.lock +++ b/glide.lock @@ -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: diff --git a/rpcserver.go b/rpcserver.go index 7d54c9d1e..97f2d944d 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -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() diff --git a/rpcserverhelp.go b/rpcserverhelp.go index fae118f38..213f3cd63 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -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)},