diff --git a/backend/telemetry_core/src/aggregator/inner_loop.rs b/backend/telemetry_core/src/aggregator/inner_loop.rs index 7b08cd2..c24df52 100644 --- a/backend/telemetry_core/src/aggregator/inner_loop.rs +++ b/backend/telemetry_core/src/aggregator/inner_loop.rs @@ -94,7 +94,7 @@ pub enum FromFeedWebsocket { }, /// The feed can subscribe to a chain to receive /// messages relating to it. - Subscribe { chain: Box }, + Subscribe { chain: BlockHash }, /// The feed wants finality info for the chain, too. SendFinality, /// The feed doesn't want any more finality info for the chain. @@ -136,12 +136,16 @@ impl FromStr for FromFeedWebsocket { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let (cmd, value) = match s.find(':') { - Some(idx) => (&s[..idx], s[idx + 1..].into()), + Some(idx) => (&s[..idx], &s[idx + 1..]), None => return Err(anyhow::anyhow!("Expecting format `CMD:CHAIN_NAME`")), }; match cmd { - "ping" => Ok(FromFeedWebsocket::Ping { value }), - "subscribe" => Ok(FromFeedWebsocket::Subscribe { chain: value }), + "ping" => Ok(FromFeedWebsocket::Ping { + value: value.into(), + }), + "subscribe" => Ok(FromFeedWebsocket::Subscribe { + chain: value.parse()?, + }), "send-finality" => Ok(FromFeedWebsocket::SendFinality), "no-more-finality" => Ok(FromFeedWebsocket::NoMoreFinality), _ => return Err(anyhow::anyhow!("Command {} not recognised", cmd)), @@ -306,7 +310,7 @@ impl InnerLoop { let chain_genesis_hash = self .node_state .get_chain_by_node_id(node_id) - .map(|chain| *chain.genesis_hash()); + .map(|chain| chain.genesis_hash()); if let Some(chain_genesis_hash) = chain_genesis_hash { self.finalize_and_broadcast_to_chain_feeds( @@ -353,7 +357,6 @@ impl InnerLoop { self.node_ids.insert(node_id, (shard_conn_id, local_id)); // Don't hold onto details too long because we want &mut self later: - let old_chain_label = details.old_chain_label.to_owned(); let new_chain_label = details.new_chain_label.to_owned(); let chain_node_count = details.chain_node_count; let has_chain_label_changed = details.has_chain_label_changed; @@ -371,11 +374,13 @@ impl InnerLoop { // Tell everybody about the new node count and potential rename: let mut feed_messages_for_all = FeedMessageSerializer::new(); if has_chain_label_changed { - feed_messages_for_all - .push(feed_message::RemovedChain(&old_chain_label)); + feed_messages_for_all.push(feed_message::RemovedChain(genesis_hash)); } - feed_messages_for_all - .push(feed_message::AddedChain(&new_chain_label, chain_node_count)); + feed_messages_for_all.push(feed_message::AddedChain( + &new_chain_label, + genesis_hash, + chain_node_count, + )); self.finalize_and_broadcast_to_all_feeds(feed_messages_for_all); // Ask for the grographical location of the node. @@ -419,7 +424,7 @@ impl InnerLoop { .update_node(node_id, payload, &mut feed_message_serializer); if let Some(chain) = self.node_state.get_chain_by_node_id(node_id) { - let genesis_hash = *chain.genesis_hash(); + let genesis_hash = chain.genesis_hash(); if broadcast_finality { self.finalize_and_broadcast_to_chain_finality_feeds( &genesis_hash, @@ -456,10 +461,13 @@ impl InnerLoop { // Tell the new feed subscription some basic things to get it going: let mut feed_serializer = FeedMessageSerializer::new(); - feed_serializer.push(feed_message::Version(31)); + feed_serializer.push(feed_message::Version(32)); for chain in self.node_state.iter_chains() { - feed_serializer - .push(feed_message::AddedChain(chain.label(), chain.node_count())); + feed_serializer.push(feed_message::AddedChain( + chain.label(), + chain.genesis_hash(), + chain.node_count(), + )); } // Send this to the channel that subscribed: @@ -498,7 +506,7 @@ impl InnerLoop { old_genesis_hash.and_then(|hash| node_state.get_chain_by_genesis_hash(&hash)); // Get new chain, ignoring the rest if it doesn't exist. - let new_chain = match self.node_state.get_chain_by_label(&chain) { + let new_chain = match self.node_state.get_chain_by_genesis_hash(&chain) { Some(chain) => chain, None => return, }; @@ -506,9 +514,9 @@ impl InnerLoop { // Send messages to the feed about this subscription: let mut feed_serializer = FeedMessageSerializer::new(); if let Some(old_chain) = old_chain { - feed_serializer.push(feed_message::UnsubscribedFrom(old_chain.label())); + feed_serializer.push(feed_message::UnsubscribedFrom(old_chain.genesis_hash())); } - feed_serializer.push(feed_message::SubscribedTo(new_chain.label())); + feed_serializer.push(feed_message::SubscribedTo(new_chain.genesis_hash())); feed_serializer.push(feed_message::TimeSync(time::now())); feed_serializer.push(feed_message::BestBlock( new_chain.best_block().height, @@ -559,7 +567,7 @@ impl InnerLoop { } // Actually make a note of the new chain subsciption: - let new_genesis_hash = *new_chain.genesis_hash(); + let new_genesis_hash = new_chain.genesis_hash(); self.chain_to_feed_conn_ids .insert(new_genesis_hash, feed_conn_id); } @@ -585,7 +593,7 @@ impl InnerLoop { for node_id in node_ids.into_iter() { if let Some(chain) = self.node_state.get_chain_by_node_id(node_id) { node_ids_per_chain - .entry(*chain.genesis_hash()) + .entry(chain.genesis_hash()) .or_default() .push(node_id); } @@ -629,13 +637,16 @@ impl InnerLoop { // The chain has been removed (no nodes left in it, or it was renamed): if removed_details.chain_node_count == 0 || removed_details.has_chain_label_changed { - feed_for_all.push(feed_message::RemovedChain(&removed_details.old_chain_label)); + feed_for_all.push(feed_message::RemovedChain( + removed_details.chain_genesis_hash, + )); } // If the chain still exists, tell everybody about the new label or updated node count: if removed_details.chain_node_count != 0 { feed_for_all.push(feed_message::AddedChain( &removed_details.new_chain_label, + removed_details.chain_genesis_hash, removed_details.chain_node_count, )); } diff --git a/backend/telemetry_core/src/feed_message.rs b/backend/telemetry_core/src/feed_message.rs index 1b5c14e..99c8869 100644 --- a/backend/telemetry_core/src/feed_message.rs +++ b/backend/telemetry_core/src/feed_message.rs @@ -115,9 +115,9 @@ actions! { 9: Hardware<'_>, 10: TimeSync, 11: AddedChain<'_>, - 12: RemovedChain<'_>, - 13: SubscribedTo<'_>, - 14: UnsubscribedFrom<'_>, + 12: RemovedChain, + 13: SubscribedTo, + 14: UnsubscribedFrom, 15: Pong<'_>, 16: AfgFinalized, 17: AfgReceivedPrevote, @@ -163,16 +163,16 @@ pub struct Hardware<'a>(pub FeedNodeId, pub &'a NodeHardware); pub struct TimeSync(pub u64); #[derive(Serialize)] -pub struct AddedChain<'a>(pub &'a str, pub usize); +pub struct AddedChain<'a>(pub &'a str, pub BlockHash, pub usize); #[derive(Serialize)] -pub struct RemovedChain<'a>(pub &'a str); +pub struct RemovedChain(pub BlockHash); #[derive(Serialize)] -pub struct SubscribedTo<'a>(pub &'a str); +pub struct SubscribedTo(pub BlockHash); #[derive(Serialize)] -pub struct UnsubscribedFrom<'a>(pub &'a str); +pub struct UnsubscribedFrom(pub BlockHash); #[derive(Serialize)] pub struct Pong<'a>(pub &'a str); diff --git a/backend/telemetry_core/src/state/chain.rs b/backend/telemetry_core/src/state/chain.rs index 9cb3e46..6ab063e 100644 --- a/backend/telemetry_core/src/state/chain.rs +++ b/backend/telemetry_core/src/state/chain.rs @@ -369,8 +369,8 @@ impl Chain { pub fn finalized_block(&self) -> &Block { &self.finalized } - pub fn genesis_hash(&self) -> &BlockHash { - &self.genesis_hash + pub fn genesis_hash(&self) -> BlockHash { + self.genesis_hash } } diff --git a/backend/telemetry_core/src/state/state.rs b/backend/telemetry_core/src/state/state.rs index 80e153f..6bde12b 100644 --- a/backend/telemetry_core/src/state/state.rs +++ b/backend/telemetry_core/src/state/state.rs @@ -47,7 +47,6 @@ pub struct State { // Find the right chain given various details. chains_by_genesis_hash: HashMap, - chains_by_label: HashMap, ChainId>, /// Chain labels that we do not want to allow connecting. denylist: HashSet, @@ -96,6 +95,8 @@ pub struct RemovedNode { pub has_chain_label_changed: bool, /// The old label of the chain. pub old_chain_label: Box, + /// Genesis hash of the chain to be updated. + pub chain_genesis_hash: BlockHash, /// The new label of the chain. pub new_chain_label: Box, } @@ -105,7 +106,6 @@ impl State { State { chains: DenseMap::new(), chains_by_genesis_hash: HashMap::new(), - chains_by_label: HashMap::new(), denylist: denylist.into_iter().collect(), } } @@ -127,13 +127,6 @@ impl State { .map(|chain| StateChain { chain }) } - pub fn get_chain_by_label(&self, label: &str) -> Option> { - self.chains_by_label - .get(label) - .and_then(|&chain_id| self.chains.get(chain_id)) - .map(|chain| StateChain { chain }) - } - pub fn add_node( &mut self, genesis_hash: BlockHash, @@ -169,17 +162,10 @@ impl State { chain::AddNodeResult::Added { id, chain_renamed } => { let chain = &*chain; - // Update the label we use to reference the chain if - // it changes (it'll always change first time a node's added): - if chain_renamed { - self.chains_by_label.remove(&old_chain_label); - self.chains_by_label.insert(chain.label().into(), chain_id); - } - AddNodeResult::NodeAddedToChain(NodeAddedToChain { id: NodeId(chain_id, id), node: chain.get_node(id).expect("node added above"), - old_chain_label: old_chain_label, + old_chain_label, new_chain_label: chain.label(), chain_node_count: chain.node_count(), has_chain_label_changed: chain_renamed, @@ -199,26 +185,20 @@ impl State { // Get updated chain details. let new_chain_label: Box = chain.label().into(); let chain_node_count = chain.node_count(); + let chain_genesis_hash = chain.genesis_hash(); // Is the chain empty? Remove if so and clean up indexes to it if chain_node_count == 0 { - let genesis_hash = *chain.genesis_hash(); - self.chains_by_label.remove(&old_chain_label); + let genesis_hash = chain.genesis_hash(); self.chains_by_genesis_hash.remove(&genesis_hash); self.chains.remove(chain_id); } - // Make sure chains always referenced by their most common label: - if remove_result.chain_renamed { - self.chains_by_label.remove(&old_chain_label); - self.chains_by_label - .insert(new_chain_label.clone(), chain_id); - } - Some(RemovedNode { old_chain_label, new_chain_label, - chain_node_count: chain_node_count, + chain_node_count, + chain_genesis_hash, has_chain_label_changed: remove_result.chain_renamed, }) } @@ -268,7 +248,7 @@ impl<'a> StateChain<'a> { pub fn label(&self) -> &'a str { self.chain.label() } - pub fn genesis_hash(&self) -> &'a BlockHash { + pub fn genesis_hash(&self) -> BlockHash { self.chain.genesis_hash() } pub fn node_count(&self) -> usize { @@ -358,7 +338,6 @@ mod test { .label(), "Chain One" ); - assert!(state.get_chain_by_label("Chain One").is_some()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_some()); let node_id1 = state @@ -373,7 +352,6 @@ mod test { .label(), "Chain One" ); - assert!(state.get_chain_by_label("Chain One").is_some()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_some()); let node_id2 = state @@ -388,8 +366,6 @@ mod test { .label(), "Chain Two" ); - assert!(state.get_chain_by_label("Chain One").is_none()); - assert!(state.get_chain_by_label("Chain Two").is_some()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_some()); state.remove_node(node_id1).expect("Removal OK (id: 1)"); @@ -403,8 +379,6 @@ mod test { .label(), "Chain One" ); - assert!(state.get_chain_by_label("Chain One").is_some()); - assert!(state.get_chain_by_label("Chain Two").is_none()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_some()); } @@ -417,13 +391,11 @@ mod test { .add_node(chain1_genesis, node("A", "Chain One")) // 0 .unwrap_id(); - assert!(state.get_chain_by_label("Chain One").is_some()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_some()); assert_eq!(state.iter_chains().count(), 1); state.remove_node(node_id); - assert!(state.get_chain_by_label("Chain One").is_none()); assert!(state.get_chain_by_genesis_hash(&chain1_genesis).is_none()); assert_eq!(state.iter_chains().count(), 0); } diff --git a/backend/telemetry_core/tests/e2e_tests.rs b/backend/telemetry_core/tests/e2e_tests.rs index 7951749..07dd011 100644 --- a/backend/telemetry_core/tests/e2e_tests.rs +++ b/backend/telemetry_core/tests/e2e_tests.rs @@ -46,6 +46,11 @@ use test_utils::{ workspace::{start_server, start_server_debug, CoreOpts, ServerOpts, ShardOpts}, }; +/// Helper for concise testing +fn ghash(id: u64) -> BlockHash { + BlockHash::from_low_u64_be(id) +} + /// The simplest test we can run; the main benefit of this test (since we check similar) /// below) is just to give a feel for _how_ we can test basic feed related things. #[ignore] @@ -60,7 +65,7 @@ async fn e2e_feed_sent_version_on_connect() { let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert_eq!( feed_messages, - vec![FeedMessage::Version(31)], + vec![FeedMessage::Version(32)], "expecting version" ); @@ -120,7 +125,7 @@ async fn e2e_multiple_feeds_sent_version_on_connect() { for feed_messages in responses { assert_eq!( feed_messages.expect("should have messages"), - vec![FeedMessage::Version(31)], + vec![FeedMessage::Version(32)], "expecting version" ); } @@ -159,7 +164,7 @@ async fn e2e_lots_of_mute_messages_dont_cause_a_deadlock() { "authority":true, "chain":"Local Testnet", "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(1), + "genesis_hash": ghash(1), "implementation":"Substrate Node", "msg":"system.connected", "name": format!("Alice {}", idx), @@ -217,7 +222,7 @@ async fn e2e_feed_add_and_remove_node() { "authority":true, "chain":"Local Testnet", "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(1), + "genesis_hash": ghash(1), "implementation":"Substrate Node", "msg":"system.connected", "name":"Alice", @@ -239,7 +244,8 @@ async fn e2e_feed_add_and_remove_node() { let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert!(feed_messages.contains(&FeedMessage::AddedChain { name: "Local Testnet".to_owned(), - node_count: 1 + genesis_hash: ghash(1), + node_count: 1, })); // Disconnect the node: @@ -247,7 +253,7 @@ async fn e2e_feed_add_and_remove_node() { let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert!(feed_messages.contains(&FeedMessage::RemovedChain { - name: "Local Testnet".to_owned(), + genesis_hash: ghash(1), })); // Tidy up: @@ -278,7 +284,7 @@ async fn e2e_feeds_told_about_chain_rename_and_stay_subscribed() { "authority":true, "chain": chain_name, "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(1), + "genesis_hash": ghash(1), "implementation":"Substrate Node", "msg":"system.connected", "name": node_name, @@ -297,15 +303,18 @@ async fn e2e_feeds_told_about_chain_rename_and_stay_subscribed() { // Connect a feed and subscribe to the above chain: let (feed_tx, mut feed_rx) = server.get_core().connect_feed().await.unwrap(); feed_tx - .send_command("subscribe", "Initial chain name") + .send_command( + "subscribe", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) .unwrap(); // Feed is told about the chain, and the node on this chain: let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert_contains_matches!( feed_messages, - FeedMessage::AddedChain { name, node_count: 1 } if name == "Initial chain name", - FeedMessage::SubscribedTo { name } if name == "Initial chain name", + FeedMessage::AddedChain { name, genesis_hash, node_count: 1 } if name == "Initial chain name" && genesis_hash == ghash(1), + FeedMessage::SubscribedTo { genesis_hash } if genesis_hash == ghash(1), FeedMessage::AddedNode { node: NodeDetails { name: node_name, .. }, ..} if node_name == "Node 1", ); @@ -318,7 +327,7 @@ async fn e2e_feeds_told_about_chain_rename_and_stay_subscribed() { assert_contains_matches!( feed_messages, FeedMessage::AddedNode { node: NodeDetails { name: node_name, .. }, ..} if node_name == "Node 2", - FeedMessage::AddedChain { name, node_count: 2 } if name == "Initial chain name", + FeedMessage::AddedChain { name, genesis_hash, node_count: 2 } if name == "Initial chain name" && genesis_hash == ghash(1), ); // Subscribe a third node. The chain renames, so we're told about the new node but also @@ -330,8 +339,8 @@ async fn e2e_feeds_told_about_chain_rename_and_stay_subscribed() { assert_contains_matches!( feed_messages, FeedMessage::AddedNode { node: NodeDetails { name: node_name, .. }, ..} if node_name == "Node 3", - FeedMessage::RemovedChain { name } if name == "Initial chain name", - FeedMessage::AddedChain { name, node_count: 3 } if name == "New chain name", + FeedMessage::RemovedChain { genesis_hash } if genesis_hash == ghash(1), + FeedMessage::AddedChain { name, genesis_hash, node_count: 3 } if name == "New chain name" && genesis_hash == ghash(1), ); // Just to be sure, subscribing a fourth node on this chain will still lead to updates @@ -343,7 +352,7 @@ async fn e2e_feeds_told_about_chain_rename_and_stay_subscribed() { assert_contains_matches!( feed_messages, FeedMessage::AddedNode { node: NodeDetails { name: node_name, .. }, ..} if node_name == "Node 4", - FeedMessage::AddedChain { name, node_count: 4 } if name == "New chain name", + FeedMessage::AddedChain { name, genesis_hash, node_count: 4 } if name == "New chain name" && genesis_hash == ghash(1), ); } @@ -377,7 +386,7 @@ async fn e2e_feed_add_and_remove_shard() { "authority":true, "chain": format!("Local Testnet {}", id), "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(id), + "genesis_hash": ghash(id), "implementation":"Substrate Node", "msg":"system.connected", "name":"Alice", @@ -399,10 +408,12 @@ async fn e2e_feed_add_and_remove_shard() { let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert!(feed_messages.contains(&FeedMessage::AddedChain { name: "Local Testnet 1".to_owned(), + genesis_hash: ghash(1), node_count: 1 })); assert!(feed_messages.contains(&FeedMessage::AddedChain { name: "Local Testnet 2".to_owned(), + genesis_hash: ghash(2), node_count: 1 })); @@ -412,12 +423,12 @@ async fn e2e_feed_add_and_remove_shard() { // We should be told about the node connected to that shard disconnecting: let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert!(feed_messages.contains(&FeedMessage::RemovedChain { - name: "Local Testnet 1".to_owned(), + genesis_hash: ghash(1), })); assert!(!feed_messages.contains( // Spot the "!"; this chain was not removed. &FeedMessage::RemovedChain { - name: "Local Testnet 2".to_owned(), + genesis_hash: ghash(2), } )); @@ -453,7 +464,7 @@ async fn e2e_feed_can_subscribe_and_unsubscribe_from_chain() { "authority":true, "chain":format!("Local Testnet {}", id), "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(id), + "genesis_hash": ghash(id), "implementation":"Substrate Node", "msg":"system.connected", "name":format!("Alice {}", id), @@ -470,17 +481,20 @@ async fn e2e_feed_can_subscribe_and_unsubscribe_from_chain() { let (feed_tx, mut feed_rx) = server.get_core().connect_feed().await.unwrap(); let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); - assert_contains_matches!(feed_messages, AddedChain { name, node_count: 1 } if name == "Local Testnet 1"); + assert_contains_matches!(feed_messages, AddedChain { name, genesis_hash, node_count: 1 } if name == "Local Testnet 1" && genesis_hash == ghash(1)); // Subscribe it to a chain feed_tx - .send_command("subscribe", "Local Testnet 1") + .send_command( + "subscribe", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) .unwrap(); let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); assert_contains_matches!( feed_messages, - SubscribedTo { name } if name == "Local Testnet 1", + SubscribedTo { genesis_hash } if genesis_hash == ghash(1), TimeSync {..}, BestBlock { block_number: 0, timestamp: 0, avg_block_time: None }, BestFinalized { block_number: 0, .. }, @@ -507,15 +521,18 @@ async fn e2e_feed_can_subscribe_and_unsubscribe_from_chain() { // We can change our subscription: feed_tx - .send_command("subscribe", "Local Testnet 2") + .send_command( + "subscribe", + "0x0000000000000000000000000000000000000000000000000000000000000002", + ) .unwrap(); let feed_messages = feed_rx.recv_feed_messages().await.unwrap(); // We are told about the subscription change and given similar on-subscribe messages to above. assert_contains_matches!( &feed_messages, - UnsubscribedFrom { name } if name == "Local Testnet 1", - SubscribedTo { name } if name == "Local Testnet 2", + UnsubscribedFrom { genesis_hash } if *genesis_hash == ghash(1), + SubscribedTo { genesis_hash } if *genesis_hash == ghash(2), TimeSync {..}, BestBlock {..}, BestFinalized {..}, @@ -630,7 +647,7 @@ async fn e2e_slow_feeds_are_disconnected() { "authority":true, "chain":"Polkadot", "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(1), + "genesis_hash": ghash(1), "implementation":"Substrate Node", "msg":"system.connected", "name": format!("Alice {}", n), @@ -721,7 +738,7 @@ async fn e2e_max_nodes_per_connection_is_enforced() { "authority":true, "chain":"Test Chain", "config":"", - "genesis_hash": BlockHash::from_low_u64_ne(1), + "genesis_hash": ghash(1), "implementation":"Polkadot", "msg":"system.connected", "name": format!("Alice {}", n), @@ -779,7 +796,12 @@ async fn e2e_max_nodes_per_connection_is_enforced() { // (now that the chain "Test Chain" is known about, subscribe to it for update messages. // This wasn't needed to receive messages re the above since everybody hears about node // count changes) - feed_tx.send_command("subscribe", "Test Chain").unwrap(); + feed_tx + .send_command( + "subscribe", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) + .unwrap(); feed_rx.recv_feed_messages().await.unwrap(); // Update about non-ignored IDs should still lead to feed output: diff --git a/backend/test_utils/src/feed_message_de.rs b/backend/test_utils/src/feed_message_de.rs index e8030c9..9770b1b 100644 --- a/backend/test_utils/src/feed_message_de.rs +++ b/backend/test_utils/src/feed_message_de.rs @@ -73,16 +73,17 @@ pub enum FeedMessage { }, AddedChain { name: String, + genesis_hash: BlockHash, node_count: usize, }, RemovedChain { - name: String, + genesis_hash: BlockHash, }, SubscribedTo { - name: String, + genesis_hash: BlockHash, }, UnsubscribedFrom { - name: String, + genesis_hash: BlockHash, }, Pong { msg: String, @@ -260,23 +261,27 @@ impl FeedMessage { } // AddedChain 11 => { - let (name, node_count) = serde_json::from_str(raw_val.get())?; - FeedMessage::AddedChain { name, node_count } + let (name, genesis_hash, node_count) = serde_json::from_str(raw_val.get())?; + FeedMessage::AddedChain { + name, + genesis_hash, + node_count, + } } // RemovedChain 12 => { - let name = serde_json::from_str(raw_val.get())?; - FeedMessage::RemovedChain { name } + let genesis_hash = serde_json::from_str(raw_val.get())?; + FeedMessage::RemovedChain { genesis_hash } } // SubscribedTo 13 => { - let name = serde_json::from_str(raw_val.get())?; - FeedMessage::SubscribedTo { name } + let genesis_hash = serde_json::from_str(raw_val.get())?; + FeedMessage::SubscribedTo { genesis_hash } } // UnsubscribedFrom 14 => { - let name = serde_json::from_str(raw_val.get())?; - FeedMessage::UnsubscribedFrom { name } + let genesis_hash = serde_json::from_str(raw_val.get())?; + FeedMessage::UnsubscribedFrom { genesis_hash } } // Pong 15 => { @@ -355,12 +360,12 @@ mod test { #[test] fn decode_remove_node_msg() { // "remove chain ''": - let msg = r#"[12,""]"#; + let msg = r#"[12,"0x0000000000000000000000000000000000000000000000000000000000000000"]"#; assert_eq!( FeedMessage::from_bytes(msg.as_bytes()).unwrap(), vec![FeedMessage::RemovedChain { - name: "".to_owned() + genesis_hash: BlockHash::zero(), }] ); } @@ -368,16 +373,17 @@ mod test { #[test] fn decode_remove_then_add_node_msg() { // "remove chain '', then add chain 'Local Testnet' with 1 node": - let msg = r#"[12,"",11,["Local Testnet",1]]"#; + let msg = r#"[12,"0x0000000000000000000000000000000000000000000000000000000000000000",11,["Local Testnet","0x0000000000000000000000000000000000000000000000000000000000000000",1]]"#; assert_eq!( FeedMessage::from_bytes(msg.as_bytes()).unwrap(), vec![ FeedMessage::RemovedChain { - name: "".to_owned() + genesis_hash: BlockHash::zero(), }, FeedMessage::AddedChain { name: "Local Testnet".to_owned(), + genesis_hash: BlockHash::zero(), node_count: 1 }, ] diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index af0a411..bb145ef 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -228,7 +228,7 @@ export default class App extends React.Component<{}, {}> { this.chainsCache = stable.inplace( Array.from(this.appState.chains.values()), (a, b) => { - const pinned = comparePinnedChains(a.label, b.label); + const pinned = comparePinnedChains(a.genesisHash, b.genesisHash); if (pinned !== 0) { return pinned; diff --git a/frontend/src/Connection.ts b/frontend/src/Connection.ts index 23ddb1e..c378ca5 100644 --- a/frontend/src/Connection.ts +++ b/frontend/src/Connection.ts @@ -119,7 +119,7 @@ export class Connection { // timestamp at which the last ping has been sent private pingSent: Maybe = null; // chain label to resubsribe to on reconnect - private resubscribeTo: Maybe = getHashData().chain; + private resubscribeTo: Maybe = getHashData().chain; // flag whether or not FE should subscribe to consensus updates on reconnect private resubscribeSendFinality: boolean = getHashData().tab === 'consensus'; @@ -132,7 +132,7 @@ export class Connection { this.bindSocket(); } - public subscribe(chain: Types.ChainLabel) { + public subscribe(chain: Types.GenesisHash) { if ( this.appState.subscribed != null && this.appState.subscribed !== chain @@ -148,7 +148,7 @@ export class Connection { this.socket.send(`subscribe:${chain}`); } - public subscribeConsensus(chain: Types.ChainLabel) { + public subscribeConsensus(chain: Types.GenesisHash) { if (this.appState.authorities.length <= VIS_AUTHORITIES_LIMIT) { setHashData({ chain }); this.resubscribeSendFinality = true; @@ -165,7 +165,7 @@ export class Connection { }); } - public unsubscribeConsensus(chain: Types.ChainLabel) { + public unsubscribeConsensus(chain: Types.GenesisHash) { this.resubscribeSendFinality = true; this.socket.send(`no-more-finality:${chain}`); } @@ -334,13 +334,13 @@ export class Connection { } case ACTIONS.AddedChain: { - const [label, nodeCount] = message.payload; - const chain = chains.get(label); + const [label, genesisHash, nodeCount] = message.payload; + const chain = chains.get(genesisHash); if (chain) { chain.nodeCount = nodeCount; } else { - chains.set(label, { label, nodeCount }); + chains.set(genesisHash, { label, genesisHash, nodeCount }); } this.appUpdate({ chains }); @@ -552,7 +552,7 @@ export class Connection { } if (topChain) { - this.subscribe(topChain.label); + this.subscribe(topChain.genesisHash); } } diff --git a/frontend/src/common/feed.ts b/frontend/src/common/feed.ts index ffc74c6..044c645 100644 --- a/frontend/src/common/feed.ts +++ b/frontend/src/common/feed.ts @@ -35,6 +35,7 @@ import { Timestamp, Milliseconds, ChainLabel, + GenesisHash, AuthoritySetInfo, } from './types'; @@ -142,22 +143,22 @@ export namespace Variants { export interface AddedChainMessage extends MessageBase { action: typeof ACTIONS.AddedChain; - payload: [ChainLabel, NodeCount]; + payload: [ChainLabel, GenesisHash, NodeCount]; } export interface RemovedChainMessage extends MessageBase { action: typeof ACTIONS.RemovedChain; - payload: ChainLabel; + payload: GenesisHash; } export interface SubscribedToMessage extends MessageBase { action: typeof ACTIONS.SubscribedTo; - payload: ChainLabel; + payload: GenesisHash; } export interface UnsubscribedFromMessage extends MessageBase { action: typeof ACTIONS.UnsubscribedFrom; - payload: ChainLabel; + payload: GenesisHash; } export interface PongMessage extends MessageBase { diff --git a/frontend/src/common/index.ts b/frontend/src/common/index.ts index 55bdb46..30eed29 100644 --- a/frontend/src/common/index.ts +++ b/frontend/src/common/index.ts @@ -25,4 +25,4 @@ import * as FeedMessage from './feed'; export { Types, FeedMessage }; // Increment this if breaking changes were made to types in `feed.ts` -export const VERSION: Types.FeedVersion = 31 as Types.FeedVersion; +export const VERSION: Types.FeedVersion = 32 as Types.FeedVersion; diff --git a/frontend/src/common/types.ts b/frontend/src/common/types.ts index c7e165e..c3c3d33 100644 --- a/frontend/src/common/types.ts +++ b/frontend/src/common/types.ts @@ -19,6 +19,7 @@ import { Id } from './id'; export type FeedVersion = Opaque; export type ChainLabel = Opaque; +export type GenesisHash = Opaque; export type FeedId = Id<'Feed'>; export type NodeId = Id<'Node'>; export type NodeName = Opaque; diff --git a/frontend/src/components/AllChains.tsx b/frontend/src/components/AllChains.tsx index 35e5f3c..f026604 100644 --- a/frontend/src/components/AllChains.tsx +++ b/frontend/src/components/AllChains.tsx @@ -24,7 +24,7 @@ import './AllChains.css'; export namespace AllChains { export interface Props { chains: ChainData[]; - subscribed: Maybe; + subscribed: Maybe; connection: Promise; } } @@ -45,10 +45,10 @@ export class AllChains extends React.Component { } private renderChain(chain: ChainData): React.ReactNode { - const { label, nodeCount } = chain; + const { label, genesisHash, nodeCount } = chain; const className = - label === this.props.subscribed + genesisHash === this.props.subscribed ? 'AllChains-chain AllChains-chain-selected' : 'AllChains-chain'; @@ -56,7 +56,7 @@ export class AllChains extends React.Component { {label}{' '} @@ -66,7 +66,7 @@ export class AllChains extends React.Component { ); } - private async subscribe(chain: Types.ChainLabel) { + private async subscribe(chain: Types.GenesisHash) { const connection = await this.props.connection; connection.subscribe(chain); diff --git a/frontend/src/components/Chains.tsx b/frontend/src/components/Chains.tsx index 228cdd7..13ddb4a 100644 --- a/frontend/src/components/Chains.tsx +++ b/frontend/src/components/Chains.tsx @@ -27,7 +27,7 @@ import './Chains.css'; export namespace Chains { export interface Props { chains: ChainData[]; - subscribed: Maybe; + subscribed: Maybe; connection: Promise; } } @@ -39,7 +39,7 @@ const RENDER_THROTTLE = 1000; export class Chains extends React.Component { private lastRender = performance.now(); - private clicked: Maybe; + private clicked: Maybe; public shouldComponentUpdate(nextProps: Chains.Props) { if (nextProps.subscribed !== this.clicked) { @@ -83,11 +83,11 @@ export class Chains extends React.Component { } private renderChain(chain: ChainData): React.ReactNode { - const { label, nodeCount } = chain; + const { label, genesisHash, nodeCount } = chain; let className = 'Chains-chain'; - if (label === this.props.subscribed) { + if (genesisHash === this.props.subscribed) { className += ' Chains-chain-selected'; } @@ -95,7 +95,7 @@ export class Chains extends React.Component { {label} @@ -105,7 +105,7 @@ export class Chains extends React.Component { ); } - private async subscribe(chain: Types.ChainLabel) { + private async subscribe(chain: Types.GenesisHash) { if (chain === this.clicked) { return; } diff --git a/frontend/src/components/Consensus/Consensus.tsx b/frontend/src/components/Consensus/Consensus.tsx index 682962b..e2d0cfb 100644 --- a/frontend/src/components/Consensus/Consensus.tsx +++ b/frontend/src/components/Consensus/Consensus.tsx @@ -427,12 +427,12 @@ export class Consensus extends React.Component { ); } - private async subscribeConsensus(chain: Types.ChainLabel) { + private async subscribeConsensus(chain: Types.GenesisHash) { const connection = await this.props.connection; connection.subscribeConsensus(chain); } - private async unsubscribeConsensus(chain: Types.ChainLabel) { + private async unsubscribeConsensus(chain: Types.GenesisHash) { const connection = await this.props.connection; connection.unsubscribeConsensus(chain); } diff --git a/frontend/src/state.ts b/frontend/src/state.ts index ff64e62..29510b2 100644 --- a/frontend/src/state.ts +++ b/frontend/src/state.ts @@ -19,8 +19,10 @@ import { Types, Maybe, SortedCollection } from './common'; import { Column } from './components/List'; export const PINNED_CHAINS = { - Kusama: 2, - Polkadot: 1, + // Kusama + '0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe': 2, + // Polkadot + '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3': 1, }; export function comparePinnedChains(a: string, b: string) { @@ -275,8 +277,8 @@ export interface State { blockTimestamp: Types.Timestamp; blockAverage: Maybe; timeDiff: Types.Milliseconds; - subscribed: Maybe; - chains: Map; + subscribed: Maybe; + chains: Map; nodes: SortedCollection; settings: Readonly; pins: Readonly>; @@ -290,5 +292,6 @@ export type Update = ( export interface ChainData { label: Types.ChainLabel; + genesisHash: Types.GenesisHash; nodeCount: Types.NodeCount; } diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index 8522727..53edb80 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -88,7 +88,7 @@ export function secondsWithPrecision(num: number): string { export interface HashData { tab?: string; - chain?: Types.ChainLabel; + chain?: Types.GenesisHash; } export function getHashData(): HashData { @@ -99,7 +99,7 @@ export function getHashData(): HashData { } const [tab, rawChain] = hash.substr(1).split('/'); - const chain = decodeURIComponent(rawChain) as Types.ChainLabel; + const chain = decodeURIComponent(rawChain) as Types.GenesisHash; return { tab, chain }; }