From c6f03fbb3f103f4a099f5e2050f01f65766821f9 Mon Sep 17 00:00:00 2001 From: prop-opentensor Date: Tue, 31 Mar 2026 19:44:27 +0200 Subject: [PATCH 1/5] Set distinct protocol ID for testnet --- chainspecs/raw_spec_testfinney.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainspecs/raw_spec_testfinney.json b/chainspecs/raw_spec_testfinney.json index 08eabf415c..4d9305a156 100644 --- a/chainspecs/raw_spec_testfinney.json +++ b/chainspecs/raw_spec_testfinney.json @@ -6,7 +6,7 @@ "/dns/bootnode.test.chain.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr" ], "telemetryEndpoints": null, - "protocolId": "bittensor", + "protocolId": "bittensor-testnet", "properties": { "ss58Format": 42, "tokenDecimals": 9, From 34ad9593c8c679fca8cf4670816aeb025bd32191 Mon Sep 17 00:00:00 2001 From: prop-opentensor Date: Tue, 31 Mar 2026 19:44:52 +0200 Subject: [PATCH 2/5] Fix testnet warp sync handling --- node/src/service.rs | 411 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 386 insertions(+), 25 deletions(-) diff --git a/node/src/service.rs b/node/src/service.rs index 067fc3ff91..dd151c1dad 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -11,14 +11,19 @@ use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_consensus_slots::SlotProportion; use sc_keystore::LocalKeystore; use sc_network::config::SyncMode; -use sc_network_sync::strategy::warp::{WarpSyncConfig, WarpSyncProvider}; +use sc_network_sync::strategy::warp::{ + EncodedProof, VerificationResult, WarpSyncConfig, WarpSyncProvider, +}; use sc_service::{Configuration, PartialComponents, TaskManager, error::Error as ServiceError}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, log}; use sc_transaction_pool::TransactionPoolHandle; use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_core::H256; use sp_core::crypto::KeyTypeId; use sp_keystore::Keystore; +use sp_runtime::codec::{DecodeAll, Encode}; +use sp_runtime::generic::BlockId; use sp_runtime::key_types; use sp_runtime::traits::{Block as BlockT, NumberFor}; use stc_shield::{self, MemoryShieldKeystore}; @@ -38,6 +43,355 @@ use crate::ethereum::{ }; const LOG_TARGET: &str = "node-service"; +const MAX_WARP_SYNC_PROOF_SIZE: usize = 8 * 1024 * 1024; +const TESTNET_WARP_PROTOCOL_ID: &str = "bittensor-testnet"; + +#[derive(Clone)] +struct TestnetWarpFragmentOverride { + set_id: sp_consensus_grandpa::SetId, + block: (H256, u32), + authorities: sp_consensus_grandpa::AuthorityList, +} + +struct TestnetWarpSyncProvider { + backend: Arc, + authority_set: sc_consensus_grandpa::SharedAuthoritySet>, + canonical_changes: Vec<(sp_consensus_grandpa::SetId, u32)>, + inner: sc_consensus_grandpa::warp_proof::NetworkProvider, +} + +fn authority_list_from_hex(authority_hex: &[&str]) -> sp_consensus_grandpa::AuthorityList { + use sp_consensus_grandpa::AuthorityId; + use sp_core::ByteArray; + + authority_hex + .iter() + .map(|hex| { + let bytes: Vec = (0..hex.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).expect("Invalid authority hex")) + .collect(); + ( + AuthorityId::from_slice(&bytes).expect("Invalid authority key length"), + 1, + ) + }) + .collect() +} + +fn testnet_genesis_grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { + authority_list_from_hex(&[ + "dc832c3b7bdfc721e90e5ee9e532c06b62a0def3c79dab5324460d938db6600a", + "c8a00ef71912b3868b101cb70ebd029999d1c9b6a1390122a98f60d72b9a0fc4", + "ee70f7b52998c2b4f3d42e509e8360cda92b0cd4ca100cd4d32be5a1ac297909", + "b57a038c9139a060358f3b654df74a1cb6d15bcdb8438bcebd64ce67ec4301eb", + "755f75dfc66aaa3b1e761a8845249509b8bd2fdf0d94cb74e1e12e1e0f4d3519", + "d97a64267f177505b0565a18677c9f5d4284d7f2eb96d515556e7e52217f82e9", + ]) +} + +fn testnet_warp_fragment_overrides() -> Vec { + let authorities = testnet_genesis_grandpa_authorities(); + + vec![ + TestnetWarpFragmentOverride { + set_id: 0, + block: ( + H256::from_str( + "0x819a5e54ffa2d267d469c6da44de5e8819b1aad1717a1389c959eab4349722ca", + ) + .expect("Invalid testnet authority change hash"), + 4_589_660u32, + ), + authorities: authorities.clone(), + }, + TestnetWarpFragmentOverride { + set_id: 1, + block: ( + H256::from_str( + "0x2b001bfdec34d007ab2ac07f712e64d0cb1a6fb4b51f7d47bfb3c7d7336a689b", + ) + .expect("Invalid testnet authority change hash"), + 4_589_686u32, + ), + authorities: authorities.clone(), + }, + TestnetWarpFragmentOverride { + set_id: 3, + block: ( + H256::from_str( + "0x4d643da5fd7cd2b9ceb795091643e7223819e2a01f942ac049c5b928f7e30dc4", + ) + .expect("Invalid testnet authority change hash"), + 5_534_451u32, + ), + authorities, + }, + ] +} + +impl TestnetWarpSyncProvider { + fn new( + backend: Arc, + authority_set: sc_consensus_grandpa::SharedAuthoritySet>, + overrides: Vec, + ) -> Self { + let canonical_changes = overrides + .iter() + .map(|fork| (fork.set_id, fork.block.1)) + .collect(); + let inner = sc_consensus_grandpa::warp_proof::NetworkProvider::new( + backend.clone(), + authority_set.clone(), + sc_consensus_grandpa::warp_proof::HardForks::new_hard_forked_authorities( + overrides + .into_iter() + .map(|fork| sc_consensus_grandpa::AuthoritySetHardFork { + set_id: fork.set_id, + block: fork.block, + authorities: fork.authorities, + last_finalized: None, + }) + .collect(), + ), + ); + + Self { + backend, + authority_set, + canonical_changes, + inner, + } + } + + fn merged_authority_set_changes( + &self, + begin_number: NumberFor, + ) -> Result< + Vec<(sp_consensus_grandpa::SetId, NumberFor)>, + sc_consensus_grandpa::warp_proof::Error, + > { + merge_testnet_warp_authority_changes( + &self.canonical_changes, + begin_number, + &self.authority_set.authority_set_changes(), + ) + } + + fn generate_proof( + &self, + begin: H256, + ) -> Result< + ( + Vec>, + bool, + ), + sc_consensus_grandpa::warp_proof::Error, + > { + let blockchain = self.backend.blockchain(); + let begin_number = blockchain + .block_number_from_id(&BlockId::Hash(begin))? + .ok_or_else(|| { + sc_consensus_grandpa::warp_proof::Error::InvalidRequest( + "Missing start block".to_string(), + ) + })?; + + if begin_number > blockchain.info().finalized_number { + return Err(sc_consensus_grandpa::warp_proof::Error::InvalidRequest( + "Start block is not finalized".to_string(), + )); + } + + let canon_hash = blockchain.hash(begin_number)?.expect( + "begin number is lower than finalized number; all blocks below finalized number must have been imported; qed.", + ); + + if canon_hash != begin { + return Err(sc_consensus_grandpa::warp_proof::Error::InvalidRequest( + "Start block is not in the finalized chain".to_string(), + )); + } + + let mut proofs = Vec::new(); + let mut proofs_encoded_len = 0; + let mut proof_limit_reached = false; + + for (_, last_block) in self.merged_authority_set_changes(begin_number)? { + let hash = match blockchain.block_hash_from_id(&BlockId::Number(last_block))? { + Some(hash) => hash, + None => { + return Err(sc_consensus_grandpa::warp_proof::Error::InvalidRequest( + "header number comes from previously applied set changes; corresponding hash must exist in db.".to_string(), + )); + } + }; + + let header = match blockchain.header(hash)? { + Some(header) => header, + None => { + return Err(sc_consensus_grandpa::warp_proof::Error::InvalidRequest( + "header hash obtained from header number exists in db; corresponding header must exist in db too.".to_string(), + )); + } + }; + + if sc_consensus_grandpa::find_scheduled_change::(&header).is_none() { + log::debug!( + target: LOG_TARGET, + "Stopping testnet warp proof generation at block #{last_block} because authority_set_changes pointed to a header without a scheduled GRANDPA change digest." + ); + break; + } + + let justification = blockchain + .justifications(header.hash())? + .and_then(|just| just.into_justification(sp_consensus_grandpa::GRANDPA_ENGINE_ID)) + .ok_or(sc_consensus_grandpa::warp_proof::Error::MissingData)?; + + let justification = sc_consensus_grandpa::GrandpaJustification::::decode_all( + &mut &justification[..], + )?; + + let proof = sc_consensus_grandpa::warp_proof::WarpSyncFragment { + header: header.clone(), + justification, + }; + let proof_size = proof.encoded_size(); + + if proofs_encoded_len + proof_size >= MAX_WARP_SYNC_PROOF_SIZE - 50 { + proof_limit_reached = true; + break; + } + + proofs_encoded_len += proof_size; + proofs.push(proof); + } + + let is_finished = if proof_limit_reached { + false + } else { + let latest_justification = sc_consensus_grandpa::best_justification(&*self.backend)? + .filter(|justification| { + let limit = proofs + .last() + .map(|proof| proof.justification.target().0 + 1) + .unwrap_or(begin_number); + + justification.target().0 >= limit + }); + + if let Some(latest_justification) = latest_justification { + let header = blockchain + .header(latest_justification.target().1)? + .expect("header hash corresponds to a justification in db; must exist in db as well; qed."); + + let proof = sc_consensus_grandpa::warp_proof::WarpSyncFragment { + header, + justification: latest_justification, + }; + + if proofs_encoded_len + proof.encoded_size() >= MAX_WARP_SYNC_PROOF_SIZE - 50 { + false + } else { + proofs.push(proof); + true + } + } else { + true + } + }; + + Ok((proofs, is_finished)) + } +} + +impl WarpSyncProvider for TestnetWarpSyncProvider { + fn generate( + &self, + start: H256, + ) -> Result> { + let proof = self.generate_proof(start).map_err(Box::new)?; + Ok(EncodedProof(proof.encode())) + } + + fn verify( + &self, + proof: &EncodedProof, + set_id: sp_consensus_grandpa::SetId, + authorities: sp_consensus_grandpa::AuthorityList, + ) -> Result, Box> { + self.inner.verify(proof, set_id, authorities) + } + + fn current_authorities(&self) -> sp_consensus_grandpa::AuthorityList { + self.inner.current_authorities() + } +} + +fn merge_testnet_warp_authority_changes( + canonical_changes: &[(sp_consensus_grandpa::SetId, u32)], + begin_number: NumberFor, + set_changes: &sc_consensus_grandpa::AuthoritySetChanges>, +) -> Result< + Vec<(sp_consensus_grandpa::SetId, NumberFor)>, + sc_consensus_grandpa::warp_proof::Error, +> { + let mut merged = canonical_changes + .iter() + .copied() + .filter(|(_, block_number)| *block_number > begin_number) + .collect::>(); + + match set_changes.iter_from(begin_number) { + Some(iter) => { + for (set_id, block_number) in iter.cloned() { + if !merged + .iter() + .any(|(_, existing_block_number)| *existing_block_number == block_number) + { + merged.push((set_id, block_number)); + } + } + } + None if merged.is_empty() => { + return Err(sc_consensus_grandpa::warp_proof::Error::MissingData); + } + None => {} + } + + merged.sort_by_key(|(_, block_number)| *block_number); + merged.dedup_by(|left, right| left.1 == right.1); + Ok(merged) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn prefixes_canonical_testnet_warp_transitions_before_poisoned_history() { + let canonical_changes = testnet_warp_fragment_overrides() + .into_iter() + .map(|fork| (fork.set_id, fork.block.1)) + .collect::>(); + let poisoned_changes = + sc_consensus_grandpa::AuthoritySetChanges::from(vec![(0, 5_672_448u32)]); + + let merged = merge_testnet_warp_authority_changes(&canonical_changes, 0, &poisoned_changes) + .expect("canonical overrides should cover genesis start"); + + assert_eq!( + merged, + vec![ + (0, 4_589_660u32), + (1, 4_589_686u32), + (3, 5_534_451u32), + (0, 5_672_448u32), + ], + ); + } +} /// The minimum period of blocks on which justifications will be /// imported and generated. @@ -132,18 +486,15 @@ pub fn new_partial( Some(HashSet::from([hash_5614869, hash_5614888])) } else { - // Testnet patch - let hash_4589660 = - H256::from_str("0x819a5e54ffa2d267d469c6da44de5e8819b1aad1717a1389c959eab4349722ca") - .expect("Invalid hash string."); - - Some(HashSet::from([hash_4589660])) + None }; - log::warn!( - "Grandpa block import patch enabled. Chain type = {:?}. Skip justifications for blocks = {skip_block_justifications:?}", - config.chain_spec.chain_type() - ); + if skip_block_justifications.is_some() { + log::warn!( + "Grandpa block import patch enabled. Chain type = {:?}. Skip justifications for blocks = {skip_block_justifications:?}", + config.chain_spec.chain_type() + ); + } let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( client.clone(), @@ -319,25 +670,35 @@ where let warp_sync_config = if sealing.is_some() { None } else { - let set_id = match config.chain_spec.chain_type() { - // Finney patch - ChainType::Live => 3, - // Testnet patch - ChainType::Development => 2, - // All others (e.g. localnet) - _ => 0, - }; log::warn!( - "Grandpa warp sync patch enabled. Chain type = {:?}. Set ID = {set_id}", + "Grandpa warp sync patch enabled. Chain type = {:?}.", config.chain_spec.chain_type() ); net_config.add_notification_protocol(grandpa_protocol_config); + let shared_authority_set = grandpa_link.shared_authority_set().clone(); let warp_sync: Arc> = - Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( - backend.clone(), - grandpa_link.shared_authority_set().clone(), - sc_consensus_grandpa::warp_proof::HardForks::new_initial_set_id(set_id), - )); + if config.chain_spec.protocol_id() == Some(TESTNET_WARP_PROTOCOL_ID) { + Arc::new(TestnetWarpSyncProvider::new( + backend.clone(), + shared_authority_set, + testnet_warp_fragment_overrides(), + )) + } else { + match config.chain_spec.chain_type() { + ChainType::Live => { + Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( + backend.clone(), + shared_authority_set, + sc_consensus_grandpa::warp_proof::HardForks::new_initial_set_id(3), + )) + } + _ => Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( + backend.clone(), + shared_authority_set, + sc_consensus_grandpa::warp_proof::HardForks::new_initial_set_id(0), + )), + } + }; Some(WarpSyncConfig::WithProvider(warp_sync)) }; From c4d19a2032c4fbc290235bc6de6644543a81f639 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 1 Apr 2026 16:57:31 +0200 Subject: [PATCH 3/5] Fix clippy lints in testnet warp service --- node/src/service.rs | 128 ++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 47 deletions(-) diff --git a/node/src/service.rs b/node/src/service.rs index dd151c1dad..a580d906ea 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -44,6 +44,7 @@ use crate::ethereum::{ const LOG_TARGET: &str = "node-service"; const MAX_WARP_SYNC_PROOF_SIZE: usize = 8 * 1024 * 1024; +const MAX_WARP_SYNC_PROOF_SIZE_LIMIT: usize = MAX_WARP_SYNC_PROOF_SIZE - 50; const TESTNET_WARP_PROTOCOL_ID: &str = "bittensor-testnet"; #[derive(Clone)] @@ -69,16 +70,43 @@ fn authority_list_from_hex(authority_hex: &[&str]) -> sp_consensus_grandpa::Auth .map(|hex| { let bytes: Vec = (0..hex.len()) .step_by(2) - .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).expect("Invalid authority hex")) + .map(|i| { + let end = match i.checked_add(2) { + Some(end) => end, + None => panic!("Authority hex index overflow for {hex}"), + }; + + match u8::from_str_radix(&hex[i..end], 16) { + Ok(byte) => byte, + Err(_) => panic!("Invalid authority hex: {hex}"), + } + }) .collect(); ( - AuthorityId::from_slice(&bytes).expect("Invalid authority key length"), + match AuthorityId::from_slice(&bytes) { + Ok(authority_id) => authority_id, + Err(_) => panic!("Invalid authority key length: {hex}"), + }, 1, ) }) .collect() } +fn testnet_authority_change_hash(hash: &str) -> H256 { + match H256::from_str(hash) { + Ok(hash) => hash, + Err(_) => panic!("Invalid testnet authority change hash: {hash}"), + } +} + +fn warp_proof_limit_reached(proofs_encoded_len: usize, proof_size: usize) -> bool { + match proofs_encoded_len.checked_add(proof_size) { + Some(total_size) => total_size >= MAX_WARP_SYNC_PROOF_SIZE_LIMIT, + None => true, + } +} + fn testnet_genesis_grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { authority_list_from_hex(&[ "dc832c3b7bdfc721e90e5ee9e532c06b62a0def3c79dab5324460d938db6600a", @@ -97,10 +125,9 @@ fn testnet_warp_fragment_overrides() -> Vec { TestnetWarpFragmentOverride { set_id: 0, block: ( - H256::from_str( + testnet_authority_change_hash( "0x819a5e54ffa2d267d469c6da44de5e8819b1aad1717a1389c959eab4349722ca", - ) - .expect("Invalid testnet authority change hash"), + ), 4_589_660u32, ), authorities: authorities.clone(), @@ -108,10 +135,9 @@ fn testnet_warp_fragment_overrides() -> Vec { TestnetWarpFragmentOverride { set_id: 1, block: ( - H256::from_str( + testnet_authority_change_hash( "0x2b001bfdec34d007ab2ac07f712e64d0cb1a6fb4b51f7d47bfb3c7d7336a689b", - ) - .expect("Invalid testnet authority change hash"), + ), 4_589_686u32, ), authorities: authorities.clone(), @@ -119,10 +145,9 @@ fn testnet_warp_fragment_overrides() -> Vec { TestnetWarpFragmentOverride { set_id: 3, block: ( - H256::from_str( + testnet_authority_change_hash( "0x4d643da5fd7cd2b9ceb795091643e7223819e2a01f942ac049c5b928f7e30dc4", - ) - .expect("Invalid testnet authority change hash"), + ), 5_534_451u32, ), authorities, @@ -203,9 +228,9 @@ impl TestnetWarpSyncProvider { )); } - let canon_hash = blockchain.hash(begin_number)?.expect( - "begin number is lower than finalized number; all blocks below finalized number must have been imported; qed.", - ); + let canon_hash = blockchain + .hash(begin_number)? + .ok_or(sc_consensus_grandpa::warp_proof::Error::MissingData)?; if canon_hash != begin { return Err(sc_consensus_grandpa::warp_proof::Error::InvalidRequest( @@ -259,12 +284,15 @@ impl TestnetWarpSyncProvider { }; let proof_size = proof.encoded_size(); - if proofs_encoded_len + proof_size >= MAX_WARP_SYNC_PROOF_SIZE - 50 { + if warp_proof_limit_reached(proofs_encoded_len, proof_size) { proof_limit_reached = true; break; } - proofs_encoded_len += proof_size; + proofs_encoded_len = match proofs_encoded_len.checked_add(proof_size) { + Some(total_size) => total_size, + None => return Err(sc_consensus_grandpa::warp_proof::Error::MissingData), + }; proofs.push(proof); } @@ -275,7 +303,7 @@ impl TestnetWarpSyncProvider { .filter(|justification| { let limit = proofs .last() - .map(|proof| proof.justification.target().0 + 1) + .map(|proof| proof.justification.target().0.saturating_add(1)) .unwrap_or(begin_number); justification.target().0 >= limit @@ -284,14 +312,14 @@ impl TestnetWarpSyncProvider { if let Some(latest_justification) = latest_justification { let header = blockchain .header(latest_justification.target().1)? - .expect("header hash corresponds to a justification in db; must exist in db as well; qed."); + .ok_or(sc_consensus_grandpa::warp_proof::Error::MissingData)?; let proof = sc_consensus_grandpa::warp_proof::WarpSyncFragment { header, justification: latest_justification, }; - if proofs_encoded_len + proof.encoded_size() >= MAX_WARP_SYNC_PROOF_SIZE - 50 { + if warp_proof_limit_reached(proofs_encoded_len, proof.encoded_size()) { false } else { proofs.push(proof); @@ -365,34 +393,6 @@ fn merge_testnet_warp_authority_changes( Ok(merged) } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn prefixes_canonical_testnet_warp_transitions_before_poisoned_history() { - let canonical_changes = testnet_warp_fragment_overrides() - .into_iter() - .map(|fork| (fork.set_id, fork.block.1)) - .collect::>(); - let poisoned_changes = - sc_consensus_grandpa::AuthoritySetChanges::from(vec![(0, 5_672_448u32)]); - - let merged = merge_testnet_warp_authority_changes(&canonical_changes, 0, &poisoned_changes) - .expect("canonical overrides should cover genesis start"); - - assert_eq!( - merged, - vec![ - (0, 4_589_660u32), - (1, 4_589_686u32), - (3, 5_534_451u32), - (0, 5_672_448u32), - ], - ); - } -} - /// The minimum period of blocks on which justifications will be /// imported and generated. const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512; @@ -1217,3 +1217,37 @@ fn copy_keys( Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn prefixes_canonical_testnet_warp_transitions_before_poisoned_history() { + let canonical_changes = testnet_warp_fragment_overrides() + .into_iter() + .map(|fork| (fork.set_id, fork.block.1)) + .collect::>(); + let poisoned_changes = + sc_consensus_grandpa::AuthoritySetChanges::from(vec![(0, 5_672_448u32)]); + + let merged = match merge_testnet_warp_authority_changes( + &canonical_changes, + 0, + &poisoned_changes, + ) { + Ok(merged) => merged, + Err(error) => panic!("canonical overrides should cover genesis start: {error}"), + }; + + assert_eq!( + merged, + vec![ + (0, 4_589_660u32), + (1, 4_589_686u32), + (3, 5_534_451u32), + (0, 5_672_448u32), + ], + ); + } +} From d8ac2938fb21c194c810602a0e9f8d9d6c55944c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 3 Apr 2026 00:21:54 +0200 Subject: [PATCH 4/5] Fix testnet protocol ID in generated chain specs --- chainspecs/plain_spec_testfinney.json | 2 +- node/src/chain_spec/testnet.rs | 2 +- node/src/service.rs | 13 +++----- node/tests/chain_spec.rs | 46 +++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/chainspecs/plain_spec_testfinney.json b/chainspecs/plain_spec_testfinney.json index 1390fe92f2..3b141e5f59 100644 --- a/chainspecs/plain_spec_testfinney.json +++ b/chainspecs/plain_spec_testfinney.json @@ -6,7 +6,7 @@ "/dns/bootnode.test.chain.opentensor.ai/tcp/30333/p2p/12D3KooWPM4mLcKJGtyVtkggqdG84zWrd7Rij6PGQDoijh1X86Vr" ], "telemetryEndpoints": null, - "protocolId": "bittensor", + "protocolId": "bittensor-testnet", "properties": { "ss58Format": 42, "tokenDecimals": 9, diff --git a/node/src/chain_spec/testnet.rs b/node/src/chain_spec/testnet.rs index a3b3d8b627..bddc84ac8a 100644 --- a/node/src/chain_spec/testnet.rs +++ b/node/src/chain_spec/testnet.rs @@ -55,7 +55,7 @@ pub fn finney_testnet_config() -> Result { .parse() .unwrap(), ]) - .with_protocol_id("bittensor") + .with_protocol_id("bittensor-testnet") .with_id("bittensor") .with_chain_type(ChainType::Development) .with_genesis_config_patch(testnet_genesis( diff --git a/node/src/service.rs b/node/src/service.rs index a580d906ea..de62d476e4 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -1231,14 +1231,11 @@ mod tests { let poisoned_changes = sc_consensus_grandpa::AuthoritySetChanges::from(vec![(0, 5_672_448u32)]); - let merged = match merge_testnet_warp_authority_changes( - &canonical_changes, - 0, - &poisoned_changes, - ) { - Ok(merged) => merged, - Err(error) => panic!("canonical overrides should cover genesis start: {error}"), - }; + let merged = + match merge_testnet_warp_authority_changes(&canonical_changes, 0, &poisoned_changes) { + Ok(merged) => merged, + Err(error) => panic!("canonical overrides should cover genesis start: {error}"), + }; assert_eq!( merged, diff --git a/node/tests/chain_spec.rs b/node/tests/chain_spec.rs index 42665c476b..fec9c51995 100644 --- a/node/tests/chain_spec.rs +++ b/node/tests/chain_spec.rs @@ -3,6 +3,7 @@ use sp_core::sr25519; // use sp_consensus_grandpa::AuthorityId as GrandpaId; use node_subtensor::chain_spec::*; +use serde_json::Value; #[test] fn test_get_from_seed() { @@ -52,3 +53,48 @@ fn test_authority_keys_from_seed_panics() { let bad_seed = ""; authority_keys_from_seed(bad_seed); } + +#[test] +fn test_finney_testnet_chain_spec_protocol_id() { + let output = std::process::Command::new(env!("CARGO_BIN_EXE_node-subtensor")) + .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/..")) + .args([ + "build-spec", + "--chain", + "test_finney", + "--disable-default-bootnode", + ]) + .output() + .expect("node-subtensor build-spec should run"); + + assert!( + output.status.success(), + "build-spec failed: {:?}", + output.status + ); + + let spec_json: Value = + serde_json::from_slice(&output.stdout).expect("build-spec should emit valid json"); + + assert_eq!( + spec_json.get("protocolId").and_then(Value::as_str), + Some("bittensor-testnet") + ); +} + +#[test] +fn test_checked_in_plain_testnet_spec_protocol_id() { + let spec_path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../chainspecs/plain_spec_testfinney.json" + ); + let spec_json: Value = serde_json::from_str( + &std::fs::read_to_string(spec_path).expect("plain testnet spec should exist"), + ) + .expect("plain testnet spec should be valid json"); + + assert_eq!( + spec_json.get("protocolId").and_then(Value::as_str), + Some("bittensor-testnet") + ); +} From 278e018d3076e55b272b3263bd39fe4c03ccc098 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 3 Apr 2026 09:27:01 +0200 Subject: [PATCH 5/5] Remove redundant testnet protocol ID chain spec tests --- node/tests/chain_spec.rs | 47 ---------------------------------------- 1 file changed, 47 deletions(-) diff --git a/node/tests/chain_spec.rs b/node/tests/chain_spec.rs index fec9c51995..e06c413995 100644 --- a/node/tests/chain_spec.rs +++ b/node/tests/chain_spec.rs @@ -3,8 +3,6 @@ use sp_core::sr25519; // use sp_consensus_grandpa::AuthorityId as GrandpaId; use node_subtensor::chain_spec::*; -use serde_json::Value; - #[test] fn test_get_from_seed() { let seed = "WoOt"; @@ -53,48 +51,3 @@ fn test_authority_keys_from_seed_panics() { let bad_seed = ""; authority_keys_from_seed(bad_seed); } - -#[test] -fn test_finney_testnet_chain_spec_protocol_id() { - let output = std::process::Command::new(env!("CARGO_BIN_EXE_node-subtensor")) - .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/..")) - .args([ - "build-spec", - "--chain", - "test_finney", - "--disable-default-bootnode", - ]) - .output() - .expect("node-subtensor build-spec should run"); - - assert!( - output.status.success(), - "build-spec failed: {:?}", - output.status - ); - - let spec_json: Value = - serde_json::from_slice(&output.stdout).expect("build-spec should emit valid json"); - - assert_eq!( - spec_json.get("protocolId").and_then(Value::as_str), - Some("bittensor-testnet") - ); -} - -#[test] -fn test_checked_in_plain_testnet_spec_protocol_id() { - let spec_path = concat!( - env!("CARGO_MANIFEST_DIR"), - "/../chainspecs/plain_spec_testfinney.json" - ); - let spec_json: Value = serde_json::from_str( - &std::fs::read_to_string(spec_path).expect("plain testnet spec should exist"), - ) - .expect("plain testnet spec should be valid json"); - - assert_eq!( - spec_json.get("protocolId").and_then(Value::as_str), - Some("bittensor-testnet") - ); -}