Skip to content

Commit

Permalink
multi: Add getblockchaininfo rpc.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnldd committed Oct 7, 2018
1 parent b413da2 commit 3e42c2e
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 46 deletions.
18 changes: 17 additions & 1 deletion blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package blockchain
import (
"container/list"
"fmt"
"math/big"
"sync"
"time"

Expand Down Expand Up @@ -295,12 +296,16 @@ func (b *BlockChain) GetStakeVersions(hash *chainhash.Hash, count int32) ([]Stak
return result, nil
}

// VoteInfo represents information on agendas and their respective states for
// a consensus deployment.
type VoteInfo struct {
Agendas []chaincfg.ConsensusDeployment
AgendaStatus []ThresholdStateTuple
}

// GetVoteInfo returns
// GetVoteInfo returns information on consensus deployment agendas
// and their respective states at the provided hash, for the provided
// deployment version.
func (b *BlockChain) GetVoteInfo(hash *chainhash.Hash, version uint32) (*VoteInfo, error) {
deployments, ok := b.chainParams.Deployments[version]
if !ok {
Expand Down Expand Up @@ -368,6 +373,17 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
return b.index.HaveBlock(hash) || b.IsKnownOrphan(hash), nil
}

// ChainWork returns the total work up to and including the block of the
// provided block hash.
func (b *BlockChain) ChainWork(hash *chainhash.Hash) (*big.Int, error) {
node := b.index.LookupNode(hash)
if node == nil {
return nil, fmt.Errorf("block %s is not known", hash)
}

return node.workSum, nil
}

// IsKnownOrphan returns whether the passed hash is currently a known orphan.
// Keep in mind that only a limited number of orphans are held onto for a
// limited amount of time, so this function must not be used as an absolute
Expand Down
78 changes: 77 additions & 1 deletion blockchain/thresholdstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type ThresholdStateTuple struct {
// state contains the current ThresholdState.
State ThresholdState

// coice is set to invalidChoice unless state is: ThresholdLockedIn,
// Choice is set to invalidChoice unless state is: ThresholdLockedIn,
// ThresholdFailed & ThresholdActive. choice should always be
// crosschecked with invalidChoice.
Choice uint32
Expand Down Expand Up @@ -465,6 +465,82 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, version uint32, deploy
return invalidState, DeploymentError(deploymentID)
}

// thresholdStatelastChanged returns the last node before the current state of
// consensus deployment agenda activated.
func (b *BlockChain) thresholdStateLastChanged(version uint32, prevNode *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (*blockNode, error) {
// The threshold state for the window that contains the genesis block is
// defined by definition.
confirmationWindow := int64(checker.RuleChangeActivationInterval())
svh := checker.StakeValidationHeight()
if prevNode == nil || prevNode.height+1 < svh+confirmationWindow {
return b.bestChain.Genesis(), nil
}

curState, err := b.thresholdState(version, prevNode, checker, cache)
if err != nil {
return nil, err
}

// Get the ancestor that is the last block of the previous confirmation
// window in order to get its threshold state. This can be done because
// the state is the same for all blocks within a given window.
wantHeight := calcWantHeight(svh, confirmationWindow, prevNode.height+1)
prevNode = prevNode.Ancestor(wantHeight)
for prevNode != nil {
state, err := b.thresholdState(version, prevNode, checker, cache)
if err != nil {
return nil, err
}

if state.State != curState.State {
return prevNode, nil
}

// Get the ancestor that is the last block of the previous
// confirmation window.
prevNode = prevNode.RelativeAncestor(confirmationWindow)
}

return b.bestChain.Genesis(), nil
}

// StateActivationHeight returns the height of the first block where the
// current state of consensus deployment agenda activated.
func (b *BlockChain) StateActivationHeight(hash *chainhash.Hash, version uint32, deploymentID string) (int64, error) {
// Fetch the block node of the provided hash.
node := b.index.LookupNode(hash)
if node == nil || !b.index.NodeStatus(node).KnownValid() {
return 0, HashError(hash.String())
}

// Fetch the treshold state cache for the provided deployment id as well as
// the condition checker.
var cache *thresholdStateCache
var checker thresholdConditionChecker
for k := range b.chainParams.Deployments[version] {
if b.chainParams.Deployments[version][k].Vote.Id == deploymentID {
checker = deploymentChecker{
deployment: &b.chainParams.Deployments[version][k],
chain: b,
}
cache = &b.deploymentCaches[version][k]
break
}
}

if cache == nil {
return 0, fmt.Errorf("Threshold state cache for agenda with "+
"deployment id (%s) not found", deploymentID)
}

stateChangeNode, err := b.thresholdStateLastChanged(version, node, checker, cache)
if err != nil {
return 0, err
}

return stateChangeNode.height + 1, err
}

// ThresholdState returns the current rule change threshold state of the given
// deployment ID for the block AFTER the provided block hash.
//
Expand Down
18 changes: 18 additions & 0 deletions blockmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ type blockManager struct {
// The following fields are used to filter duplicate block announcements.
announcedBlockMtx sync.Mutex
announcedBlock *chainhash.Hash

// The following fields are used to track the current synced block height
// from peers.
syncHeightMtx sync.Mutex
syncHeight int64
}

// resetHeaderState sets the headers-first mode state to values appropriate for
Expand All @@ -352,6 +357,13 @@ func (b *blockManager) resetHeaderState(newestHash *chainhash.Hash, newestHeight
}
}

// SyncHeight returns latest known block being synced to.
func (b *blockManager) SyncHeight() int64 {
b.syncHeightMtx.Lock()
defer b.syncHeightMtx.Unlock()
return b.syncHeight
}

// findNextHeaderCheckpoint returns the next checkpoint after the passed height.
// It returns nil when there is not one either because the height is already
// later than the final checkpoint or some other reason such as disabled
Expand Down Expand Up @@ -479,6 +491,9 @@ func (b *blockManager) startSync(peers *list.List) {
}
}
b.syncPeer = bestPeer
b.syncHeightMtx.Lock()
b.syncHeight = bestPeer.LastBlock()
b.syncHeightMtx.Unlock()
} else {
bmgrLog.Warnf("No sync peer candidates available")
}
Expand Down Expand Up @@ -2307,6 +2322,9 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager, interrupt
}

