From 0c8a9002b3db032750a2e168f5d41b76a9830db1 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:09:08 +0200 Subject: [PATCH 01/14] Clarify docs of async_tree --- bin/light-base/src/sync_service/parachain.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index ad1cc05a62..d1b6667753 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -98,13 +98,18 @@ pub(super) async fn start_parachain( // sync service. Once inside, their corresponding parahead is fetched. Once the parahead // is fetched, this parahead is reported to our subscriptions. // - // Each block in the tree has an associated parahead behind an `Option`. This `Option` - // always contains `Some`, unless the relay chain finalized block hasn't had its parahead - // fetched yet. + // The root of the tree is a "virtual" block. It can be thought as the parent of the relay + // chain finalized block, but is there even if the relay chain finalized block is block 0. + // + // All block in the tree has an associated parahead behind an `Option`. This `Option` + // always contains `Some`, except for the "virtual" root block for which it is `None`. + // + // If the output finalized block has a parahead equal to `None`, it therefore means that + // no finalized parahead is known yet. // // The set of blocks in this tree whose parahead hasn't been fetched yet is the same as // the set of blocks that is maintained pinned on the runtime service. Blocks are unpinned - // when their parahead fetching succeeds. + // when their parahead fetching succeeds or when they are removed from the tree. let mut async_tree = { let mut async_tree = async_tree::AsyncTree::::new(async_tree::Config { From 7e58ad514e0c53320f58a5b288a23ea4952f0ad3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:09:56 +0200 Subject: [PATCH 02/14] Add TODO --- bin/light-base/src/sync_service/parachain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index d1b6667753..1ed0493f41 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -489,6 +489,7 @@ pub(super) async fn start_parachain( // same thing as whether its relay chain is at the head of the chain. // Note that there is no ordering guarantee of any kind w.r.t. // block subscriptions notifications. + // TODO: that's not exactly true, we might not have fetched any parahead yet let val = relay_chain_sync.is_near_head_of_chain_heuristic().await; let _ = send_back.send(val); }, From 0cc7a11f44a123155ba058ad16646bb29fa6d60f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:16:10 +0200 Subject: [PATCH 03/14] Actually fix the issue --- bin/light-base/src/sync_service/parachain.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 1ed0493f41..0e7d037c1b 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -205,6 +205,11 @@ pub(super) async fn start_parachain( .. } if *new_parahead != former_parahead => { debug_assert!(new_parahead.is_some()); + + if former_parahead.is_none() { + all_subscriptions.clear(); + } + let hash = header::hash_from_scale_encoded_header(new_parahead.as_ref().unwrap()); From 593562a26c9885f4ac7e2c14831d75a91a16a259 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:21:24 +0200 Subject: [PATCH 04/14] finalized_parahead -> obsolete_finalized_parahead --- bin/light-base/src/sync_service/parachain.rs | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 0e7d037c1b..fb123fcda5 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -52,22 +52,23 @@ pub(super) async fn start_parachain( // Necessary for the `select!` loop below. let mut from_network_service = from_network_service.fuse(); - // Last good known parachain header of a relay chain finalized block. + // Last-known finalized parachain header. Can be very old and obsolete. // Updated after we successfully fetch the parahead of a relay chain finalized block, and left // untouched if the fetch fails. // Initialized to the parachain genesis block header. - let mut finalized_parahead = chain_information + let mut obsolete_finalized_parahead = chain_information .as_ref() .finalized_block_header .scale_encoding_vec(block_number_bytes); // Hash of the best parachain that has been reported to the output. - let mut best_parahead_hash = header::hash_from_scale_encoded_header(&finalized_parahead); + let mut best_parahead_hash = + header::hash_from_scale_encoded_header(&obsolete_finalized_parahead); // State machine that tracks the list of parachain network sources and their known blocks. let mut sync_sources = sources::AllForksSources::<(PeerId, protocol::Role)>::new( 40, - header::decode(&finalized_parahead, block_number_bytes) + header::decode(&obsolete_finalized_parahead, block_number_bytes) .unwrap() .number, ); @@ -213,9 +214,10 @@ pub(super) async fn start_parachain( let hash = header::hash_from_scale_encoded_header(new_parahead.as_ref().unwrap()); - finalized_parahead = new_parahead.clone().unwrap(); + obsolete_finalized_parahead = new_parahead.clone().unwrap(); - if let Ok(header) = header::decode(&finalized_parahead, block_number_bytes) + if let Ok(header) = + header::decode(&obsolete_finalized_parahead, block_number_bytes) { sync_sources.set_finalized_block_height(header.number); // TODO: what about an `else`? does sync_sources leak if the block can't be decoded? @@ -266,7 +268,7 @@ pub(super) async fn start_parachain( async_tree .best_block_index() .map(|(_, b)| b.as_ref().unwrap()) - .unwrap_or(&finalized_parahead), + .unwrap_or(&obsolete_finalized_parahead), ); if parahash != best_parahead_hash { @@ -304,7 +306,7 @@ pub(super) async fn start_parachain( // past. This covers situations where the parahead is identical to the // relay chain's parent's parahead, but also situations where multiple // sibling relay chain blocks have the same parahead. - if finalized_parahead == scale_encoded_header + if obsolete_finalized_parahead == scale_encoded_header || async_tree .input_iter_unordered() .filter(|item| item.id != block_index) @@ -359,7 +361,7 @@ pub(super) async fn start_parachain( .unwrap() }) .or_else(|| async_tree.finalized_async_user_data().as_ref()) - .unwrap_or(&finalized_parahead), + .unwrap_or(&obsolete_finalized_parahead), ); // Elements in `all_subscriptions` are removed one by one and @@ -501,7 +503,7 @@ pub(super) async fn start_parachain( ToBackground::SubscribeAll { send_back, buffer_size, .. } => { let (tx, new_blocks) = mpsc::channel(buffer_size.saturating_sub(1)); let _ = send_back.send(super::SubscribeAll { - finalized_block_scale_encoded_header: finalized_parahead.clone(), + finalized_block_scale_encoded_header: obsolete_finalized_parahead.clone(), finalized_block_runtime: None, non_finalized_blocks_ancestry_order: async_tree.input_iter_unordered().filter_map(|block| { // `async_op_user_data` is `Some` only if this block has @@ -511,7 +513,7 @@ pub(super) async fn start_parachain( let parent_hash = async_tree.parent(block.id) .map(|idx| header::hash_from_scale_encoded_header(&async_tree.block_async_user_data(idx).unwrap().as_ref().unwrap())) .or_else(|| async_tree.finalized_async_user_data().as_ref().map(header::hash_from_scale_encoded_header)) - .unwrap_or(header::hash_from_scale_encoded_header(&finalized_parahead)); + .unwrap_or(header::hash_from_scale_encoded_header(&obsolete_finalized_parahead)); Some(super::BlockNotification { is_new_best: block.is_output_best, From 6223acde5781cfc1214cf42784dd5bf25270fb51 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:30:12 +0200 Subject: [PATCH 05/14] Tweak SubscribeAll handling --- bin/light-base/src/sync_service/parachain.rs | 69 ++++++++++++++------ 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index fb123fcda5..8affc1dd35 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -107,6 +107,9 @@ pub(super) async fn start_parachain( // // If the output finalized block has a parahead equal to `None`, it therefore means that // no finalized parahead is known yet. + // Note that, when it is the case, `SubscribeAll` messages from the frontend are still + // answered with a single finalized block set to `obsolete_finalized_parahead`. Once a + // finalized parahead is known, it is important to reset all subscriptions. // // The set of blocks in this tree whose parahead hasn't been fetched yet is the same as // the set of blocks that is maintained pinned on the runtime service. Blocks are unpinned @@ -207,6 +210,11 @@ pub(super) async fn start_parachain( } if *new_parahead != former_parahead => { debug_assert!(new_parahead.is_some()); + // If this is the first time (in this loop) a finalized parahead is known, + // any `SuscribeAll` message that has been answered beforehand was + // answered in a dummy way with a potentially obsolete finalized header. + // For this reason, we reset all subscriptions to force all subscribers to + // re-subscribe. if former_parahead.is_none() { all_subscriptions.clear(); } @@ -501,28 +509,47 @@ pub(super) async fn start_parachain( let _ = send_back.send(val); }, ToBackground::SubscribeAll { send_back, buffer_size, .. } => { + // There are two possibilities here: either we know of any recent + // finalized parahead, or we don't. In case where we don't know of + // any finalized parahead yet, we report a single obsolete finalized + // parahead, which is `obsolete_finalized_parahead`. The rest of this + // module makes sure that no other block is reported to subscriptions + // as long as this is the case, and that subscriptions are reset once + // the first known finalized parahead is known. let (tx, new_blocks) = mpsc::channel(buffer_size.saturating_sub(1)); - let _ = send_back.send(super::SubscribeAll { - finalized_block_scale_encoded_header: obsolete_finalized_parahead.clone(), - finalized_block_runtime: None, - non_finalized_blocks_ancestry_order: async_tree.input_iter_unordered().filter_map(|block| { - // `async_op_user_data` is `Some` only if this block has - // already been reported on the output. In order to maintain - // consistency, only these blocks should be reported. - let parahead = block.async_op_user_data?.as_ref().unwrap(); - let parent_hash = async_tree.parent(block.id) - .map(|idx| header::hash_from_scale_encoded_header(&async_tree.block_async_user_data(idx).unwrap().as_ref().unwrap())) - .or_else(|| async_tree.finalized_async_user_data().as_ref().map(header::hash_from_scale_encoded_header)) - .unwrap_or(header::hash_from_scale_encoded_header(&obsolete_finalized_parahead)); - - Some(super::BlockNotification { - is_new_best: block.is_output_best, - scale_encoded_header: parahead.clone(), - parent_hash, - }) - }).collect(), - new_blocks, - }); + + if let Some(finalized_parahead) = async_tree.finalized_async_user_data() { + // Finalized parahead is known. + let _ = send_back.send(super::SubscribeAll { + finalized_block_scale_encoded_header: finalized_parahead.clone(), + finalized_block_runtime: None, + non_finalized_blocks_ancestry_order: async_tree.input_iter_unordered().filter_map(|block| { + // `async_op_user_data` is `Some` only if this block has + // already been reported on the output. In order to + // maintain consistency, only these blocks should be + // reported. + let parahead = block.async_op_user_data?.as_ref().unwrap(); + let parent_hash = async_tree.parent(block.id) + .map(|idx| header::hash_from_scale_encoded_header(&async_tree.block_async_user_data(idx).unwrap().as_ref().unwrap())) + .unwrap_or_else(|| header::hash_from_scale_encoded_header(&finalized_parahead)); + + Some(super::BlockNotification { + is_new_best: block.is_output_best, + scale_encoded_header: parahead.clone(), + parent_hash, + }) + }).collect(), + new_blocks, + }); + } else { + // No known finalized parahead. + let _ = send_back.send(super::SubscribeAll { + finalized_block_scale_encoded_header: obsolete_finalized_parahead.clone(), + finalized_block_runtime: None, + non_finalized_blocks_ancestry_order: Vec::new(), + new_blocks, + }); + } all_subscriptions.push(tx); } From be0cff50c46734c871c8a6b092b9e16b368d3ba6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:36:26 +0200 Subject: [PATCH 06/14] Don't report new blocks if finalized parahead unknown --- bin/light-base/src/sync_service/parachain.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 8affc1dd35..9d98fb1729 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -310,11 +310,18 @@ pub(super) async fn start_parachain( header::hash_from_scale_encoded_header(&scale_encoded_header); let block_index = block.index; + // Do not report anything to subscriptions if no finalized parahead is + // known yet. + let finalized_parahead = match async_tree.finalized_async_user_data() { + Some(p) => p, + None => continue, + }; + // Do not report the new block if it has already been reported in the // past. This covers situations where the parahead is identical to the // relay chain's parent's parahead, but also situations where multiple // sibling relay chain blocks have the same parahead. - if obsolete_finalized_parahead == scale_encoded_header + if *finalized_parahead == scale_encoded_header || async_tree .input_iter_unordered() .filter(|item| item.id != block_index) @@ -368,8 +375,7 @@ pub(super) async fn start_parachain( .as_ref() .unwrap() }) - .or_else(|| async_tree.finalized_async_user_data().as_ref()) - .unwrap_or(&obsolete_finalized_parahead), + .unwrap_or(&finalized_parahead), ); // Elements in `all_subscriptions` are removed one by one and From 7f2b9f97c899002316165f69a62ee67d5af44b85 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:37:03 +0200 Subject: [PATCH 07/14] Small tweak --- bin/light-base/src/sync_service/parachain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 9d98fb1729..42a85661e3 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -515,6 +515,8 @@ pub(super) async fn start_parachain( let _ = send_back.send(val); }, ToBackground::SubscribeAll { send_back, buffer_size, .. } => { + let (tx, new_blocks) = mpsc::channel(buffer_size.saturating_sub(1)); + // There are two possibilities here: either we know of any recent // finalized parahead, or we don't. In case where we don't know of // any finalized parahead yet, we report a single obsolete finalized @@ -522,8 +524,6 @@ pub(super) async fn start_parachain( // module makes sure that no other block is reported to subscriptions // as long as this is the case, and that subscriptions are reset once // the first known finalized parahead is known. - let (tx, new_blocks) = mpsc::channel(buffer_size.saturating_sub(1)); - if let Some(finalized_parahead) = async_tree.finalized_async_user_data() { // Finalized parahead is known. let _ = send_back.send(super::SubscribeAll { From 55f4285ae9b13137657533cdb732731105aaf892 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:38:54 +0200 Subject: [PATCH 08/14] Also don't report best block changes --- bin/light-base/src/sync_service/parachain.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 42a85661e3..42555e366d 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -270,13 +270,20 @@ pub(super) async fn start_parachain( } async_tree::OutputUpdate::Finalized { .. } | async_tree::OutputUpdate::BestBlockChanged { .. } => { + // Do not report anything to subscriptions if no finalized parahead is + // known yet. + let finalized_parahead = match async_tree.finalized_async_user_data() { + Some(p) => p, + None => continue, + }; + // Calculate hash of the parablock corresponding to the new best relay // chain block. let parahash = header::hash_from_scale_encoded_header( async_tree .best_block_index() .map(|(_, b)| b.as_ref().unwrap()) - .unwrap_or(&obsolete_finalized_parahead), + .unwrap_or(&finalized_parahead), ); if parahash != best_parahead_hash { From 8cf2ad48bed9fb7cdd080f54837f1d03830d74b9 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:39:10 +0200 Subject: [PATCH 09/14] Typo --- bin/light-base/src/sync_service/parachain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 42555e366d..56eb9164ba 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -211,7 +211,7 @@ pub(super) async fn start_parachain( debug_assert!(new_parahead.is_some()); // If this is the first time (in this loop) a finalized parahead is known, - // any `SuscribeAll` message that has been answered beforehand was + // any `SubscribeAll` message that has been answered beforehand was // answered in a dummy way with a potentially obsolete finalized header. // For this reason, we reset all subscriptions to force all subscribers to // re-subscribe. From 9446b0e1f6b3d4aaced4d36e67cfe0dee8e48e11 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:39:32 +0200 Subject: [PATCH 10/14] Renames --- bin/light-base/src/sync_service/parachain.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 56eb9164ba..08a3536350 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -203,26 +203,27 @@ pub(super) async fn start_parachain( while let Some(update) = async_tree.try_advance_output() { match update { async_tree::OutputUpdate::Finalized { - async_op_user_data: new_parahead, - former_finalized_async_op_user_data: former_parahead, + async_op_user_data: new_finalized_parahead, + former_finalized_async_op_user_data: former_finalized_parahead, pruned_blocks, .. - } if *new_parahead != former_parahead => { - debug_assert!(new_parahead.is_some()); + } if *new_finalized_parahead != former_finalized_parahead => { + debug_assert!(new_finalized_parahead.is_some()); // If this is the first time (in this loop) a finalized parahead is known, // any `SubscribeAll` message that has been answered beforehand was // answered in a dummy way with a potentially obsolete finalized header. // For this reason, we reset all subscriptions to force all subscribers to // re-subscribe. - if former_parahead.is_none() { + if former_finalized_parahead.is_none() { all_subscriptions.clear(); } - let hash = - header::hash_from_scale_encoded_header(new_parahead.as_ref().unwrap()); + let hash = header::hash_from_scale_encoded_header( + new_finalized_parahead.as_ref().unwrap(), + ); - obsolete_finalized_parahead = new_parahead.clone().unwrap(); + obsolete_finalized_parahead = new_finalized_parahead.clone().unwrap(); if let Ok(header) = header::decode(&obsolete_finalized_parahead, block_number_bytes) From f5b6fbe946b649afad0762b33480589587974483 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:42:35 +0200 Subject: [PATCH 11/14] Revamp best_parahead_hash --- bin/light-base/src/sync_service/parachain.rs | 28 +++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 08a3536350..53538a4868 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -61,10 +61,6 @@ pub(super) async fn start_parachain( .finalized_block_header .scale_encoding_vec(block_number_bytes); - // Hash of the best parachain that has been reported to the output. - let mut best_parahead_hash = - header::hash_from_scale_encoded_header(&obsolete_finalized_parahead); - // State machine that tracks the list of parachain network sources and their known blocks. let mut sync_sources = sources::AllForksSources::<(PeerId, protocol::Role)>::new( 40, @@ -95,6 +91,10 @@ pub(super) async fn start_parachain( )) ); + // Hash of the best parachain that has been reported to the subscriptions. + // `None` if and only if no finalized parahead is known yet. + let mut reported_best_parahead_hash = None; + // Tree of relay chain blocks. Blocks are inserted when received from the relay chain // sync service. Once inside, their corresponding parahead is fetched. Once the parahead // is fetched, this parahead is reported to our subscriptions. @@ -157,6 +157,12 @@ pub(super) async fn start_parachain( let mut wakeup_deadline = future::Either::Right(future::pending()); loop { + // Internal state check. + debug_assert_eq!( + reported_best_parahead_hash.is_some(), + async_tree.finalized_async_user_data().is_some() + ); + // Start fetching paraheads of new blocks whose parahead needs to be fetched. while in_progress_paraheads.len() < 4 { match async_tree.next_necessary_async_op(&TPlat::now()) { @@ -254,7 +260,7 @@ pub(super) async fn start_parachain( header::hash_from_scale_encoded_header(parahead.as_ref().unwrap()) }) .unwrap_or(hash); - best_parahead_hash = best_block_hash; + reported_best_parahead_hash = Some(best_block_hash); // Elements in `all_subscriptions` are removed one by one and // inserted back if the channel is still open. @@ -287,8 +293,8 @@ pub(super) async fn start_parachain( .unwrap_or(&finalized_parahead), ); - if parahash != best_parahead_hash { - best_parahead_hash = parahash; + if reported_best_parahead_hash.as_ref() != Some(¶hash) { + reported_best_parahead_hash = Some(parahash); log::debug!( target: &log_target, @@ -339,8 +345,10 @@ pub(super) async fn start_parachain( // While the parablock has already been reported, it is possible that // it becomes the new best block while it wasn't before, in which // case we should send a notification. - if is_new_best && parahash != best_parahead_hash { - best_parahead_hash = parahash; + if is_new_best + && reported_best_parahead_hash.as_ref() != Some(¶hash) + { + reported_best_parahead_hash = Some(parahash); log::debug!( target: &log_target, @@ -370,7 +378,7 @@ pub(super) async fn start_parachain( ); if is_new_best { - best_parahead_hash = parahash; + reported_best_parahead_hash = Some(parahash); } let parent_hash = header::hash_from_scale_encoded_header( From 81797822f4910067468aae764587ffdada7e906c Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:45:35 +0200 Subject: [PATCH 12/14] Tweak IsNearHeadOfChainHeuristic --- bin/light-base/src/sync_service/parachain.rs | 23 +++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/bin/light-base/src/sync_service/parachain.rs b/bin/light-base/src/sync_service/parachain.rs index 53538a4868..97327f4875 100644 --- a/bin/light-base/src/sync_service/parachain.rs +++ b/bin/light-base/src/sync_service/parachain.rs @@ -521,14 +521,21 @@ pub(super) async fn start_parachain( match foreground_message { ToBackground::IsNearHeadOfChainHeuristic { send_back } => { - // Since there is a mapping between relay chain blocks and parachain - // blocks, whether a parachain is at the head of the chain is the - // same thing as whether its relay chain is at the head of the chain. - // Note that there is no ordering guarantee of any kind w.r.t. - // block subscriptions notifications. - // TODO: that's not exactly true, we might not have fetched any parahead yet - let val = relay_chain_sync.is_near_head_of_chain_heuristic().await; - let _ = send_back.send(val); + if async_tree.finalized_async_user_data().is_some() { + // Since there is a mapping between relay chain blocks and + // parachain blocks, whether a parachain is at the head of the + // chain is the same thing as whether its relay chain is at the + // head of the chain. + // Note that there is no ordering guarantee of any kind w.r.t. + // block subscriptions notifications. + let val = relay_chain_sync.is_near_head_of_chain_heuristic().await; + let _ = send_back.send(val); + } else { + // If no finalized parahead is known yet, we might be very close + // to the head but also maybe very very far away. We lean on the + // cautious side and always return `false`. + let _ = send_back.send(false); + } }, ToBackground::SubscribeAll { send_back, buffer_size, .. } => { let (tx, new_blocks) = mpsc::channel(buffer_size.saturating_sub(1)); From a87cd664d0db7a5a2c25bc71ac48467e3ca46ca3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:52:54 +0200 Subject: [PATCH 13/14] CHANGELOG --- bin/wasm-node/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/wasm-node/CHANGELOG.md b/bin/wasm-node/CHANGELOG.md index c3427099a6..15d3a2cfec 100644 --- a/bin/wasm-node/CHANGELOG.md +++ b/bin/wasm-node/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Fixed + +- Fix sometimes erroneously reporting a very old `parent_hash` (usually the genesis block hash) in `chainHead_unstable_follow` when following a parachain. +- After smoldot has downloaded the runtime of an old parachain block, it would sometimes erroneously consider that this runtime hasn't changed since then. This would lead to issues such as `state_getRuntimeVersion` and `state_subscribeRuntimeVersion` returning information about an old runtime, or `state_getMetadata` or `state_call` using an old runtime. + ## 0.6.28 - 2022-08-08 ### Changed From ed8a971980e9bccd2aac05a9120c8e7f2ad4abb7 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 9 Aug 2022 10:57:54 +0200 Subject: [PATCH 14/14] PR number --- bin/wasm-node/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/wasm-node/CHANGELOG.md b/bin/wasm-node/CHANGELOG.md index 15d3a2cfec..5f111715cf 100644 --- a/bin/wasm-node/CHANGELOG.md +++ b/bin/wasm-node/CHANGELOG.md @@ -4,8 +4,8 @@ ### Fixed -- Fix sometimes erroneously reporting a very old `parent_hash` (usually the genesis block hash) in `chainHead_unstable_follow` when following a parachain. -- After smoldot has downloaded the runtime of an old parachain block, it would sometimes erroneously consider that this runtime hasn't changed since then. This would lead to issues such as `state_getRuntimeVersion` and `state_subscribeRuntimeVersion` returning information about an old runtime, or `state_getMetadata` or `state_call` using an old runtime. +- Fix sometimes erroneously reporting a very old `parent_hash` (usually the genesis block hash) in `chainHead_unstable_follow` when following a parachain. ([#2602](https://github.com/paritytech/smoldot/pull/2602)) +- After smoldot has downloaded the runtime of an old parachain block, it would sometimes erroneously consider that this runtime hasn't changed since then. This would lead to issues such as `state_getRuntimeVersion` and `state_subscribeRuntimeVersion` returning information about an old runtime, or `state_getMetadata` or `state_call` using an old runtime. ([#2602](https://github.com/paritytech/smoldot/pull/2602)) ## 0.6.28 - 2022-08-08