Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: Add getblockchaininfo rpc. #1479

Merged
merged 1 commit into from
Oct 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
104 changes: 103 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,108 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, version uint32, deploy
return invalidState, DeploymentError(deploymentID)
}

// stateLastChanged returns the node at which the provided consensus deployment
// agenda last changed state. The function will return nil if the state has
// never changed.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) stateLastChanged(version uint32, node *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (*blockNode, error) {
// No state changes are possible if the chain is not yet past stake
// validation height and had a full interval to change.
confirmationInterval := int64(checker.RuleChangeActivationInterval())
svh := checker.StakeValidationHeight()
if node == nil || node.height < svh+confirmationInterval {
return nil, nil
}

// Determine the current state. Notice that thresholdState always
// calculates the state for the block after the provided one, so use the
// parent to get the state for the requested block.
curState, err := b.thresholdState(version, node.parent, checker, cache)
if err != nil {
return nil, err
}

// Determine the first block of the current confirmation interval in order
// to determine block at which the state possibly changed. Since the state
// can only change at an interval boundary, loop backwards one interval at
// a time to determine when (and if) the state changed.
finalNodeHeight := calcWantHeight(svh, confirmationInterval, node.height)
node = node.Ancestor(finalNodeHeight + 1)
priorStateChangeNode := node
for node != nil && node.parent != nil {
// As previously mentioned, thresholdState always calculates the state
// for the block after the provided one, so use the parent to get the
// state of the block itself.
state, err := b.thresholdState(version, node.parent, checker, cache)
if err != nil {
return nil, err
}

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

// Get the ancestor that is the first block of the previous confirmation
// interval.
priorStateChangeNode = node
node = node.RelativeAncestor(confirmationInterval)
}

return nil, nil
}

// StateLastChangedHeight returns the height at which the provided consensus
// deployment agenda last changed state. Note that, unlike the ThresholdState
// function, this function returns the information as of the passed block hash.
//
// This function is safe for concurrent access.
func (b *BlockChain) StateLastChangedHeight(hash *chainhash.Hash, version uint32, deploymentID string) (int64, error) {
// NOTE: The requirement for the node being fully validated here is strictly
// stronger than what is actually required. In reality, all that is needed
// is for the block data for the node and all of its ancestors to be
// available, but there is not currently any tracking to be able to
// efficiently determine that state.
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)
}

// Find the node at which the current state changed.
b.chainLock.Lock()
stateNode, err := b.stateLastChanged(version, node, checker, cache)
b.chainLock.Unlock()
if err != nil {
return 0, err
}

var height int64
if stateNode != nil {
height = stateNode.height
}
return height, nil
}

// 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 height being synced to 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
26 changes: 19 additions & 7 deletions dcrjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,28 @@ type GetBlockVerboseResult struct {
NextHash string `json:"nextblockhash,omitempty"`
}

// AgendaInfo provides an overview of an agenda in a consensus deployment.
type AgendaInfo struct {
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 number of blocks in the current best chain.<br />`headers`: `(numeric)` The number of validated block headers that comprise the target best chain.<br />`syncheight`: `(numeric)` The latest known block height 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)` Best guess of whether this node is in the initial block download mode used to catch up the chain when it is far behind.<br />`maxblocksize`: `(numeric)` The maximum allowed block size.<br />`deployments`: `(json array of objects)` Network consensus deployments.<br />`status`: `(string)` The deployment agenda's current status.<br />`since`: `(numeric)` The blockheight of the first block to which the status applies.<br />`starttime`: `(numeric)` The start time of the voting period for the agenda.<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