bm.lotteryDataBroadcast = make(map[chainhash.Hash]struct{})
bm.syncHeightMtx.Lock()
bm.syncHeight = best.Height
bm.syncHeightMtx.Unlock()

return &bm, nil
}
Expand Down
27 changes: 20 additions & 7 deletions dcrjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,29 @@ type GetBlockVerboseResult struct {
NextHash string `json:"nextblockhash,omitempty"`
}

// AgendaInfo provides an overview of an agenda in a consensus deployment.
type AgendaInfo struct {
Version uint32 `json:"version"`
Status string `json:"status"`
Since int64 `json:"since,omitempty"`
StartTime uint64 `json:"starttime"`
ExpireTime uint64 `json:"expiretime"`
}

// GetBlockChainInfoResult models the data returned from the getblockchaininfo
// command.
type GetBlockChainInfoResult struct {
Chain string `json:"chain"`
Blocks int32 `json:"blocks"`
Headers int32 `json:"headers"`
BestBlockHash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
VerificationProgress float64 `json:"verificationprogress"`
ChainWork string `json:"chainwork"`
Chain string `json:"chain"`
Blocks int64 `json:"blocks"`
Headers int64 `json:"headers"`
SyncHeight int64 `json:"syncheight"`
BestBlockHash string `json:"bestblockhash"`
Difficulty uint32 `json:"difficulty"`
VerificationProgress float64 `json:"verificationprogress"`
ChainWork string `json:"chainwork"`
InitialBlockDownload bool `json:"initialblockdownload"`
MaxBlockSize int64 `json:"maxblocksize"`
Deployments map[string]AgendaInfo `json:"deployments"`
}

