diff --git a/blockmanager.go b/blockmanager.go index 201ac3ce..757ae71f 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -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. @@ -141,6 +141,7 @@ type blockManager struct { started int32 shutdown int32 chain *blockchain.BlockChain + txMemPool *mempool.TxPool rejectedTxns map[chainhash.Hash]struct{} requestedTxns map[chainhash.Hash]struct{} requestedBlocks map[chainhash.Hash]struct{} @@ -431,7 +432,7 @@ func (b *blockManager) handleTxMsg(tmsg *txMsg) { // Process the transaction to include validation, insertion in the // memory pool, orphan handling, etc. allowOrphans := cfg.MaxOrphanTxs > 0 - acceptedTxs, err := b.server.txMemPool.ProcessTransaction(tmsg.tx, + acceptedTxs, err := b.txMemPool.ProcessTransaction(tmsg.tx, allowOrphans, true, mempool.Tag(tmsg.peer.ID())) // Remove transaction from request maps. Either the mempool/chain @@ -867,7 +868,7 @@ func (b *blockManager) haveInventory(invVect *wire.InvVect) (bool, error) { case wire.InvTypeTx: // Ask the transaction memory pool if the transaction is known // to it in any form (main pool or orphan). - if b.server.txMemPool.HaveTransaction(&invVect.Hash) { + if b.txMemPool.HaveTransaction(&invVect.Hash) { return true, nil } @@ -1215,10 +1216,10 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // transaction are NOT removed recursively because they are still // valid. for _, tx := range block.Transactions()[1:] { - b.server.txMemPool.RemoveTransaction(tx, false) - b.server.txMemPool.RemoveDoubleSpends(tx) - b.server.txMemPool.RemoveOrphan(tx) - acceptedTxs := b.server.txMemPool.ProcessOrphans(tx) + b.txMemPool.RemoveTransaction(tx, false) + b.txMemPool.RemoveDoubleSpends(tx) + b.txMemPool.RemoveOrphan(tx) + acceptedTxs := b.txMemPool.ProcessOrphans(tx) b.server.AnnounceNewTransactions(acceptedTxs) } @@ -1246,13 +1247,13 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // Reinsert all of the transactions (except the coinbase) into // the transaction pool. for _, tx := range block.Transactions()[1:] { - _, _, err := b.server.txMemPool.MaybeAcceptTransaction(tx, + _, _, err := b.txMemPool.MaybeAcceptTransaction(tx, false, false) if err != nil { // Remove the transaction and all transactions // that depend on it if it wasn't accepted into // the transaction pool. - b.server.txMemPool.RemoveTransaction(tx, true) + b.txMemPool.RemoveTransaction(tx, true) } } @@ -1390,64 +1391,16 @@ func (b *blockManager) Pause() chan<- struct{} { return c } -// checkpointSorter implements sort.Interface to allow a slice of checkpoints to -// be sorted. -type checkpointSorter []chaincfg.Checkpoint - -// Len returns the number of checkpoints in the slice. It is part of the -// sort.Interface implementation. -func (s checkpointSorter) Len() int { - return len(s) -} - -// Swap swaps the checkpoints at the passed indices. It is part of the -// sort.Interface implementation. -func (s checkpointSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less returns whether the checkpoint with index i should sort before the -// checkpoint with index j. It is part of the sort.Interface implementation. -func (s checkpointSorter) Less(i, j int) bool { - return s[i].Height < s[j].Height -} - -// mergeCheckpoints returns two slices of checkpoints merged into one slice -// such that the checkpoints are sorted by height. In the case the additional -// checkpoints contain a checkpoint with the same height as a checkpoint in the -// default checkpoints, the additional checkpoint will take precedence and -// overwrite the default one. -func mergeCheckpoints(defaultCheckpoints, additional []chaincfg.Checkpoint) []chaincfg.Checkpoint { - // Create a map of the additional checkpoints to remove duplicates while - // leaving the most recently-specified checkpoint. - extra := make(map[int32]chaincfg.Checkpoint) - for _, checkpoint := range additional { - extra[checkpoint.Height] = checkpoint - } - - // Add all default checkpoints that do not have an override in the - // additional checkpoints. - numDefault := len(defaultCheckpoints) - checkpoints := make([]chaincfg.Checkpoint, 0, numDefault+len(extra)) - for _, checkpoint := range defaultCheckpoints { - if _, exists := extra[checkpoint.Height]; !exists { - checkpoints = append(checkpoints, checkpoint) - } - } - - // Append the additional checkpoints and return the sorted results. - for _, checkpoint := range extra { - checkpoints = append(checkpoints, checkpoint) - } - sort.Sort(checkpointSorter(checkpoints)) - return checkpoints -} - // newBlockManager returns a new bitcoin block manager. // Use Start to begin processing asynchronous block and inv updates. -func newBlockManager(s *server, indexManager blockchain.IndexManager) (*blockManager, error) { +func newBlockManager( + s *server, indexManager blockchain.IndexManager, + chain *blockchain.BlockChain, txMemPool *mempool.TxPool, +) (*blockManager, error) { bm := blockManager{ server: s, + chain: chain, + txMemPool: txMemPool, rejectedTxns: make(map[chainhash.Hash]struct{}), requestedTxns: make(map[chainhash.Hash]struct{}), requestedBlocks: make(map[chainhash.Hash]struct{}), @@ -1457,26 +1410,7 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager) (*blockMan quit: make(chan struct{}), } - // Merge given checkpoints with the default ones unless they are disabled. - var checkpoints []chaincfg.Checkpoint - if !cfg.DisableCheckpoints { - checkpoints = mergeCheckpoints(s.chainParams.Checkpoints, cfg.addCheckpoints) - } - - // Create a new block chain instance with the appropriate configuration. - var err error - bm.chain, err = blockchain.New(&blockchain.Config{ - DB: s.db, - ChainParams: s.chainParams, - Checkpoints: checkpoints, - TimeSource: s.timeSource, - SigCache: s.sigCache, - IndexManager: indexManager, - HashCache: s.hashCache, - }) - if err != nil { - return nil, err - } + // Register blockchain notification callbacks bm.chain.Subscribe(bm.handleNotifyMsg) best := bm.chain.BestSnapshot() diff --git a/server.go b/server.go index cf8db264..ecf1a80d 100644 --- a/server.go +++ b/server.go @@ -2448,11 +2448,27 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param if len(indexes) > 0 { indexManager = indexers.NewManager(db, indexes) } - bm, err := newBlockManager(&s, indexManager) + + // Merge given checkpoints with the default ones unless they are disabled. + var checkpoints []chaincfg.Checkpoint + if !cfg.DisableCheckpoints { + checkpoints = mergeCheckpoints(s.chainParams.Checkpoints, cfg.addCheckpoints) + } + + // Create a new block chain instance with the appropriate configuration. + chain, err := blockchain.New(&blockchain.Config{ + DB: s.db, + ChainParams: s.chainParams, + Checkpoints: checkpoints, + TimeSource: s.timeSource, + Notifications: bm.handleNotifyMsg, + SigCache: s.sigCache, + IndexManager: indexManager, + HashCache: s.hashCache, + }) if err != nil { return nil, err } - s.blockManager = bm txC := mempool.Config{ Policy: mempool.Policy{ @@ -2466,11 +2482,11 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param MaxTxVersion: 2, }, ChainParams: chainParams, - FetchUtxoView: s.blockManager.chain.FetchUtxoView, - BestHeight: func() int32 { return bm.chain.BestSnapshot().Height }, - MedianTimePast: func() time.Time { return bm.chain.BestSnapshot().MedianTime }, + FetchUtxoView: chain.FetchUtxoView, + BestHeight: func() int32 { return chain.BestSnapshot().Height }, + MedianTimePast: func() time.Time { return chain.BestSnapshot().MedianTime }, CalcSequenceLock: func(tx *btcutil.Tx, view *blockchain.UtxoViewpoint) (*blockchain.SequenceLock, error) { - return bm.chain.CalcSequenceLock(tx, view, true) + return chain.CalcSequenceLock(tx, view, true) }, IsDeploymentActive: bm.chain.IsDeploymentActive, SigCache: s.sigCache, @@ -2479,6 +2495,11 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param } s.txMemPool = mempool.New(&txC) + s.bm, err = newBlockManager(&s, indexManager, &chain, s.txMemPool) + if err != nil { + return nil, err + } + // Create the mining policy and block template generator based on the // configuration options. // @@ -2672,3 +2693,56 @@ func dynamicTickDuration(remaining time.Duration) time.Duration { } return time.Hour } + +// checkpointSorter implements sort.Interface to allow a slice of checkpoints to +// be sorted. +type checkpointSorter []chaincfg.Checkpoint + +// Len returns the number of checkpoints in the slice. It is part of the +// sort.Interface implementation. +func (s checkpointSorter) Len() int { + return len(s) +} + +// Swap swaps the checkpoints at the passed indices. It is part of the +// sort.Interface implementation. +func (s checkpointSorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Less returns whether the checkpoint with index i should sort before the +// checkpoint with index j. It is part of the sort.Interface implementation. +func (s checkpointSorter) Less(i, j int) bool { + return s[i].Height < s[j].Height +} + +// mergeCheckpoints returns two slices of checkpoints merged into one slice +// such that the checkpoints are sorted by height. In the case the additional +// checkpoints contain a checkpoint with the same height as a checkpoint in the +// default checkpoints, the additional checkpoint will take precedence and +// overwrite the default one. +func mergeCheckpoints(defaultCheckpoints, additional []chaincfg.Checkpoint) []chaincfg.Checkpoint { + // Create a map of the additional checkpoints to remove duplicates while + // leaving the most recently-specified checkpoint. + extra := make(map[int32]chaincfg.Checkpoint) + for _, checkpoint := range additional { + extra[checkpoint.Height] = checkpoint + } + + // Add all default checkpoints that do not have an override in the + // additional checkpoints. + numDefault := len(defaultCheckpoints) + checkpoints := make([]chaincfg.Checkpoint, 0, numDefault+len(extra)) + for _, checkpoint := range defaultCheckpoints { + if _, exists := extra[checkpoint.Height]; !exists { + checkpoints = append(checkpoints, checkpoint) + } + } + + // Append the additional checkpoints and return the sorted results. + for _, checkpoint := range extra { + checkpoints = append(checkpoints, checkpoint) + } + sort.Sort(checkpointSorter(checkpoints)) + return checkpoints +}