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 package consensus
import ( import (
"math/big"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/state"
"github.com/ubiq/go-ubiq/core/types" "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 retrieves a block from the database by hash and number.
GetBlock(hash common.Hash, number uint64) *types.Block 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. // 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. // prior to, and including, the passed block node.
// //
// Modified from btcsuite // Modified from btcsuite
func (bc *BlockChain) CalcPastMedianTime(number uint64) *big.Int { func (bc *BlockChain) CalcPastMedianTime(number uint64, parent *types.Header) *big.Int {
// Genesis block. return bc.hc.CalcPastMedianTime(number, parent)
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
} }
// GetBlock retrieves a block from the database by hash and number, // GetBlock retrieves a block from the database by hash and number,

View file

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