blockchain: Associate time src with chain instance.
Rather than making the caller to pass in the median time source on ProcessBlock and IsCurrent, modify the Config struct to include the median time source and associate it with the chain instance when it is created. This is being done because both the ProcessBlock and IsCurrent functions require access to the blockchain state already, it is a little bit safer to ensure the time source matches the chain instance state, it simplifies the caller logic, and it also allows its use within the logic of the blockchain package itself which will be required by upcoming rule change warning logic that is part of BIP9.
This commit is contained in:
parent
1ffc3dc18d
commit
00ebb9d14d
8 changed files with 30 additions and 26 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue