refactor calcPastMedianTime

This commit is contained in:
Luke Williams 2019-02-22 05:24:49 +01:00
parent bd4b1ebf96
commit 9aa4a39940
3 changed files with 36 additions and 32 deletions

View file

@ -18,6 +18,8 @@
package consensus
import (
"math/big"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/state"
"github.com/ubiq/go-ubiq/core/types"
@ -45,6 +47,10 @@ type ChainReader interface {
// GetBlock retrieves a block from the database by hash and number.
GetBlock(hash common.Hash, number uint64) *types.Block
// CalcPastMedianTime calculates the median time of the previous few blocks
// prior to, and including, the passed block node.
CalcPastMedianTime(number uint64, parent *types.Header) *big.Int
}
// Engine is an algorithm agnostic consensus engine.

View file

@ -536,31 +536,8 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash) bool {
// prior to, and including, the passed block node.
//
// Modified from btcsuite
func (bc *BlockChain) CalcPastMedianTime(number uint64) *big.Int {
// Genesis block.
if number == 0 {
return bc.Genesis().Time()
}
timestamps := make([]*big.Int, medianTimeBlocks)
numNodes := 0
iterNode := bc.GetHeaderByNumber(number)
ancestors := make(map[common.Hash]*types.Header)
for i, ancestor := range bc.GetBlockHeadersFromHash(iterNode.Hash(), medianTimeBlocks) {
ancestors[ancestor.Hash()] = ancestor
timestamps[i] = ancestor.Time
numNodes++
}
// Prune the slice to the actual number of available timestamps which
// will be fewer than desired near the beginning of the block chain
// and sort them.
timestamps = timestamps[:numNodes]
sort.Sort(BigIntSlice(timestamps))
medianTimestamp := timestamps[numNodes/2]
return medianTimestamp
func (bc *BlockChain) CalcPastMedianTime(number uint64, parent *types.Header) *big.Int {
return bc.hc.CalcPastMedianTime(number, parent)
}
// GetBlock retrieves a block from the database by hash and number,

View file

@ -38,6 +38,8 @@ const (
headerCacheLimit = 512
tdCacheLimit = 1024
numberCacheLimit = 2048
hashCacheLimit = 64
medianTimeBlocks = 11
)
// HeaderChain implements the basic block header chain logic that is shared by
@ -57,6 +59,7 @@ type HeaderChain struct {
headerCache *lru.Cache // Cache for the most recent block headers
tdCache *lru.Cache // Cache for the most recent block total difficulties
numberCache *lru.Cache // Cache for the most recent block numbers
hashCache *lru.Cache
procInterrupt func() bool
@ -72,6 +75,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
headerCache, _ := lru.New(headerCacheLimit)
tdCache, _ := lru.New(tdCacheLimit)
numberCache, _ := lru.New(numberCacheLimit)
hashCache, _ := lru.New(hashCacheLimit)
// Seed a fast but crypto originating random generator
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
@ -85,6 +89,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
headerCache: headerCache,
tdCache: tdCache,
numberCache: numberCache,
hashCache: hashCache,
procInterrupt: procInterrupt,
rand: mrand.New(mrand.NewSource(seed.Int64())),
engine: engine,
@ -115,6 +120,7 @@ func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 {
number := GetBlockNumber(hc.chainDb, hash)
if number != missingNumber {
hc.numberCache.Add(hash, number)
hc.hashCache.Add(number, hash)
}
return number
}
@ -190,6 +196,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
hc.headerCache.Add(hash, header)
hc.numberCache.Add(hash, number)
hc.hashCache.Add(number, hash)
return
}
@ -354,8 +361,7 @@ func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int {
// prior to, and including, the passed block node.
//
// Modified from btcsuite
func (hc *HeaderChain) CalcPastMedianTime(number uint64) *big.Int {
medianTimeBlocks := uint64(11)
func (hc *HeaderChain) CalcPastMedianTime(number uint64, parent *types.Header) *big.Int {
// Genesis block.
if number == 0 {
@ -364,13 +370,22 @@ func (hc *HeaderChain) CalcPastMedianTime(number uint64) *big.Int {
timestamps := make([]*big.Int, medianTimeBlocks)
numNodes := 0
iterNode := hc.GetHeaderByNumber(number)
limit := uint64(0)
if number >= medianTimeBlocks {
limit = number - medianTimeBlocks + 1
}
ancestors := make(map[common.Hash]*types.Header)
for i, ancestor := range hc.GetBlockHeadersFromHash(iterNode.Hash(), medianTimeBlocks) {
ancestors[ancestor.Hash()] = ancestor
timestamps[i] = ancestor.Time
for i := number; i >= limit; i-- {
if parent != nil && i == number {
timestamps[numNodes] = parent.Time
} else {
header := hc.GetHeaderByNumber(i)
timestamps[numNodes] = header.Time
}
numNodes++
if i == 0 {
break
}
}
// Prune the slice to the actual number of available timestamps which
@ -424,6 +439,11 @@ func (hc *HeaderChain) HasHeader(hash common.Hash) bool {
// GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found.
func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
// check cache
if cache, ok := hc.hashCache.Get(number); ok {
return hc.GetHeader(cache.(common.Hash), number)
}
hash := GetCanonicalHash(hc.chainDb, number)
if hash == (common.Hash{}) {
return nil
@ -476,6 +496,7 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
hc.headerCache.Purge()
hc.tdCache.Purge()
hc.numberCache.Purge()
hc.hashCache.Purge()
if hc.currentHeader == nil {
hc.currentHeader = hc.genesisHeader