// GetBlockHeaderVerboseResult models the data from the getblockheader command when
Expand Down
77 changes: 45 additions & 32 deletions docs/json_rpc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,38 +161,39 @@ the method name for further details such as parameter and return information.
|5|[getaddednodeinfo](#getaddednodeinfo)|N|Returns information about manually added (persistent) peers.|
|6|[getbestblockhash](#getbestblockhash)|Y|Returns the hash of the of the best (most recent) block in the longest block chain.|
|7|[getblock](#getblock)|Y|Returns information about a block given its hash.|
|8|[getblockcount](#getblockcount)|Y|Returns the number of blocks in the longest block chain.|
|9|[getblockhash](#getblockhash)|Y|Returns hash of the block in best block chain at the given height.|
|10|[getblockheader](#getblockheader)|Y|Returns the block header of the block.|
|11|[getchaintips](#getchaintips)|Y|Returns information about all known chain tips the in the block tree.|
|12|[getconnectioncount](#getconnectioncount)|N|Returns the number of active connections to other peers.|
|13|[getdifficulty](#getdifficulty)|Y|Returns the proof-of-work difficulty as a multiple of the minimum difficulty.|
|14|[getgenerate](#getgenerate)|N|Return if the server is set to generate coins (mine) or not.|
|15|[gethashespersec](#gethashespersec)|N|Returns a recent hashes per second performance measurement while generating coins (mining).|
|16|[getinfo](#getinfo)|Y|Returns a JSON object containing various state info.|
|17|[getmempoolinfo](#getmempoolinfo)|N|Returns a JSON object containing mempool-related information.|
|18|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.|
|19|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.|
|20|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.|
|21|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.|
|22|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.|
|23|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.|
|24|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.<br /><br />NOTE: Since dcrd does not have the wallet integrated to provide payment addresses, dcrd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|25|[help](#help)|Y|Returns a list of all commands or help for a specified command.|
|26|[ping](#ping)|N|Queues a ping to be sent to each connected peer.|
|27|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.<br /><br />NOTE: dcrd does not yet implement the `allowhighfees` parameter, so it has no effect|
|28|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.<br/>NOTE: Since dcrd does not have the wallet integrated to provide payment addresses, dcrd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|29|[stop](#stop)|N|Shutdown dcrd.|
|30|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.|
|31|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since dcrd does not have a wallet integrated, dcrd will only return whether the address is valid or not.|
|32|[verifychain](#verifychain)|N|Verifies the block chain database.|
|33|[debuglevel](#debuglevel)|N|Dynamically changes the debug logging level.|
|34|[getbestblock](#getbestblock)|Y|Get block height and hash of best block in the main chain.|
|35|[getcurrentnet](#getcurrentnet)|Y|Get Decred network dcrd is running on.|
|36|[searchrawtransactions](#searchrawtransactions)|Y|Query for transactions related to a particular address.|
|37|[node](#node)|N|Attempts to add or remove a peer. |
|38|[generate](#generate)|N|When in simnet or regtest mode, generate a set number of blocks. |
|39|[getstakeversions](#getstakeversions)|Y|Get stake versions per block. |
|8|[getblockchaininfo](#getblockchaininfo)|Y|Returns information about the current state of the block chain.|
|9|[getblockcount](#getblockcount)|Y|Returns the number of blocks in the longest block chain.|
|10|[getblockhash](#getblockhash)|Y|Returns hash of the block in best block chain at the given height.|
|11|[getblockheader](#getblockheader)|Y|Returns the block header of the block.|
|12|[getchaintips](#getchaintips)|Y|Returns information about all known chain tips the in the block tree.|
|13|[getconnectioncount](#getconnectioncount)|N|Returns the number of active connections to other peers.|
|14|[getdifficulty](#getdifficulty)|Y|Returns the proof-of-work difficulty as a multiple of the minimum difficulty.|
|15|[getgenerate](#getgenerate)|N|Return if the server is set to generate coins (mine) or not.|
|16|[gethashespersec](#gethashespersec)|N|Returns a recent hashes per second performance measurement while generating coins (mining).|
|17|[getinfo](#getinfo)|Y|Returns a JSON object containing various state info.|
|18|[getmempoolinfo](#getmempoolinfo)|N|Returns a JSON object containing mempool-related information.|
|19|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.|
|20|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.|
|21|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.|
|22|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.|
|23|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.|
|24|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.|
|25|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.<br /><br />NOTE: Since dcrd does not have the wallet integrated to provide payment addresses, dcrd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|26|[help](#help)|Y|Returns a list of all commands or help for a specified command.|
|27|[ping](#ping)|N|Queues a ping to be sent to each connected peer.|
|28|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.<br /><br />NOTE: dcrd does not yet implement the `allowhighfees` parameter, so it has no effect|
|29|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.<br/>NOTE: Since dcrd does not have the wallet integrated to provide payment addresses, dcrd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|30|[stop](#stop)|N|Shutdown dcrd.|
|31|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.|
|32|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since dcrd does not have a wallet integrated, dcrd will only return whether the address is valid or not.|
|33|[verifychain](#verifychain)|N|Verifies the block chain database.|
|34|[debuglevel](#debuglevel)|N|Dynamically changes the debug logging level.|
|35|[getbestblock](#getbestblock)|Y|Get block height and hash of best block in the main chain.|
|36|[getcurrentnet](#getcurrentnet)|Y|Get Decred network dcrd is running on.|
|37|[searchrawtransactions](#searchrawtransactions)|Y|Query for transactions related to a particular address.|
|38|[node](#node)|N|Attempts to add or remove a peer. |
|39|[generate](#generate)|N|When in simnet or regtest mode, generate a set number of blocks. |
|40|[getstakeversions](#getstakeversions)|Y|Get stake versions per block. |

<a name="MethodDetails" />

Expand Down Expand Up @@ -335,6 +336,18 @@ the method name for further details such as parameter and return information.
|Example Return|`[{"height": 217033, "hash": "00000000000000161bd5b120ef945faad60fc6e4c32b5caf1d4cabeae9a75346", "branchlen": 0, "status": "active"}, {"height": 213522, "hash": "0000000000000015e27658ce02ba8fa05d8d7ad9c587a5a472e3307773a9b36e", "branchlen": 1, "status": "valid-fork"}]"`|
[Return to Overview](#MethodOverview)<br />

***
<a name="getblockchaininfo"/>

| | |
|---|---|
|Method|getblockchaininfo|
|Parameters|None|
|Description|Returns information about the current state of the block chain.|
|Returns|`(json object)`<br />`chain`: `(string)` The current network name.<br />`blocks`: `(numeric)` The block count.<br />`headers`: `(numeric)` The block header count.<br />`syncheight`: `(numeric)` The latest known block being synced to.<br />`bestblockhash`: `(string)` The block hash of the current best chain tip.<br />`difficulty`: `(numeric)` The current network difficulty.<br />`verificationprogress`: `(numeric)` The chain verification progress estimate.<br />`chainwork`: `(string)` Hex encoded total work done for the chain.<br />`initialblockdownload`: `(boolean)` Syncing status.<br /><br />`maxblocksize`: `(numeric)` The maximum allowed block size.<br /><br />`deployments`: `(json array of objects)` Network consensus deployments.<br /><br />`status`: `(string)` The deployment agenda's current status.<br /><br />`since`: `(numeric)` The blockheight of the first block to which the status applies.<br /><br />`starttime`: `(numeric)` The start time of the voting period for the agenda.<br /><br />`expiretime`: `(numeric)` The expiry time of the voting period for the agenda.<br /><br />`{ "chain": "name", "blocks": n, "headers": n, "syncheight": n, "bestblockhash": "hash", "difficulty": n, "verificationprogress": n, "chainwork": "n", "initialblockdownload": bool, "maxblocksize": n, "deployments": {"agenda": { "status": "status", "since": n, "starttime": n, "expiretime": n}, ...}}`|
|Example Return|`{"chain": "simnet", "blocks": 463, "headers": 463, "syncheight": 0, "bestblockhash": "000043c89f6e227c9d90a5460aff98b662e503b9a394818942bdd60709cbb8aa", "difficulty": 520127421, "verificationprogress": 0, "chainwork": "0x23c0e40", "initialblockdownload": false, "maxblocksize": 1000000, "deployments": {"lnfeatures": {"status": "started", "since": 463, "starttime": 0, "expiretime": 9223372036854775807}, "maxblocksize": {"status": "started", "since": 463, "starttime": 0, "expiretime": 9223372036854775807}, "sdiffalgorithm": {"status": "started", "since": 463, "starttime": 0, "expiretime": 9223372036854775807}}}`|
[Return to Overview](#MethodOverview)<br />

***
<a name="getconnectioncount"/>

Expand Down
Loading

0 comments on commit 3e42c2e

Please sign in to comment.