Unify ChainSync actions under one enum (#2180)

All `ChainSync` actions that `SyncingEngine` should perform are unified
under one `ChainSyncAction`. Processing of these actions put into a
single place after `select!` in `SyncingEngine::run` instead of multiple
places where calling `ChainSync` methods.
This commit is contained in:
Dmitry Markin
2023-11-13 07:33:37 +02:00
committed by GitHub
parent 0c5dcca9e3
commit 951bcceba0
3 changed files with 314 additions and 328 deletions
@@ -53,7 +53,7 @@ fn processes_empty_response_on_justification_request_for_unknown_block() {
};
// add a new peer with the same best block
sync.new_peer(peer_id, a1_hash, a1_number).unwrap();
sync.new_peer(peer_id, a1_hash, a1_number);
// and request a justification for the block
sync.request_justification(&a1_hash, a1_number);
@@ -74,10 +74,8 @@ fn processes_empty_response_on_justification_request_for_unknown_block() {
// if the peer replies with an empty response (i.e. it doesn't know the block),
// the active request should be cleared.
assert_eq!(
sync.on_block_justification(peer_id, BlockResponse::<Block> { id: 0, blocks: vec![] }),
Ok(OnBlockJustification::Nothing),
);
sync.on_block_justification(peer_id, BlockResponse::<Block> { id: 0, blocks: vec![] })
.unwrap();
// there should be no in-flight requests
assert_eq!(sync.extra_justifications.active_requests().count(), 0);
@@ -119,8 +117,8 @@ fn restart_doesnt_affect_peers_downloading_finality_data() {
let (b1_hash, b1_number) = new_blocks(50);
// add 2 peers at blocks that we don't have locally
sync.new_peer(peer_id1, Hash::random(), 42).unwrap();
sync.new_peer(peer_id2, Hash::random(), 10).unwrap();
sync.new_peer(peer_id1, Hash::random(), 42);
sync.new_peer(peer_id2, Hash::random(), 10);
// we wil send block requests to these peers
// for these blocks we don't know about
@@ -130,7 +128,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() {
.all(|(p, _)| { p == peer_id1 || p == peer_id2 }));
// add a new peer at a known block
sync.new_peer(peer_id3, b1_hash, b1_number).unwrap();
sync.new_peer(peer_id3, b1_hash, b1_number);
// we request a justification for a block we have locally
sync.request_justification(&b1_hash, b1_number);
@@ -148,14 +146,19 @@ fn restart_doesnt_affect_peers_downloading_finality_data() {
PeerSyncState::DownloadingJustification(b1_hash),
);
// clear old actions
let _ = sync.take_actions();
// we restart the sync state
let block_requests = sync.restart();
sync.restart();
let actions = sync.take_actions().collect::<Vec<_>>();
// which should make us send out block requests to the first two peers
assert!(block_requests.map(|r| r.unwrap()).all(|event| match event {
BlockRequestAction::SendRequest { peer_id, .. } =>
peer_id == peer_id1 || peer_id == peer_id2,
BlockRequestAction::RemoveStale { .. } => false,
assert_eq!(actions.len(), 2);
assert!(actions.iter().all(|action| match action {
ChainSyncAction::SendBlockRequest { peer_id, .. } =>
peer_id == &peer_id1 || peer_id == &peer_id2,
_ => false,
}));
// peer 3 should be unaffected it was downloading finality data
@@ -166,7 +169,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() {
// Set common block to something that we don't have (e.g. failed import)
sync.peers.get_mut(&peer_id3).unwrap().common_number = 100;
let _ = sync.restart().count();
sync.restart();
assert_eq!(sync.peers.get(&peer_id3).unwrap().common_number, 50);
}
@@ -280,9 +283,8 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() {
let best_block = blocks.last().unwrap().clone();
let max_blocks_to_request = sync.max_blocks_per_request;
// Connect the node we will sync from
sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number())
.unwrap();
sync.new_peer(peer_id2, info.best_hash, 0).unwrap();
sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number());
sync.new_peer(peer_id2, info.best_hash, 0);
let mut best_block_num = 0;
while best_block_num < MAX_DOWNLOAD_AHEAD {
@@ -300,11 +302,17 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() {
let response = create_block_response(resp_blocks.clone());
let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap();
// Clear old actions to not deal with them
let _ = sync.take_actions();
sync.on_block_data(&peer_id1, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert_eq!(actions.len(), 1);
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize
),);
&actions[0],
ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == max_blocks_to_request as usize,
));
best_block_num += max_blocks_to_request as u32;
@@ -356,11 +364,14 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() {
assert_eq!(FromBlock::Number(best_block_num as u64), peer2_req.from);
let response = create_block_response(vec![blocks[(best_block_num - 1) as usize].clone()]);
let res = sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap();
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()
),);
// Clear old actions to not deal with them
let _ = sync.take_actions();
sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert!(actions.is_empty());
let peer1_from = unwrap_from_block_number(peer1_req.unwrap().from);
@@ -421,25 +432,34 @@ fn can_sync_huge_fork() {
let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone();
// Connect the node we will sync from
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number())
.unwrap();
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number());
send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync);
let mut request =
get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1);
// Discard old actions we are not interested in
let _ = sync.take_actions();
// Do the ancestor search
loop {
let block = &fork_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1];
let response = create_block_response(vec![block.clone()]);
let on_block_data = sync.on_block_data(&peer_id1, Some(request), response).unwrap();
request = if let OnBlockData::Request(_peer, request) = on_block_data {
request
} else {
sync.on_block_data(&peer_id1, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
request = if actions.is_empty() {
// We found the ancenstor
break
} else {
assert_eq!(actions.len(), 1);
match &actions[0] {
ChainSyncAction::SendBlockRequest { peer_id: _, request } => request.clone(),
action @ _ => panic!("Unexpected action: {action:?}"),
}
};
log::trace!(target: LOG_TARGET, "Request: {request:?}");
@@ -463,15 +483,18 @@ fn can_sync_huge_fork() {
let response = create_block_response(resp_blocks.clone());
let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap();
sync.on_block_data(&peer_id1, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert_eq!(actions.len(), 1);
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == sync.max_blocks_per_request as usize
),);
&actions[0],
ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == sync.max_blocks_per_request as usize
));
best_block_num += sync.max_blocks_per_request as u32;
let _ = sync.on_blocks_processed(
sync.on_blocks_processed(
max_blocks_to_request as usize,
max_blocks_to_request as usize,
resp_blocks
@@ -490,6 +513,9 @@ fn can_sync_huge_fork() {
.collect(),
);
// Discard pending actions
let _ = sync.take_actions();
resp_blocks
.into_iter()
.rev()
@@ -539,25 +565,34 @@ fn syncs_fork_without_duplicate_requests() {
let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone();
// Connect the node we will sync from
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number())
.unwrap();
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number());
send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync);
let mut request =
get_block_request(&mut sync, FromBlock::Number(info.best_number), 1, &peer_id1);
// Discard pending actions
let _ = sync.take_actions();
// Do the ancestor search
loop {
let block = &fork_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1];
let response = create_block_response(vec![block.clone()]);
let on_block_data = sync.on_block_data(&peer_id1, Some(request), response).unwrap();
request = if let OnBlockData::Request(_peer, request) = on_block_data {
request
} else {
sync.on_block_data(&peer_id1, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
request = if actions.is_empty() {
// We found the ancenstor
break
} else {
assert_eq!(actions.len(), 1);
match &actions[0] {
ChainSyncAction::SendBlockRequest { peer_id: _, request } => request.clone(),
action @ _ => panic!("Unexpected action: {action:?}"),
}
};
log::trace!(target: LOG_TARGET, "Request: {request:?}");
@@ -582,11 +617,17 @@ fn syncs_fork_without_duplicate_requests() {
let response = create_block_response(resp_blocks.clone());
let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap();
// Discard old actions
let _ = sync.take_actions();
sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert_eq!(actions.len(), 1);
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize
),);
&actions[0],
ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == max_blocks_to_request as usize
));
best_block_num += max_blocks_to_request as u32;
@@ -653,8 +694,7 @@ fn removes_target_fork_on_disconnect() {
let peer_id1 = PeerId::random();
let common_block = blocks[1].clone();
// Connect the node we will sync from
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number())
.unwrap();
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number());
// Create a "new" header and announce it
let mut header = blocks[0].header().clone();
@@ -678,8 +718,7 @@ fn can_import_response_with_missing_blocks() {
let peer_id1 = PeerId::random();
let best_block = blocks[3].clone();
sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number())
.unwrap();
sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number());
sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available;
sync.peers.get_mut(&peer_id1).unwrap().common_number = 0;
@@ -730,7 +769,7 @@ fn sync_restart_removes_block_but_not_justification_requests() {
let (b1_hash, b1_number) = new_blocks(50);
// add new peer and request blocks from them
sync.new_peer(peers[0], Hash::random(), 42).unwrap();
sync.new_peer(peers[0], Hash::random(), 42);
// we don't actually perform any requests, just keep track of peers waiting for a response
let mut pending_responses = HashSet::new();
@@ -743,7 +782,7 @@ fn sync_restart_removes_block_but_not_justification_requests() {
}
// add a new peer at a known block
sync.new_peer(peers[1], b1_hash, b1_number).unwrap();
sync.new_peer(peers[1], b1_hash, b1_number);
// we request a justification for a block we have locally
sync.request_justification(&b1_hash, b1_number);
@@ -766,24 +805,29 @@ fn sync_restart_removes_block_but_not_justification_requests() {
);
assert_eq!(pending_responses.len(), 2);
// discard old actions
let _ = sync.take_actions();
// restart sync
let request_events = sync.restart().collect::<Vec<_>>();
for event in request_events.iter() {
match event.as_ref().unwrap() {
BlockRequestAction::RemoveStale { peer_id } => {
sync.restart();
let actions = sync.take_actions().collect::<Vec<_>>();
for action in actions.iter() {
match action {
ChainSyncAction::CancelBlockRequest { peer_id } => {
pending_responses.remove(&peer_id);
},
BlockRequestAction::SendRequest { peer_id, .. } => {
ChainSyncAction::SendBlockRequest { peer_id, .. } => {
// we drop obsolete response, but don't register a new request, it's checked in
// the `assert!` below
pending_responses.remove(&peer_id);
},
action @ _ => panic!("Unexpected action: {action:?}"),
}
}
assert!(request_events.iter().any(|event| {
match event.as_ref().unwrap() {
BlockRequestAction::RemoveStale { .. } => false,
BlockRequestAction::SendRequest { peer_id, .. } => peer_id == &peers[0],
assert!(actions.iter().any(|action| {
match action {
ChainSyncAction::SendBlockRequest { peer_id, .. } => peer_id == &peers[0],
_ => false,
}
}));
@@ -848,11 +892,9 @@ fn request_across_forks() {
// Add the peers, all at the common ancestor 100.
let common_block = blocks.last().unwrap();
let peer_id1 = PeerId::random();
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number())
.unwrap();
sync.new_peer(peer_id1, common_block.hash(), *common_block.header().number());
let peer_id2 = PeerId::random();
sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number())
.unwrap();
sync.new_peer(peer_id2, common_block.hash(), *common_block.header().number());
// Peer 1 announces 107 from fork 1, 100-107 get downloaded.
{
@@ -864,11 +906,17 @@ fn request_across_forks() {
let mut resp_blocks = fork_a_blocks[100_usize..107_usize].to_vec();
resp_blocks.reverse();
let response = create_block_response(resp_blocks.clone());
let res = sync.on_block_data(&peer, Some(request), response).unwrap();
// Drop old actions
let _ = sync.take_actions();
sync.on_block_data(&peer, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert_eq!(actions.len(), 1);
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 7_usize
),);
&actions[0],
ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == 7_usize
));
assert_eq!(sync.best_queued_number, 107);
assert_eq!(sync.best_queued_hash, block.hash());
assert!(sync.is_known(&block.header.parent_hash()));
@@ -903,11 +951,17 @@ fn request_across_forks() {
// block is announced.
let request = get_block_request(&mut sync, FromBlock::Hash(block.hash()), 1, &peer);
let response = create_block_response(vec![block.clone()]);
let res = sync.on_block_data(&peer, Some(request), response).unwrap();
// Drop old actions we are not going to check
let _ = sync.take_actions();
sync.on_block_data(&peer, Some(request), response).unwrap();
let actions = sync.take_actions().collect::<Vec<_>>();
assert_eq!(actions.len(), 1);
assert!(matches!(
res,
OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 1_usize
),);
&actions[0],
ChainSyncAction::ImportBlocks{ origin: _, blocks } if blocks.len() == 1_usize
));
assert!(sync.is_known(&block.header.parent_hash()));
}
}