blockchain: Associate time src with chain instance.

Upstream commit 00ebb9d14d

Also, the merge commit contains the necessary decred-specific
alterations.
This commit is contained in:
Dave Collins 2016-11-11 18:03:25 -06:00
commit 748ecb2a52
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
10 changed files with 58 additions and 65 deletions

View File

@ -193,6 +193,7 @@ type BlockChain struct {
db database.DB
dbInfo *databaseInfo
chainParams *chaincfg.Params
timeSource MedianTimeSource
notifications NotificationCallback
sigCache *txscript.SigCache
indexManager IndexManager
@ -1703,8 +1704,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List,
// forceReorganizationToBlock forces a reorganization of the block chain to the
// block hash requested, so long as it matches up with the current organization
// of the best chain.
func (b *BlockChain) forceHeadReorganization(formerBest chainhash.Hash,
newBest chainhash.Hash, timeSource MedianTimeSource) error {
func (b *BlockChain) forceHeadReorganization(formerBest chainhash.Hash, newBest chainhash.Hash) error {
if formerBest.IsEqual(&newBest) {
return fmt.Errorf("can't reorganize to the same block")
}
@ -1773,10 +1773,10 @@ func (b *BlockChain) forceHeadReorganization(formerBest chainhash.Hash,
return err
}
err = checkBlockSanity(newBestBlock,
timeSource,
BFNone,
b.chainParams)
err = checkBlockSanity(newBestBlock, b.timeSource, BFNone, b.chainParams)
if err != nil {
return err
}
err = b.checkConnectBlock(newBestNode, newBestBlock, view, nil)
if err != nil {
@ -1792,11 +1792,10 @@ func (b *BlockChain) forceHeadReorganization(formerBest chainhash.Hash,
}
// ForceHeadReorganization is the exported version of forceHeadReorganization.
func (b *BlockChain) ForceHeadReorganization(formerBest chainhash.Hash,
newBest chainhash.Hash, timeSource MedianTimeSource) error {
func (b *BlockChain) ForceHeadReorganization(formerBest chainhash.Hash, newBest chainhash.Hash) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.forceHeadReorganization(formerBest, newBest, timeSource)
return b.forceHeadReorganization(formerBest, newBest)
}
// connectBestChain handles connecting the passed block to the chain while
@ -2001,7 +2000,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *dcrutil.Block,
// - Latest block has a timestamp newer than 24 hours ago
//
// This function is safe for concurrent access.
func (b *BlockChain) IsCurrent(timeSource MedianTimeSource) bool {
func (b *BlockChain) IsCurrent() bool {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
@ -2014,7 +2013,7 @@ func (b *BlockChain) IsCurrent(timeSource MedianTimeSource) bool {
// Not current if the latest best block has a timestamp before 24 hours
// ago.
minus24Hours := timeSource.AdjustedTime().Add(-24 * time.Hour)
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour)
if b.bestNode.header.Timestamp.Before(minus24Hours) {
return false
}
@ -2067,6 +2066,14 @@ type Config struct {
// This field is required.
ChainParams *chaincfg.Params
// TimeSource defines the median time source to use for things such as
// block processing and determining whether or not the chain is current.
//
// The caller is expected to keep a reference to the time source as well
// and add time samples from other peers on the network so the local
// time is adjusted to be in agreement with other peers.
TimeSource MedianTimeSource
// Notifications defines a callback to which notifications will be sent
// when various events take place. See the documentation for
// Notification and NotificationType for details on the types and
@ -2118,6 +2125,7 @@ func New(config *Config) (*BlockChain, error) {
checkpointsByHeight: checkpointsByHeight,
db: config.DB,
chainParams: params,
timeSource: config.TimeSource,
notifications: config.Notifications,
sigCache: config.SigCache,
indexManager: config.IndexManager,

View File

@ -56,7 +56,6 @@ func TestBlockchainFunctions(t *testing.T) {
}
// Insert blocks 1 to 168 and perform various tests.
timeSource := blockchain.NewMedianTime()
for i := 1; i <= 168; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
if err != nil {
@ -64,7 +63,7 @@ func TestBlockchainFunctions(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}

View File

@ -112,6 +112,7 @@ func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain,
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: params,
TimeSource: blockchain.NewMedianTime(),
})
if err != nil {

View File

@ -42,28 +42,25 @@ func ExampleBlockChain_ProcessBlock() {
// Create a new BlockChain instance using the underlying database for
// the main bitcoin network. This example does not demonstrate some
// of the other available configuration options such as specifying a
// notification callback and signature cache.
// notification callback and signature cache. Also, the caller would
// ordinarily keep a reference to the median time source and add time
// values obtained from other peers on the network so the local time is
// adjusted to be in agreement with other peers.
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: &chaincfg.MainNetParams,
TimeSource: blockchain.NewMedianTime(),
})
if err != nil {
fmt.Printf("Failed to create chain instance: %v\n", err)
return
}
// Create a new median time source that is required by the upcoming
// call to ProcessBlock. Ordinarily this would also add time values
// obtained from other peers on the network so the local time is
// adjusted to be in agreement with other peers.
timeSource := blockchain.NewMedianTime()
// Create a new BlockChain instance using the underlying database for
// the main bitcoin network. This example does not demonstrate some
// of the other available configuration options such as specifying a
// notification callback and signature cache.
// Process a block. For this example, we are going to intentionally
// cause an error by trying to process the genesis block which already
// exists.
genesisBlock := dcrutil.NewBlock(chaincfg.MainNetParams.GenesisBlock)
_, isOrphan, err := chain.ProcessBlock(genesisBlock, timeSource, blockchain.BFNone)
_, isOrphan, err := chain.ProcessBlock(genesisBlock, blockchain.BFNone)
if err != nil {
fmt.Printf("Failed to create chain instance: %v\n", err)
return

View File

@ -32,7 +32,6 @@ func TestFullBlocks(t *testing.T) {
// testAcceptedBlock attempts to process the block in the provided test
// instance and ensures that it was accepted according to the flags
// specified in the test.
timeSource := blockchain.NewMedianTime()
testAcceptedBlock := func(item fullblocktests.AcceptedBlock) {
blockHeight := item.Block.Header.Height
block := dcrutil.NewBlock(item.Block)
@ -40,7 +39,7 @@ func TestFullBlocks(t *testing.T) {
item.Name, block.Sha(), blockHeight)
isMainChain, isOrphan, err := chain.ProcessBlock(block,
timeSource, blockchain.BFNone)
blockchain.BFNone)
if err != nil {
t.Fatalf("block %q (hash %s, height %d) should "+
"have been accepted: %v", item.Name,
@ -72,8 +71,7 @@ func TestFullBlocks(t *testing.T) {
t.Logf("Testing block %s (hash %s, height %d)",
item.Name, block.Sha(), blockHeight)
_, _, err := chain.ProcessBlock(block, timeSource,
blockchain.BFNone)
_, _, err := chain.ProcessBlock(block, blockchain.BFNone)
if err == nil {
t.Fatalf("block %q (hash %s, height %d) should not "+
"have been accepted", item.Name, block.Sha(),
@ -106,8 +104,7 @@ func TestFullBlocks(t *testing.T) {
t.Logf("Testing block %s (hash %s, height %d)",
item.Name, block.Sha(), blockHeight)
_, isOrphan, err := chain.ProcessBlock(block, timeSource,
blockchain.BFNone)
_, isOrphan, err := chain.ProcessBlock(block, blockchain.BFNone)
if err != nil {
// Ensure the error code is of the expected type.
if _, ok := err.(blockchain.RuleError); !ok {

View File

@ -126,8 +126,7 @@ func (b *BlockChain) processOrphans(hash *chainhash.Hash, flags BehaviorFlags) e
// or on a side chain. True means it's on the main chain.
//
// This function is safe for concurrent access.
func (b *BlockChain) ProcessBlock(block *dcrutil.Block,
timeSource MedianTimeSource, flags BehaviorFlags) (bool, bool, error) {
func (b *BlockChain) ProcessBlock(block *dcrutil.Block, flags BehaviorFlags) (bool, bool, error) {
b.chainLock.Lock()
defer b.chainLock.Unlock()
@ -160,7 +159,7 @@ func (b *BlockChain) ProcessBlock(block *dcrutil.Block,
}
// Perform preliminary sanity checks on the block and its transactions.
err = checkBlockSanity(block, timeSource, flags, b.chainParams)
err = checkBlockSanity(block, b.timeSource, flags, b.chainParams)
if err != nil {
return false, false, err
}

View File

@ -57,7 +57,6 @@ func reorgTestLong(t *testing.T) {
}
// Load up the short chain
timeSource := blockchain.NewMedianTime()
finalIdx1 := 179
for i := 1; i < finalIdx1+1; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
@ -66,7 +65,7 @@ func reorgTestLong(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}
@ -102,7 +101,7 @@ func reorgTestLong(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error: %v", err.Error())
}
@ -168,8 +167,6 @@ func reorgTestShort(t *testing.T) {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
timeSource := blockchain.NewMedianTime()
// Load the long chain and begin loading blocks from that too,
// forcing a reorganization
// Load up the rest of the blocks up to HEAD.
@ -201,7 +198,7 @@ func reorgTestShort(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}
@ -218,7 +215,7 @@ func reorgTestShort(t *testing.T) {
}
bl.SetHeight(int64(i + j))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error: %v", err.Error())
}
@ -287,7 +284,6 @@ func reorgTestForced(t *testing.T) {
}
// Load up the short chain
timeSource := blockchain.NewMedianTime()
finalIdx1 := 131
var oldBestHash *chainhash.Hash
for i := 1; i < finalIdx1+1; i++ {
@ -300,7 +296,7 @@ func reorgTestForced(t *testing.T) {
oldBestHash = bl.Sha()
}
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}
@ -334,13 +330,13 @@ func reorgTestForced(t *testing.T) {
}
forkBl.SetHeight(forkPoint)
_, _, err = chain.ProcessBlock(forkBl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(forkBl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error: %v", err.Error())
}
newBestHash := forkBl.Sha()
err = chain.ForceHeadReorganization(*oldBestHash, *newBestHash, timeSource)
err = chain.ForceHeadReorganization(*oldBestHash, *newBestHash)
if err != nil {
t.Fatalf("failed forced reorganization: %v", err.Error())
}

View File

@ -180,7 +180,7 @@ func TestBlockValidationRules(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}
@ -257,7 +257,7 @@ func TestBlockValidationRules(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock error at height %v: %v", i,
err.Error())
@ -330,7 +330,7 @@ func TestBlockValidationRules(t *testing.T) {
b153test = dcrutil.NewBlock(badDifficulty153)
b153test.SetHeight(int64(testsIdx1))
_, _, err = chain.ProcessBlock(b153test, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(b153test, blockchain.BFNone)
if err == nil || err.(blockchain.RuleError).ErrorCode !=
blockchain.ErrUnexpectedDifficulty {
t.Errorf("Failed to get error or correct error for "+
@ -345,7 +345,7 @@ func TestBlockValidationRules(t *testing.T) {
b153test = dcrutil.NewBlock(badBlockSize153)
b153test.SetHeight(int64(testsIdx1))
_, _, err = chain.ProcessBlock(b153test, timeSource, blockchain.BFNoPoWCheck)
_, _, err = chain.ProcessBlock(b153test, blockchain.BFNoPoWCheck)
if err == nil || err.(blockchain.RuleError).ErrorCode !=
blockchain.ErrWrongBlockSize {
t.Errorf("Failed to get error or correct error for "+
@ -360,7 +360,7 @@ func TestBlockValidationRules(t *testing.T) {
b153test = dcrutil.NewBlock(badHash153)
b153test.SetHeight(int64(testsIdx1))
_, _, err = chain.ProcessBlock(b153test, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(b153test, blockchain.BFNone)
if err == nil || err.(blockchain.RuleError).ErrorCode !=
blockchain.ErrHighHash {
t.Errorf("Failed to get error or correct error for "+
@ -741,7 +741,7 @@ func TestBlockValidationRules(t *testing.T) {
block153MsgBlock.FromBytes(block153Bytes)
b153test = dcrutil.NewBlock(block153MsgBlock)
b153test.SetHeight(int64(testsIdx1))
_, _, err = chain.ProcessBlock(b153test, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(b153test, blockchain.BFNone)
if err != nil {
t.Errorf("Got unexpected error processing block 153 %v", err)
}
@ -1420,7 +1420,7 @@ func TestBlockValidationRules(t *testing.T) {
b154test.SetHeight(int64(testsIdx2))
// Throws ProcessBlock error through checkBlockContext.
_, _, err = chain.ProcessBlock(b154test, timeSource, blockchain.BFNoPoWCheck)
_, _, err = chain.ProcessBlock(b154test, blockchain.BFNoPoWCheck)
if err == nil || err.(blockchain.RuleError).ErrorCode !=
blockchain.ErrBadBlockHeight {
t.Errorf("ProcessBlock ErrBadBlockHeight test no or unexpected "+
@ -1780,7 +1780,7 @@ func TestBlockValidationRules(t *testing.T) {
}
}
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock error: %v", err.Error())
}
@ -2008,7 +2008,6 @@ func TestBlockchainSpendJournal(t *testing.T) {
}
// Load up the short chain
timeSource := blockchain.NewMedianTime()
finalIdx1 := 179
for i := 1; i < finalIdx1+1; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
@ -2017,7 +2016,7 @@ func TestBlockchainSpendJournal(t *testing.T) {
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}

View File

@ -865,7 +865,7 @@ func (b *blockManager) handleTxMsg(tmsg *txMsg) {
// current returns true if we believe we are synced with our peers, false if we
// still have blocks to check
func (b *blockManager) current() bool {
if !b.chain.IsCurrent(b.server.timeSource) {
if !b.chain.IsCurrent() {
return false
}
@ -1124,7 +1124,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) {
// Process the block to include validation, best chain selection, orphan
// handling, etc.
onMainChain, isOrphan, err := b.chain.ProcessBlock(bmsg.block,
b.server.timeSource, behaviorFlags)
behaviorFlags)
if err != nil {
// When the error is a rule error, it means the block was simply
// rejected as opposed to something actually going wrong, so log
@ -1821,9 +1821,7 @@ out:
case forceReorganizationMsg:
err := b.chain.ForceHeadReorganization(
msg.formerBest,
msg.newBest,
b.server.timeSource)
msg.formerBest, msg.newBest)
// Reorganizing has succeeded, so we need to
// update the chain state.
@ -1906,7 +1904,7 @@ out:
case processBlockMsg:
onMainChain, isOrphan, err := b.chain.ProcessBlock(
msg.block, b.server.timeSource, msg.flags)
msg.block, msg.flags)
if err != nil {
msg.reply <- processBlockResponse{
onMainChain: onMainChain,
@ -2741,6 +2739,7 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager) (*blockMan
bm.chain, err = blockchain.New(&blockchain.Config{
DB: s.db,
ChainParams: s.chainParams,
TimeSource: s.timeSource,
Notifications: bm.handleNotifyMsg,
SigCache: s.sigCache,
IndexManager: indexManager,

View File

@ -35,7 +35,6 @@ type importResults struct {
type blockImporter struct {
db database.DB
chain *blockchain.BlockChain
medianTime blockchain.MedianTimeSource
r io.ReadSeeker
processQueue chan []byte
doneChan chan bool
@ -133,8 +132,7 @@ func (bi *blockImporter) processBlock(serializedBlock []byte) (bool, error) {
// Ensure the blocks follows all of the chain rules and match up to the
// known checkpoints.
_, isOrphan, err := bi.chain.ProcessBlock(block, bi.medianTime,
blockchain.BFFastAdd)
_, isOrphan, err := bi.chain.ProcessBlock(block, blockchain.BFFastAdd)
if err != nil {
return false, err
}
@ -340,6 +338,7 @@ func newBlockImporter(db database.DB, r io.ReadSeeker) (*blockImporter, error) {
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: activeNetParams,
TimeSource: blockchain.NewMedianTime(),
IndexManager: indexManager,
})
if err != nil {
@ -354,7 +353,6 @@ func newBlockImporter(db database.DB, r io.ReadSeeker) (*blockImporter, error) {
errChan: make(chan error),
quit: make(chan struct{}),
chain: chain,
medianTime: blockchain.NewMedianTime(),
lastLogTime: time.Now(),
startTime: time.Now(),
}, nil