[rpc blockchain] Add support for mediantime, chainwork to RPC getblock.
This commit is contained in:
parent
7f9fe4b970
commit
7df208eb88
4 changed files with 72 additions and 25 deletions
|
@ -8,6 +8,7 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -1373,6 +1374,54 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro
|
||||||
return &node.hash, nil
|
return &node.hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockAttributes desribes a Block in relation to others on the main chain.
|
||||||
|
type BlockAttributes struct {
|
||||||
|
Height int32
|
||||||
|
Confirmations int32
|
||||||
|
MedianTime time.Time
|
||||||
|
ChainWork *big.Int
|
||||||
|
PrevHash *chainhash.Hash
|
||||||
|
NextHash *chainhash.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockAttributesByHash returns BlockAttributes for the block with the given hash
|
||||||
|
// relative to other blocks in the main chain. A BestState snapshot describing
|
||||||
|
// the main chain is also returned for convenience.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) (
|
||||||
|
attrs *BlockAttributes, best *BestState, err error) {
|
||||||
|
best = b.BestSnapshot()
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil || !b.bestChain.Contains(node) {
|
||||||
|
str := fmt.Sprintf("block %s is not in the main chain", hash)
|
||||||
|
return nil, best, errNotInMainChain(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs = &BlockAttributes{
|
||||||
|
Height: node.height,
|
||||||
|
Confirmations: 1 + best.Height - node.height,
|
||||||
|
MedianTime: node.CalcPastMedianTime(),
|
||||||
|
ChainWork: node.workSum,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate prev block hash if there is one.
|
||||||
|
if node.height > 0 {
|
||||||
|
attrs.PrevHash = prevHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate next block hash if there is one.
|
||||||
|
if node.height < best.Height {
|
||||||
|
nextHash, err := b.BlockHashByHeight(node.height + 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, best, err
|
||||||
|
}
|
||||||
|
attrs.NextHash = nextHash
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, best, nil
|
||||||
|
}
|
||||||
|
|
||||||
// HeightRange returns a range of block hashes for the given start and end
|
// HeightRange returns a range of block hashes for the given start and end
|
||||||
// heights. It is inclusive of the start height and exclusive of the end
|
// heights. It is inclusive of the start height and exclusive of the end
|
||||||
// height. The end height will be limited to the current main chain height.
|
// height. The end height will be limited to the current main chain height.
|
||||||
|
|
|
@ -77,9 +77,11 @@ type GetBlockVerboseResultBase struct {
|
||||||
VersionHex string `json:"versionHex"`
|
VersionHex string `json:"versionHex"`
|
||||||
MerkleRoot string `json:"merkleroot"`
|
MerkleRoot string `json:"merkleroot"`
|
||||||
Time int64 `json:"time"`
|
Time int64 `json:"time"`
|
||||||
|
MedianTime int64 `json:"mediantime"`
|
||||||
Nonce uint32 `json:"nonce"`
|
Nonce uint32 `json:"nonce"`
|
||||||
Bits string `json:"bits"`
|
Bits string `json:"bits"`
|
||||||
Difficulty float64 `json:"difficulty"`
|
Difficulty float64 `json:"difficulty"`
|
||||||
|
ChainWork string `json:"chainwork"`
|
||||||
PreviousHash string `json:"previousblockhash,omitempty"`
|
PreviousHash string `json:"previousblockhash,omitempty"`
|
||||||
NextHash string `json:"nextblockhash,omitempty"`
|
NextHash string `json:"nextblockhash,omitempty"`
|
||||||
|
|
||||||
|
|
44
rpcserver.go
44
rpcserver.go
|
@ -1209,31 +1209,23 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
|
||||||
return nil, internalRPCError(err.Error(), context)
|
return nil, internalRPCError(err.Error(), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the block height from chain.
|
|
||||||
blockHeight, err := s.cfg.Chain.BlockHeightByHash(hash)
|
|
||||||
if err != nil {
|
|
||||||
context := "Failed to obtain block height"
|
|
||||||
return nil, internalRPCError(err.Error(), context)
|
|
||||||
}
|
|
||||||
blk.SetHeight(blockHeight)
|
|
||||||
best := s.cfg.Chain.BestSnapshot()
|
|
||||||
|
|
||||||
// Get next block hash unless there are none.
|
|
||||||
var nextHashString string
|
|
||||||
if blockHeight < best.Height {
|
|
||||||
nextHash, err := s.cfg.Chain.BlockHashByHeight(blockHeight + 1)
|
|
||||||
if err != nil {
|
|
||||||
context := "No next block"
|
|
||||||
return nil, internalRPCError(err.Error(), context)
|
|
||||||
}
|
|
||||||
nextHashString = nextHash.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
params := s.cfg.ChainParams
|
params := s.cfg.ChainParams
|
||||||
blockHeader := &blk.MsgBlock().Header
|
blockHeader := &blk.MsgBlock().Header
|
||||||
|
|
||||||
|
// Get further details (height, confirmations, nexthash, mediantime, etc.) from chain.
|
||||||
|
attrs, best, err := s.cfg.Chain.BlockAttributesByHash(hash, &blockHeader.PrevBlock)
|
||||||
|
if err != nil {
|
||||||
|
context := "Failed to obtain block details"
|
||||||
|
return nil, internalRPCError(err.Error(), context)
|
||||||
|
}
|
||||||
|
|
||||||
var prevHashString string
|
var prevHashString string
|
||||||
if blockHeight > 0 {
|
if attrs.PrevHash != nil {
|
||||||
prevHashString = blockHeader.PrevBlock.String()
|
prevHashString = attrs.PrevHash.String()
|
||||||
|
}
|
||||||
|
var nextHashString string
|
||||||
|
if attrs.NextHash != nil {
|
||||||
|
nextHashString = attrs.NextHash.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
base := btcjson.GetBlockVerboseResultBase{
|
base := btcjson.GetBlockVerboseResultBase{
|
||||||
|
@ -1244,13 +1236,15 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
|
||||||
PreviousHash: prevHashString,
|
PreviousHash: prevHashString,
|
||||||
Nonce: blockHeader.Nonce,
|
Nonce: blockHeader.Nonce,
|
||||||
Time: blockHeader.Timestamp.Unix(),
|
Time: blockHeader.Timestamp.Unix(),
|
||||||
Confirmations: int64(1 + best.Height - blockHeight),
|
MedianTime: attrs.MedianTime.Unix(),
|
||||||
Height: int64(blockHeight),
|
Confirmations: int64(attrs.Confirmations),
|
||||||
|
Height: int64(attrs.Height),
|
||||||
Size: int32(len(blkBytes)),
|
Size: int32(len(blkBytes)),
|
||||||
StrippedSize: int32(blk.MsgBlock().SerializeSizeStripped()),
|
StrippedSize: int32(blk.MsgBlock().SerializeSizeStripped()),
|
||||||
Weight: int32(blockchain.GetBlockWeight(blk)),
|
Weight: int32(blockchain.GetBlockWeight(blk)),
|
||||||
Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
|
Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
|
||||||
Difficulty: getDifficultyRatio(blockHeader.Bits, params),
|
Difficulty: getDifficultyRatio(blockHeader.Bits, params),
|
||||||
|
ChainWork: attrs.ChainWork.Text(16),
|
||||||
NextHash: nextHashString,
|
NextHash: nextHashString,
|
||||||
ClaimTrie: blockHeader.ClaimTrie.String(),
|
ClaimTrie: blockHeader.ClaimTrie.String(),
|
||||||
}
|
}
|
||||||
|
@ -1275,7 +1269,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
|
||||||
for i, tx := range txns {
|
for i, tx := range txns {
|
||||||
rawTxn, err := createTxRawResult(params, tx.MsgTx(),
|
rawTxn, err := createTxRawResult(params, tx.MsgTx(),
|
||||||
tx.Hash().String(), blockHeader, hash.String(),
|
tx.Hash().String(), blockHeader, hash.String(),
|
||||||
blockHeight, best.Height)
|
attrs.Height, best.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,9 +260,11 @@ var helpDescsEnUS = map[string]string{
|
||||||
"getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)",
|
"getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)",
|
||||||
"getblockverboseresult-nTx": "The number of transactions (aka, count of TX)",
|
"getblockverboseresult-nTx": "The number of transactions (aka, count of TX)",
|
||||||
"getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT",
|
"getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT",
|
||||||
|
"getblockverboseresult-mediantime": "The median block time in seconds since 1 Jan 1970 GMT",
|
||||||
"getblockverboseresult-nonce": "The block nonce",
|
"getblockverboseresult-nonce": "The block nonce",
|
||||||
"getblockverboseresult-bits": "The bits which represent the block difficulty",
|
"getblockverboseresult-bits": "The bits which represent the block difficulty",
|
||||||
"getblockverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty",
|
"getblockverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty",
|
||||||
|
"getblockverboseresult-chainwork": "Expected number of hashes required to produce the chain up to this block (in hex)",
|
||||||
"getblockverboseresult-previousblockhash": "The hash of the previous block",
|
"getblockverboseresult-previousblockhash": "The hash of the previous block",
|
||||||
"getblockverboseresult-nextblockhash": "The hash of the next block (only if there is one)",
|
"getblockverboseresult-nextblockhash": "The hash of the next block (only if there is one)",
|
||||||
"getblockverboseresult-strippedsize": "The size of the block without witness data",
|
"getblockverboseresult-strippedsize": "The size of the block without witness data",
|
||||||
|
|
Loading…
Reference in a new issue