From c6820a988e149c51000de34efc25be4de748be83 Mon Sep 17 00:00:00 2001 From: Julian Yap Date: Sun, 4 Dec 2016 00:11:39 -1000 Subject: [PATCH] Implement CalcPastMedianTime to HeaderChain --- core/headerchain.go | 55 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/core/headerchain.go b/core/headerchain.go index c89624971f..8b6f532a71 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -23,6 +23,7 @@ import ( "math/big" mrand "math/rand" "runtime" + "sort" "sync" "sync/atomic" "time" @@ -356,6 +357,27 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co return chain } +func (hc *HeaderChain) GetBlockHeadersFromHash(hash common.Hash, max uint64) []*types.Header { + // Get the origin header from which to fetch + header := hc.GetHeader(hash) + if header == nil { + return nil + } + // Iterate the headers until enough is collected or the genesis reached + chain := make([]*types.Header, 0, max) + for i := uint64(0); i < max; i++ { + next := header.ParentHash + if header = hc.GetHeader(next); header == nil { + break + } + chain = append(chain, hc.GetHeader(next)) + if header.Number.Cmp(common.Big0) == 0 { + break + } + } + return chain +} + // GetTd retrieves a block's total difficulty in the canonical chain from the // database by hash and number, caching it if found. func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { @@ -378,6 +400,39 @@ func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { return hc.GetTd(hash, hc.GetBlockNumber(hash)) } +// calcPastMedianTime calculates the median time of the previous few blocks +// prior to, and including, the passed block node. +// +// Modified from btcsuite +func (hc *HeaderChain) CalcPastMedianTime(number uint64) *big.Int { + medianTimeBlocks := uint64(11) + + // Genesis block. + if number == 0 { + return hc.GetHeaderByNumber(0).Time + } + + timestamps := make([]*big.Int, medianTimeBlocks) + numNodes := 0 + iterNode := hc.GetHeaderByNumber(number) + + ancestors := make(map[common.Hash]*types.Header) + for i, ancestor := range hc.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 +} + // WriteTd stores a block's total difficulty into the database, also caching it // along the way. func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error {