diff --git a/blockchain/chain.go b/blockchain/chain.go index 40cf0434..aa1f407e 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -164,6 +164,7 @@ type BlockChain struct { checkpointsByHeight map[int32]*chaincfg.Checkpoint db database.DB chainParams *chaincfg.Params + timeSource MedianTimeSource notifications NotificationCallback sigCache *txscript.SigCache indexManager IndexManager @@ -1331,7 +1332,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla // - 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() @@ -1344,7 +1345,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.timestamp.Before(minus24Hours) { return false } @@ -1397,6 +1398,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 @@ -1448,6 +1457,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, diff --git a/blockchain/chain_test.go b/blockchain/chain_test.go index 0cf9090e..02ff7230 100644 --- a/blockchain/chain_test.go +++ b/blockchain/chain_test.go @@ -48,10 +48,8 @@ func TestHaveBlock(t *testing.T) { chain.DisableCheckpoints(true) blockchain.TstSetCoinbaseMaturity(1) - timeSource := blockchain.NewMedianTime() for i := 1; i < len(blocks); i++ { - isOrphan, err := chain.ProcessBlock(blocks[i], timeSource, - blockchain.BFNone) + isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone) if err != nil { t.Errorf("ProcessBlock fail on block %v: %v\n", i, err) return @@ -65,7 +63,7 @@ func TestHaveBlock(t *testing.T) { // Insert an orphan block. isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000), - timeSource, blockchain.BFNone) + blockchain.BFNone) if err != nil { t.Errorf("Unable to process block: %v", err) return diff --git a/blockchain/common_test.go b/blockchain/common_test.go index 9021b048..aebf8f7a 100644 --- a/blockchain/common_test.go +++ b/blockchain/common_test.go @@ -110,6 +110,7 @@ func chainSetup(dbName string) (*blockchain.BlockChain, func(), error) { chain, err := blockchain.New(&blockchain.Config{ DB: db, ChainParams: &chaincfg.MainNetParams, + TimeSource: blockchain.NewMedianTime(), }) if err != nil { teardown() diff --git a/blockchain/example_test.go b/blockchain/example_test.go index aba59557..ef39b72c 100644 --- a/blockchain/example_test.go +++ b/blockchain/example_test.go @@ -41,27 +41,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() - // 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 := btcutil.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 process block: %v\n", err) return diff --git a/blockchain/process.go b/blockchain/process.go index 930966f1..70180047 100644 --- a/blockchain/process.go +++ b/blockchain/process.go @@ -125,7 +125,7 @@ func (b *BlockChain) processOrphans(hash *wire.ShaHash, flags BehaviorFlags) err // when the error is nil. // // This function is safe for concurrent access. -func (b *BlockChain) ProcessBlock(block *btcutil.Block, timeSource MedianTimeSource, flags BehaviorFlags) (bool, error) { +func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { b.chainLock.Lock() defer b.chainLock.Unlock() @@ -152,7 +152,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, timeSource MedianTimeSou } // Perform preliminary sanity checks on the block and its transactions. - err = checkBlockSanity(block, b.chainParams.PowLimit, timeSource, flags) + err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags) if err != nil { return false, err } diff --git a/blockchain/reorganization_test.go b/blockchain/reorganization_test.go index 5ae4d3b2..efd6706f 100644 --- a/blockchain/reorganization_test.go +++ b/blockchain/reorganization_test.go @@ -58,10 +58,9 @@ func TestReorganization(t *testing.T) { chain.DisableCheckpoints(true) blockchain.TstSetCoinbaseMaturity(1) - timeSource := blockchain.NewMedianTime() expectedOrphans := map[int]struct{}{5: {}, 6: {}} for i := 1; i < len(blocks); i++ { - isOrphan, err := chain.ProcessBlock(blocks[i], timeSource, blockchain.BFNone) + isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone) if err != nil { t.Errorf("ProcessBlock fail on block %v: %v\n", i, err) return diff --git a/blockmanager.go b/blockmanager.go index 26659d01..f8918751 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -496,7 +496,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 } @@ -564,8 +564,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { // Process the block to include validation, best chain selection, orphan // handling, etc. - isOrphan, err := b.chain.ProcessBlock(bmsg.block, - b.server.timeSource, behaviorFlags) + isOrphan, err := b.chain.ProcessBlock(bmsg.block, 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 @@ -1121,7 +1120,7 @@ out: case processBlockMsg: isOrphan, err := b.chain.ProcessBlock(msg.block, - b.server.timeSource, msg.flags) + msg.flags) if err != nil { msg.reply <- processBlockResponse{ isOrphan: false, @@ -1402,6 +1401,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, diff --git a/cmd/addblock/import.go b/cmd/addblock/import.go index a6f2d86a..f6aab615 100644 --- a/cmd/addblock/import.go +++ b/cmd/addblock/import.go @@ -32,7 +32,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 @@ -129,8 +128,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 } @@ -329,6 +327,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 { @@ -343,7 +342,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(), }, nil }