eth/downloader: refactor downloader + queue (#21263)
* eth/downloader: refactor downloader + queue downloader, fetcher: throttle-metrics, fetcher filter improvements, standalone resultcache downloader: more accurate deliverytime calculation, less mem overhead in state requests downloader/queue: increase underlying buffer of results, new throttle mechanism eth/downloader: updates to tests eth/downloader: fix up some review concerns eth/downloader/queue: minor fixes eth/downloader: minor fixes after review call eth/downloader: testcases for queue.go eth/downloader: minor change, don't set progress unless progress... eth/downloader: fix flaw which prevented useless peers from being dropped eth/downloader: try to fix tests eth/downloader: verify non-deliveries against advertised remote head eth/downloader: fix flaw with checking closed-status causing hang eth/downloader: hashing avoidance eth/downloader: review concerns + simplify resultcache and queue eth/downloader: add back some locks, address review concerns downloader/queue: fix remaining lock flaw * eth/downloader: nitpick fixes * eth/downloader: remove the *2*3/4 throttling threshold dance * eth/downloader: print correct throttle threshold in stats Co-authored-by: Péter Szilágyi <peterke@gmail.com>
This commit is contained in:
committed by
GitHub
parent
3a57eecc69
commit
105922180f
@ -297,14 +297,13 @@ func (dl *downloadTester) InsertChain(blocks types.Blocks) (i int, err error) {
|
||||
} else if _, err := dl.stateDb.Get(parent.Root().Bytes()); err != nil {
|
||||
return i, fmt.Errorf("InsertChain: unknown parent state %x: %v", parent.Root(), err)
|
||||
}
|
||||
if _, ok := dl.ownHeaders[block.Hash()]; !ok {
|
||||
if hdr := dl.getHeaderByHash(block.Hash()); hdr == nil {
|
||||
dl.ownHashes = append(dl.ownHashes, block.Hash())
|
||||
dl.ownHeaders[block.Hash()] = block.Header()
|
||||
}
|
||||
dl.ownBlocks[block.Hash()] = block
|
||||
dl.ownReceipts[block.Hash()] = make(types.Receipts, 0)
|
||||
dl.stateDb.Put(block.Root().Bytes(), []byte{0x00})
|
||||
|
||||
td := dl.getTd(block.ParentHash())
|
||||
dl.ownChainTd[block.Hash()] = new(big.Int).Add(td, block.Difficulty())
|
||||
}
|
||||
@ -538,7 +537,6 @@ func TestThrottling64Fast(t *testing.T) { testThrottling(t, 64, FastSync) }
|
||||
func testThrottling(t *testing.T, protocol int, mode SyncMode) {
|
||||
t.Parallel()
|
||||
tester := newTester()
|
||||
defer tester.terminate()
|
||||
|
||||
// Create a long block chain to download and the tester
|
||||
targetBlocks := testChainBase.len() - 1
|
||||
@ -570,31 +568,32 @@ func testThrottling(t *testing.T, protocol int, mode SyncMode) {
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
|
||||
tester.lock.Lock()
|
||||
tester.downloader.queue.lock.Lock()
|
||||
cached = len(tester.downloader.queue.blockDonePool)
|
||||
if mode == FastSync {
|
||||
if receipts := len(tester.downloader.queue.receiptDonePool); receipts < cached {
|
||||
cached = receipts
|
||||
}
|
||||
{
|
||||
tester.downloader.queue.resultCache.lock.Lock()
|
||||
cached = tester.downloader.queue.resultCache.countCompleted()
|
||||
tester.downloader.queue.resultCache.lock.Unlock()
|
||||
frozen = int(atomic.LoadUint32(&blocked))
|
||||
retrieved = len(tester.ownBlocks)
|
||||
|
||||
}
|
||||
frozen = int(atomic.LoadUint32(&blocked))
|
||||
retrieved = len(tester.ownBlocks)
|
||||
tester.downloader.queue.lock.Unlock()
|
||||
tester.lock.Unlock()
|
||||
|
||||
if cached == blockCacheItems || cached == blockCacheItems-reorgProtHeaderDelay || retrieved+cached+frozen == targetBlocks+1 || retrieved+cached+frozen == targetBlocks+1-reorgProtHeaderDelay {
|
||||
if cached == blockCacheItems ||
|
||||
cached == blockCacheItems-reorgProtHeaderDelay ||
|
||||
retrieved+cached+frozen == targetBlocks+1 ||
|
||||
retrieved+cached+frozen == targetBlocks+1-reorgProtHeaderDelay {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Make sure we filled up the cache, then exhaust it
|
||||
time.Sleep(25 * time.Millisecond) // give it a chance to screw up
|
||||
|
||||
tester.lock.RLock()
|
||||
retrieved = len(tester.ownBlocks)
|
||||
tester.lock.RUnlock()
|
||||
if cached != blockCacheItems && cached != blockCacheItems-reorgProtHeaderDelay && retrieved+cached+frozen != targetBlocks+1 && retrieved+cached+frozen != targetBlocks+1-reorgProtHeaderDelay {
|
||||
t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheItems, retrieved, frozen, targetBlocks+1)
|
||||
}
|
||||
|
||||
// Permit the blocked blocks to import
|
||||
if atomic.LoadUint32(&blocked) > 0 {
|
||||
atomic.StoreUint32(&blocked, uint32(0))
|
||||
@ -606,6 +605,8 @@ func testThrottling(t *testing.T, protocol int, mode SyncMode) {
|
||||
if err := <-errc; err != nil {
|
||||
t.Fatalf("block synchronization failed: %v", err)
|
||||
}
|
||||
tester.terminate()
|
||||
|
||||
}
|
||||
|
||||
// Tests that simple synchronization against a forked chain works correctly. In
|
||||
@ -628,7 +629,6 @@ func testForkedSync(t *testing.T, protocol int, mode SyncMode) {
|
||||
chainB := testChainForkLightB.shorten(testChainBase.len() + 80)
|
||||
tester.newPeer("fork A", protocol, chainA)
|
||||
tester.newPeer("fork B", protocol, chainB)
|
||||
|
||||
// Synchronise with the peer and make sure all blocks were retrieved
|
||||
if err := tester.sync("fork A", nil, mode); err != nil {
|
||||
t.Fatalf("failed to synchronise blocks: %v", err)
|
||||
@ -720,15 +720,12 @@ func TestBoundedHeavyForkedSync64Light(t *testing.T) { testBoundedHeavyForkedSyn
|
||||
|
||||
func testBoundedHeavyForkedSync(t *testing.T, protocol int, mode SyncMode) {
|
||||
t.Parallel()
|
||||
|
||||
tester := newTester()
|
||||
defer tester.terminate()
|
||||
|
||||
// Create a long enough forked chain
|
||||
chainA := testChainForkLightA
|
||||
chainB := testChainForkHeavy
|
||||
tester.newPeer("original", protocol, chainA)
|
||||
tester.newPeer("heavy-rewriter", protocol, chainB)
|
||||
|
||||
// Synchronise with the peer and make sure all blocks were retrieved
|
||||
if err := tester.sync("original", nil, mode); err != nil {
|
||||
@ -736,10 +733,12 @@ func testBoundedHeavyForkedSync(t *testing.T, protocol int, mode SyncMode) {
|
||||
}
|
||||
assertOwnChain(t, tester, chainA.len())
|
||||
|
||||
tester.newPeer("heavy-rewriter", protocol, chainB)
|
||||
// Synchronise with the second peer and ensure that the fork is rejected to being too old
|
||||
if err := tester.sync("heavy-rewriter", nil, mode); err != errInvalidAncestor {
|
||||
t.Fatalf("sync failure mismatch: have %v, want %v", err, errInvalidAncestor)
|
||||
}
|
||||
tester.terminate()
|
||||
}
|
||||
|
||||
// Tests that an inactive downloader will not accept incoming block headers and
|
||||
@ -1007,7 +1006,6 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
|
||||
t.Parallel()
|
||||
|
||||
tester := newTester()
|
||||
defer tester.terminate()
|
||||
|
||||
// Create a small enough block chain to download
|
||||
targetBlocks := 3*fsHeaderSafetyNet + 256 + fsMinFullBlocks
|
||||
@ -1087,6 +1085,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
|
||||
t.Fatalf("synchronised blocks mismatch: have %v, want %v", bs, chain.len())
|
||||
}
|
||||
}
|
||||
tester.terminate()
|
||||
}
|
||||
|
||||
// Tests that a peer advertising a high TD doesn't get to stall the downloader
|
||||
@ -1102,13 +1101,13 @@ func testHighTDStarvationAttack(t *testing.T, protocol int, mode SyncMode) {
|
||||
t.Parallel()
|
||||
|
||||
tester := newTester()
|
||||
defer tester.terminate()
|
||||
|
||||
chain := testChainBase.shorten(1)
|
||||
tester.newPeer("attack", protocol, chain)
|
||||
if err := tester.sync("attack", big.NewInt(1000000), mode); err != errStallingPeer {
|
||||
t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer)
|
||||
}
|
||||
tester.terminate()
|
||||
}
|
||||
|
||||
// Tests that misbehaving peers are disconnected, whilst behaving ones are not.
|
||||
|
Reference in New Issue
Block a user