blockchain: Use int64 timestamps in block nodes.

This modifies the block nodes used in the blockchain package for keeping
track of the block index to use int64 for the timestamps instead of
time.Time.

This is being done because a time.Time takes 24 bytes while an int64
only takes 8 and the plan is to eventually move the entire block index
into memory instead of the current dynamically-loaded version, so
cutting the number of bytes used for the timestamp by a third is highly
desirable.

Also, the consensus code requires working with unix-style timestamps
anyways, so switching over to them in the block node does not seem
unreasonable.

Finally, this does not go so far as to change all of the time.Time
references, particularly those that are in the public API, so it is
purely an internal change.
This commit is contained in:
Dave Collins 2017-01-30 18:32:50 -06:00
parent 9f71f090e6
commit 5ffd552214
No known key found for this signature in database
GPG key ID: B8904D9D9C93D1F2
7 changed files with 49 additions and 51 deletions

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -62,7 +62,7 @@ type blockNode struct {
// Some fields from block headers to aid in best chain selection.
version int32
bits uint32
timestamp time.Time
timestamp int64
}
// newBlockNode returns a new block node for the given block header. It is
@ -81,7 +81,7 @@ func newBlockNode(blockHeader *wire.BlockHeader, blockHash *chainhash.Hash, heig
height: height,
version: blockHeader.Version,
bits: blockHeader.Bits,
timestamp: blockHeader.Timestamp,
timestamp: blockHeader.Timestamp.Unix(),
}
return &node
}
@ -666,7 +666,7 @@ func (b *BlockChain) calcPastMedianTime(startNode *blockNode) (time.Time, error)
// Create a slice of the previous few block timestamps used to calculate
// the median per the number defined by the constant medianTimeBlocks.
timestamps := make([]time.Time, medianTimeBlocks)
timestamps := make([]int64, medianTimeBlocks)
numNodes := 0
iterNode := startNode
for i := 0; i < medianTimeBlocks && iterNode != nil; i++ {
@ -705,7 +705,7 @@ func (b *BlockChain) calcPastMedianTime(startNode *blockNode) (time.Time, error)
// however, be aware that should the medianTimeBlocks constant ever be
// changed to an even number, this code will be wrong.
medianTimestamp := timestamps[numNodes/2]
return medianTimestamp, nil
return time.Unix(medianTimestamp, 0), nil
}
// CalcPastMedianTime calculates the median time of the previous few blocks
@ -1581,8 +1581,8 @@ func (b *BlockChain) isCurrent() bool {
//
// The chain appears to be current if none of the checks reported
// otherwise.
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour)
return !b.bestNode.timestamp.Before(minus24Hours)
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
return b.bestNode.timestamp >= minus24Hours
}
// IsCurrent returns whether or not the chain believes it is current. Several
@ -1716,8 +1716,8 @@ func New(config *Config) (*BlockChain, error) {
}
params := config.ChainParams
targetTimespan := int64(params.TargetTimespan)
targetTimePerBlock := int64(params.TargetTimePerBlock)
targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{
checkpoints: config.Checkpoints,

View file

@ -1,4 +1,4 @@
// Copyright (c) 2015-2016 The btcsuite developers
// Copyright (c) 2015-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -10,6 +10,7 @@ import (
"fmt"
"math/big"
"sort"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
@ -1092,7 +1093,7 @@ func (b *BlockChain) createChainState() error {
numTxns := uint64(len(genesisBlock.MsgBlock().Transactions))
blockSize := uint64(genesisBlock.MsgBlock().SerializeSize())
b.stateSnapshot = newBestState(b.bestNode, blockSize, numTxns, numTxns,
b.bestNode.timestamp)
time.Unix(b.bestNode.timestamp, 0))
// Create the initial the database chain state including creating the
// necessary index buckets and inserting the genesis block.

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -158,14 +158,16 @@ func CalcWork(bits uint32) *big.Int {
// known good checkpoint.
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below.
durationVal := int64(duration)
durationVal := int64(duration / time.Second)
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
// The test network rules allow minimum difficulty blocks after more
// than twice the desired amount of time needed to generate a block has
// elapsed.
if b.chainParams.ReduceMinDifficulty {
if durationVal > int64(b.chainParams.MinDiffReductionTime) {
reductionTime := int64(b.chainParams.MinDiffReductionTime /
time.Second)
if durationVal > reductionTime {
return b.chainParams.PowLimitBits
}
}
@ -243,9 +245,10 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
if b.chainParams.ReduceMinDifficulty {
// Return minimum difficulty when more than the desired
// amount of time has elapsed without mining a block.
reductionTime := b.chainParams.MinDiffReductionTime
allowMinTime := lastNode.timestamp.Add(reductionTime)
if newBlockTime.After(allowMinTime) {
reductionTime := int64(b.chainParams.MinDiffReductionTime /
time.Second)
allowMinTime := lastNode.timestamp + reductionTime
if newBlockTime.Unix() > allowMinTime {
return b.chainParams.PowLimitBits, nil
}
@ -286,7 +289,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// Limit the amount of adjustment that can occur to the previous
// difficulty.
actualTimespan := lastNode.timestamp.UnixNano() - firstNode.timestamp.UnixNano()
actualTimespan := lastNode.timestamp - firstNode.timestamp
adjustedTimespan := actualTimespan
if actualTimespan < b.minRetargetTimespan {
adjustedTimespan = b.minRetargetTimespan
@ -301,7 +304,8 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// result.
oldTarget := CompactToBig(lastNode.bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
newTarget.Div(newTarget, big.NewInt(int64(b.chainParams.TargetTimespan)))
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
// Limit new value to the proof of work limit.
if newTarget.Cmp(b.chainParams.PowLimit) > 0 {
@ -317,7 +321,8 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
log.Debugf("Old target %08x (%064x)", lastNode.bits, oldTarget)
log.Debugf("New target %08x (%064x)", newTargetBits, CompactToBig(newTargetBits))
log.Debugf("Actual timespan %v, adjusted timespan %v, target timespan %v",
time.Duration(actualTimespan), time.Duration(adjustedTimespan),
time.Duration(actualTimespan)*time.Second,
time.Duration(adjustedTimespan)*time.Second,
b.chainParams.TargetTimespan)
return newTargetBits, nil

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -14,7 +14,6 @@ package blockchain
import (
"sort"
"time"
)
// TstSetCoinbaseMaturity makes the ability to set the coinbase maturity
@ -25,7 +24,7 @@ func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) {
// TstTimeSorter makes the internal timeSorter type available to the test
// package.
func TstTimeSorter(times []time.Time) sort.Interface {
func TstTimeSorter(times []int64) sort.Interface {
return timeSorter(times)
}

View file

@ -1,16 +1,12 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"time"
)
// timeSorter implements sort.Interface to allow a slice of timestamps to
// be sorted.
type timeSorter []time.Time
type timeSorter []int64
// Len returns the number of timestamps in the slice. It is part of the
// sort.Interface implementation.
@ -27,5 +23,5 @@ func (s timeSorter) Swap(i, j int) {
// Less returns whether the timstamp with index i should sort before the
// timestamp with index j. It is part of the sort.Interface implementation.
func (s timeSorter) Less(i, j int) bool {
return s[i].Before(s[j])
return s[i] < s[j]
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -8,7 +8,6 @@ import (
"reflect"
"sort"
"testing"
"time"
"github.com/btcsuite/btcd/blockchain"
)
@ -16,31 +15,29 @@ import (
// TestTimeSorter tests the timeSorter implementation.
func TestTimeSorter(t *testing.T) {
tests := []struct {
in []time.Time
want []time.Time
in []int64
want []int64
}{
{
in: []time.Time{
time.Unix(1351228575, 0), // Fri Oct 26 05:16:15 UTC 2012 (Block #205000)
time.Unix(1351228575, 1), // Fri Oct 26 05:16:15 UTC 2012 (+1 nanosecond)
time.Unix(1348310759, 0), // Sat Sep 22 10:45:59 UTC 2012 (Block #200000)
time.Unix(1305758502, 0), // Wed May 18 22:41:42 UTC 2011 (Block #125000)
time.Unix(1347777156, 0), // Sun Sep 16 06:32:36 UTC 2012 (Block #199000)
time.Unix(1349492104, 0), // Sat Oct 6 02:55:04 UTC 2012 (Block #202000)
in: []int64{
1351228575, // Fri Oct 26 05:16:15 UTC 2012 (Block #205000)
1348310759, // Sat Sep 22 10:45:59 UTC 2012 (Block #200000)
1305758502, // Wed May 18 22:41:42 UTC 2011 (Block #125000)
1347777156, // Sun Sep 16 06:32:36 UTC 2012 (Block #199000)
1349492104, // Sat Oct 6 02:55:04 UTC 2012 (Block #202000)
},
want: []time.Time{
time.Unix(1305758502, 0), // Wed May 18 22:41:42 UTC 2011 (Block #125000)
time.Unix(1347777156, 0), // Sun Sep 16 06:32:36 UTC 2012 (Block #199000)
time.Unix(1348310759, 0), // Sat Sep 22 10:45:59 UTC 2012 (Block #200000)
time.Unix(1349492104, 0), // Sat Oct 6 02:55:04 UTC 2012 (Block #202000)
time.Unix(1351228575, 0), // Fri Oct 26 05:16:15 UTC 2012 (Block #205000)
time.Unix(1351228575, 1), // Fri Oct 26 05:16:15 UTC 2012 (+1 nanosecond)
want: []int64{
1305758502, // Wed May 18 22:41:42 UTC 2011 (Block #125000)
1347777156, // Sun Sep 16 06:32:36 UTC 2012 (Block #199000)
1348310759, // Sat Sep 22 10:45:59 UTC 2012 (Block #200000)
1349492104, // Sat Oct 6 02:55:04 UTC 2012 (Block #202000)
1351228575, // Fri Oct 26 05:16:15 UTC 2012 (Block #205000)
},
},
}
for i, test := range tests {
result := make([]time.Time, len(test.in))
result := make([]int64, len(test.in))
copy(result, test.in)
sort.Sort(blockchain.TstTimeSorter(result))
if !reflect.DeepEqual(result, test.want) {

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -1011,7 +1011,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
// "standard" type. The rules for this BIP only apply to transactions
// after the timestamp defined by txscript.Bip16Activation. See
// https://en.bitcoin.it/wiki/BIP_0016 for more details.
enforceBIP0016 := node.timestamp.After(txscript.Bip16Activation)
enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix()
// The number of signature operations must be less than the maximum
// allowed per block. Note that the preliminary sanity checks on a