|
@@ -33,10 +33,12 @@ import (
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
const (
|
|
|
- lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested
|
|
|
|
|
- arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested
|
|
|
|
|
- gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches
|
|
|
|
|
- fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested block/transaction
|
|
|
|
|
|
|
+ lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested
|
|
|
|
|
+ arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested
|
|
|
|
|
+ gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches
|
|
|
|
|
+ fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested block/transaction
|
|
|
|
|
+ reQueueBlockTimeout = 500 * time.Millisecond // Time allowance before blocks are requeued for import
|
|
|
|
|
+
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
const (
|
|
@@ -167,6 +169,8 @@ type BlockFetcher struct {
|
|
|
done chan common.Hash
|
|
done chan common.Hash
|
|
|
quit chan struct{}
|
|
quit chan struct{}
|
|
|
|
|
|
|
|
|
|
+ requeue chan *blockOrHeaderInject
|
|
|
|
|
+
|
|
|
// Announce states
|
|
// Announce states
|
|
|
announces map[string]int // Per peer blockAnnounce counts to prevent memory exhaustion
|
|
announces map[string]int // Per peer blockAnnounce counts to prevent memory exhaustion
|
|
|
announced map[common.Hash][]*blockAnnounce // Announced blocks, scheduled for fetching
|
|
announced map[common.Hash][]*blockAnnounce // Announced blocks, scheduled for fetching
|
|
@@ -207,6 +211,7 @@ func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetr
|
|
|
bodyFilter: make(chan chan *bodyFilterTask),
|
|
bodyFilter: make(chan chan *bodyFilterTask),
|
|
|
done: make(chan common.Hash),
|
|
done: make(chan common.Hash),
|
|
|
quit: make(chan struct{}),
|
|
quit: make(chan struct{}),
|
|
|
|
|
+ requeue: make(chan *blockOrHeaderInject),
|
|
|
announces: make(map[string]int),
|
|
announces: make(map[string]int),
|
|
|
announced: make(map[common.Hash][]*blockAnnounce),
|
|
announced: make(map[common.Hash][]*blockAnnounce),
|
|
|
fetching: make(map[common.Hash]*blockAnnounce),
|
|
fetching: make(map[common.Hash]*blockAnnounce),
|
|
@@ -371,9 +376,9 @@ func (f *BlockFetcher) loop() {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
if f.light {
|
|
if f.light {
|
|
|
- f.importHeaders(op.origin, op.header)
|
|
|
|
|
|
|
+ f.importHeaders(op)
|
|
|
} else {
|
|
} else {
|
|
|
- f.importBlocks(op.origin, op.block)
|
|
|
|
|
|
|
+ f.importBlocks(op)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// Wait for an outside event to occur
|
|
// Wait for an outside event to occur
|
|
@@ -416,6 +421,21 @@ func (f *BlockFetcher) loop() {
|
|
|
f.rescheduleFetch(fetchTimer)
|
|
f.rescheduleFetch(fetchTimer)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ case op := <-f.requeue:
|
|
|
|
|
+ // Re-queue blocks that have not been written due to fork block competition
|
|
|
|
|
+ number := int64(0)
|
|
|
|
|
+ hash := ""
|
|
|
|
|
+ if op.header != nil {
|
|
|
|
|
+ number = op.header.Number.Int64()
|
|
|
|
|
+ hash = op.header.Hash().String()
|
|
|
|
|
+ } else if op.block != nil {
|
|
|
|
|
+ number = op.block.Number().Int64()
|
|
|
|
|
+ hash = op.block.Hash().String()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.Info("Re-queue blocks", "number", number, "hash", hash)
|
|
|
|
|
+ f.enqueue(op.origin, op.header, op.block)
|
|
|
|
|
+
|
|
|
case op := <-f.inject:
|
|
case op := <-f.inject:
|
|
|
// A direct block insertion was requested, try and fill any pending gaps
|
|
// A direct block insertion was requested, try and fill any pending gaps
|
|
|
blockBroadcastInMeter.Mark(1)
|
|
blockBroadcastInMeter.Mark(1)
|
|
@@ -751,7 +771,9 @@ func (f *BlockFetcher) enqueue(peer string, header *types.Header, block *types.B
|
|
|
// importHeaders spawns a new goroutine to run a header insertion into the chain.
|
|
// importHeaders spawns a new goroutine to run a header insertion into the chain.
|
|
|
// If the header's number is at the same height as the current import phase, it
|
|
// If the header's number is at the same height as the current import phase, it
|
|
|
// updates the phase states accordingly.
|
|
// updates the phase states accordingly.
|
|
|
-func (f *BlockFetcher) importHeaders(peer string, header *types.Header) {
|
|
|
|
|
|
|
+func (f *BlockFetcher) importHeaders(op *blockOrHeaderInject) {
|
|
|
|
|
+ peer := op.origin
|
|
|
|
|
+ header := op.header
|
|
|
hash := header.Hash()
|
|
hash := header.Hash()
|
|
|
log.Debug("Importing propagated header", "peer", peer, "number", header.Number, "hash", hash)
|
|
log.Debug("Importing propagated header", "peer", peer, "number", header.Number, "hash", hash)
|
|
|
|
|
|
|
@@ -761,6 +783,8 @@ func (f *BlockFetcher) importHeaders(peer string, header *types.Header) {
|
|
|
parent := f.getHeader(header.ParentHash)
|
|
parent := f.getHeader(header.ParentHash)
|
|
|
if parent == nil {
|
|
if parent == nil {
|
|
|
log.Debug("Unknown parent of propagated header", "peer", peer, "number", header.Number, "hash", hash, "parent", header.ParentHash)
|
|
log.Debug("Unknown parent of propagated header", "peer", peer, "number", header.Number, "hash", hash, "parent", header.ParentHash)
|
|
|
|
|
+ time.Sleep(reQueueBlockTimeout)
|
|
|
|
|
+ f.requeue <- op
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
// Validate the header and if something went wrong, drop the peer
|
|
// Validate the header and if something went wrong, drop the peer
|
|
@@ -784,7 +808,9 @@ func (f *BlockFetcher) importHeaders(peer string, header *types.Header) {
|
|
|
// importBlocks spawns a new goroutine to run a block insertion into the chain. If the
|
|
// importBlocks spawns a new goroutine to run a block insertion into the chain. If the
|
|
|
// block's number is at the same height as the current import phase, it updates
|
|
// block's number is at the same height as the current import phase, it updates
|
|
|
// the phase states accordingly.
|
|
// the phase states accordingly.
|
|
|
-func (f *BlockFetcher) importBlocks(peer string, block *types.Block) {
|
|
|
|
|
|
|
+func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) {
|
|
|
|
|
+ peer := op.origin
|
|
|
|
|
+ block := op.block
|
|
|
hash := block.Hash()
|
|
hash := block.Hash()
|
|
|
|
|
|
|
|
// Run the import on a new thread
|
|
// Run the import on a new thread
|
|
@@ -796,6 +822,8 @@ func (f *BlockFetcher) importBlocks(peer string, block *types.Block) {
|
|
|
parent := f.getBlock(block.ParentHash())
|
|
parent := f.getBlock(block.ParentHash())
|
|
|
if parent == nil {
|
|
if parent == nil {
|
|
|
log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
|
|
log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
|
|
|
|
|
+ time.Sleep(reQueueBlockTimeout)
|
|
|
|
|
+ f.requeue <- op
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
// Quickly validate the header and propagate the block if it passes
|
|
// Quickly validate the header and propagate the block if it passes
|