From 0a490fa7ac83a8435724685e9a9810637636177b Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 00:17:43 +0200 Subject: [PATCH 1/9] - Added a possibility to configure max epochs per block. --- chain-extensions/src/mock.rs | 2 +- eco-tests/src/mock.rs | 2 +- pallets/admin-utils/src/lib.rs | 14 ++++++++++++++ pallets/admin-utils/src/tests/mock.rs | 2 +- pallets/subtensor/src/coinbase/run_coinbase.rs | 5 +++-- pallets/subtensor/src/lib.rs | 10 ++++++++++ pallets/subtensor/src/macros/config.rs | 7 ++++--- pallets/subtensor/src/macros/events.rs | 2 ++ pallets/subtensor/src/tests/coinbase.rs | 4 ++-- pallets/subtensor/src/tests/mock.rs | 2 +- pallets/subtensor/src/tests/mock_high_ed.rs | 2 +- pallets/subtensor/src/utils/misc.rs | 9 +++++++++ pallets/transaction-fee/src/tests/mock.rs | 2 +- precompiles/src/mock.rs | 2 +- runtime/src/lib.rs | 2 +- 15 files changed, 52 insertions(+), 15 deletions(-) diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index a910f7c517..3373131c69 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -440,7 +440,7 @@ impl pallet_subtensor::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/eco-tests/src/mock.rs b/eco-tests/src/mock.rs index e4fc547789..ee08387863 100644 --- a/eco-tests/src/mock.rs +++ b/eco-tests/src/mock.rs @@ -327,7 +327,7 @@ impl pallet_subtensor::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); type AlphaAssets = AlphaAssets; } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index ac9f239f3c..f5e5293ccc 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2279,6 +2279,20 @@ pub mod pallet { Ok(()) } + + /// Sets the per-block cap on subnet epochs (dynamic tempo throttle). + #[pallet::call_index(96)] + #[pallet::weight(::WeightInfo::sudo_set_tx_rate_limit())] + pub fn sudo_set_max_epochs_per_block( + origin: OriginFor, + max_epochs_per_block: u32, + ) -> DispatchResult { + ensure_root(origin)?; + ensure!(max_epochs_per_block >= 1, Error::::ValueNotInBounds); + pallet_subtensor::Pallet::::set_max_epochs_per_block(max_epochs_per_block); + + Ok(()) + } } } diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 2534c719f4..1ac98af43d 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -249,7 +249,7 @@ impl pallet_subtensor::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index d42f90ec98..53a91769e7 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -322,7 +322,7 @@ impl Pallet { /// Subnets whose epoch slot is due *this* block but is deferred by the per-block /// cap (`MaxEpochsPerBlock`). pub fn epochs_deferred_this_block(subnets: &[NetUid], current_block: u64) -> BTreeSet { - let cap = T::MaxEpochsPerBlock::get(); + let cap = Self::get_max_epochs_per_block(); let mut deferred: BTreeSet = BTreeSet::new(); let mut epochs_run_this_block: u32 = 0; @@ -353,6 +353,7 @@ impl Pallet { > = BTreeMap::new(); // Per-block cap on number of epochs that may run; the rest are deferred 1 block forward // by setting `PendingEpochAt`. + let max_epochs_per_block = Self::get_max_epochs_per_block(); let mut epochs_run_this_block: u32 = 0; for &netuid in subnets.iter() { @@ -364,7 +365,7 @@ impl Pallet { } // Per-block cap — defer if already at limit. - if epochs_run_this_block >= T::MaxEpochsPerBlock::get() { + if epochs_run_this_block >= max_epochs_per_block { let next_block = current_block.saturating_add(1); PendingEpochAt::::insert(netuid, next_block); Self::deposit_event(Event::EpochDeferred { diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 410e3bef16..d7569a2f74 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -923,6 +923,12 @@ pub mod pallet { // T::InitialHotkeyEmissionTempo::get() // } (DEPRECATED) + /// Default per-block epoch cap, seeded from the runtime-configured initial value. + #[pallet::type_value] + pub fn DefaultMaxEpochsPerBlock() -> u32 { + T::InitialMaxEpochsPerBlock::get() + } + /// Default value for rate limiting #[pallet::type_value] pub fn DefaultTxRateLimit() -> u64 { @@ -2130,6 +2136,10 @@ pub mod pallet { DefaultRAORecycledForRegistration, >; + /// --- ITEM ( max_epochs_per_block ) + #[pallet::storage] + pub type MaxEpochsPerBlock = StorageValue<_, u32, ValueQuery, DefaultMaxEpochsPerBlock>; + /// --- ITEM ( tx_rate_limit ) #[pallet::storage] pub type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index 553451ab12..d7300a98e4 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -282,9 +282,10 @@ mod config { /// Burn account ID #[pallet::constant] type BurnAccountId: Get; - /// Per-block cap on number of subnet epochs that may execute in a single - /// `block_step`; the rest are deferred 1 block forward via `PendingEpochAt`. + /// Initial default per-block cap on number of subnet epochs that may + /// execute in a single `block_step`; the rest are deferred 1 block forward via + /// `PendingEpochAt`. #[pallet::constant] - type MaxEpochsPerBlock: Get; + type InitialMaxEpochsPerBlock: Get; } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index b5bea2c186..943348e755 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -109,6 +109,8 @@ mod events { MaxBurnSet(NetUid, TaoBalance), /// setting min burn on a network. MinBurnSet(NetUid, TaoBalance), + /// setting the per-block epoch cap (dynamic tempo throttle). + MaxEpochsPerBlockSet(u32), /// setting the transaction rate limit. TxRateLimitSet(u64), /// setting the delegate take transaction rate limit. diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 02d1865905..4f3da7d6bb 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -4272,7 +4272,7 @@ fn test_get_subnet_terms_alpha_emissions_cap() { #[test] fn test_epochs_deferred_this_block_respects_cap() { new_test_ext(1).execute_with(|| { - let cap = ::MaxEpochsPerBlock::get() as usize; + let cap = SubtensorModule::get_max_epochs_per_block() as usize; let n = cap + 2; for i in 0..n { @@ -4311,7 +4311,7 @@ fn test_epochs_deferred_this_block_respects_cap() { #[test] fn test_reveal_crv3_defers_with_capped_epoch() { new_test_ext(1).execute_with(|| { - let cap = ::MaxEpochsPerBlock::get() as usize; + let cap = SubtensorModule::get_max_epochs_per_block() as usize; let n = cap + 2; let mec0 = subtensor_runtime_common::MechId::from(0); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 49ec0c1638..b36d1b7f86 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -341,7 +341,7 @@ impl crate::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/pallets/subtensor/src/tests/mock_high_ed.rs b/pallets/subtensor/src/tests/mock_high_ed.rs index cb381a3f81..1cf29ad746 100644 --- a/pallets/subtensor/src/tests/mock_high_ed.rs +++ b/pallets/subtensor/src/tests/mock_high_ed.rs @@ -301,7 +301,7 @@ impl crate::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index a2b0fa2627..00cb179797 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -377,6 +377,15 @@ impl Pallet { // ========= Sudo ========= // ======================== + // Per-block epoch cap (dynamic tempo throttle) + pub fn get_max_epochs_per_block() -> u32 { + MaxEpochsPerBlock::::get() + } + pub fn set_max_epochs_per_block(max_epochs_per_block: u32) { + MaxEpochsPerBlock::::put(max_epochs_per_block); + Self::deposit_event(Event::MaxEpochsPerBlockSet(max_epochs_per_block)); + } + // Configure tx rate limiting pub fn get_tx_rate_limit() -> u64 { TxRateLimit::::get() diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index 703ed27ba2..bee17be801 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -319,7 +319,7 @@ impl pallet_subtensor::Config for Test { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/precompiles/src/mock.rs b/precompiles/src/mock.rs index cb7275e47c..b77d82db32 100644 --- a/precompiles/src/mock.rs +++ b/precompiles/src/mock.rs @@ -483,7 +483,7 @@ impl pallet_subtensor::Config for Runtime { type AuthorshipProvider = MockAuthorshipProvider; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = MaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = MaxEpochsPerBlock; type WeightInfo = (); } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index f18065f75c..1e42485fa5 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1116,7 +1116,7 @@ impl pallet_subtensor::Config for Runtime { type AuthorshipProvider = BlockAuthorFromAura; type SubtensorPalletId = SubtensorPalletId; type BurnAccountId = BurnAccountId; - type MaxEpochsPerBlock = SubtensorMaxEpochsPerBlock; + type InitialMaxEpochsPerBlock = SubtensorMaxEpochsPerBlock; type WeightInfo = pallet_subtensor::weights::SubstrateWeight; } From 06362bad49776d40bd45114d678255cfda5b2137 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 00:22:22 +0200 Subject: [PATCH 2/9] spec_version bump --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 1e42485fa5..9e8427539a 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -234,7 +234,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 420, + spec_version: 421, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 35b3aabdbef61725dc18282bdbfea1735104ae58 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 09:35:25 +0200 Subject: [PATCH 3/9] - added weights - updated type - added more tests --- chain-extensions/src/mock.rs | 2 +- eco-tests/src/mock.rs | 2 +- pallets/admin-utils/src/benchmarking.rs | 11 +++ pallets/admin-utils/src/lib.rs | 4 +- pallets/admin-utils/src/tests/mock.rs | 2 +- pallets/admin-utils/src/tests/mod.rs | 73 +++++++++++++++++++ pallets/admin-utils/src/weights.rs | 21 ++++++ .../subtensor/src/coinbase/run_coinbase.rs | 4 +- pallets/subtensor/src/lib.rs | 4 +- pallets/subtensor/src/macros/config.rs | 2 +- pallets/subtensor/src/macros/events.rs | 2 +- pallets/subtensor/src/tests/mock.rs | 2 +- pallets/subtensor/src/tests/mock_high_ed.rs | 2 +- pallets/subtensor/src/utils/misc.rs | 4 +- pallets/transaction-fee/src/tests/mock.rs | 2 +- precompiles/src/mock.rs | 2 +- runtime/src/lib.rs | 2 +- 17 files changed, 123 insertions(+), 18 deletions(-) diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index 3373131c69..db25a9df68 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -356,7 +356,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 10; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl pallet_subtensor::Config for Test { diff --git a/eco-tests/src/mock.rs b/eco-tests/src/mock.rs index ee08387863..d605f47a65 100644 --- a/eco-tests/src/mock.rs +++ b/eco-tests/src/mock.rs @@ -244,7 +244,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 10; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl pallet_subtensor::Config for Test { diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 0f4928237c..d1a373d791 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -689,5 +689,16 @@ mod benchmarks { ); /* sudo_set_min_non_immune_uids() */ } + #[benchmark] + fn sudo_set_max_epochs_per_block() { + #[extrinsic_call] + _(RawOrigin::Root, 8u8); + + assert_eq!( + pallet_subtensor::Pallet::::get_max_epochs_per_block(), + 8u8 + ); + } + impl_benchmark_test_suite!(AdminUtils, mock::new_test_ext(), mock::Test); } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index f5e5293ccc..0e63a1f05a 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2282,10 +2282,10 @@ pub mod pallet { /// Sets the per-block cap on subnet epochs (dynamic tempo throttle). #[pallet::call_index(96)] - #[pallet::weight(::WeightInfo::sudo_set_tx_rate_limit())] + #[pallet::weight(::WeightInfo::sudo_set_max_epochs_per_block())] pub fn sudo_set_max_epochs_per_block( origin: OriginFor, - max_epochs_per_block: u32, + max_epochs_per_block: u8, ) -> DispatchResult { ensure_root(origin)?; ensure!(max_epochs_per_block >= 1, Error::::ValueNotInBounds); diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 1ac98af43d..e3b658a0a8 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -165,7 +165,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 0; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl pallet_subtensor::Config for Test { diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index de49e7651d..735e784ad8 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1498,6 +1498,79 @@ fn test_sudo_set_coldkey_swap_reannouncement_delay() { }); } +#[test] +fn test_sudo_set_max_epochs_per_block() { + new_test_ext().execute_with(|| { + let root = RuntimeOrigin::root(); + let non_root = RuntimeOrigin::signed(U256::from(1)); + let init_value = SubtensorModule::get_max_epochs_per_block(); + let to_be_set: u8 = init_value.saturating_add(3); + + // Non-root is rejected and leaves the value untouched. + assert_noop!( + AdminUtils::sudo_set_max_epochs_per_block(non_root, to_be_set), + DispatchError::BadOrigin + ); + assert_eq!(SubtensorModule::get_max_epochs_per_block(), init_value); + + // Zero is rejected by the `>= 1` guard (a zero cap would halt all subnet epochs). + assert_noop!( + AdminUtils::sudo_set_max_epochs_per_block(root.clone(), 0u8), + Error::::ValueNotInBounds + ); + assert_eq!(SubtensorModule::get_max_epochs_per_block(), init_value); + + // Root succeeds: storage is updated and the event is emitted. + assert_ok!(AdminUtils::sudo_set_max_epochs_per_block(root, to_be_set)); + assert_eq!(SubtensorModule::get_max_epochs_per_block(), to_be_set); + System::assert_last_event(Event::MaxEpochsPerBlockSet(to_be_set).into()); + }); +} + +#[test] +fn test_sudo_set_max_epochs_per_block_changes_deferrals() { + new_test_ext().execute_with(|| { + let root = RuntimeOrigin::root(); + + // Create several subnets and force each to be "due this block". + let created: u16 = 4; + for i in 0..created { + let netuid = NetUid::from(i + 1); + add_network(netuid, 100 /*tempo*/); + pallet_subtensor::PendingEpochAt::::insert(netuid, 1); + } + + let block = SubtensorModule::get_current_block_as_u64(); + let subnets: Vec = SubtensorModule::get_all_subnet_netuids() + .into_iter() + .filter(|x| *x != NetUid::ROOT) + .collect(); + let due = subnets + .iter() + .filter(|n| SubtensorModule::should_run_epoch(**n, block)) + .count(); + assert!(due >= created as usize); + + // Tight cap (1): every due subnet beyond the first is deferred. + assert_ok!(AdminUtils::sudo_set_max_epochs_per_block(root.clone(), 1u8)); + let deferred_tight = SubtensorModule::epochs_deferred_this_block(&subnets, block).len(); + assert_eq!(deferred_tight, due.saturating_sub(1)); + + // Raising the cap above the due count clears all deferrals — proving the + // admin-set cap directly drives which epochs are deferred. + assert_ok!(AdminUtils::sudo_set_max_epochs_per_block( + root, + (due as u8).saturating_add(2) + )); + let deferred_loose = SubtensorModule::epochs_deferred_this_block(&subnets, block).len(); + assert_eq!(deferred_loose, 0); + assert!( + deferred_loose < deferred_tight, + "raising MaxEpochsPerBlock must defer fewer epochs" + ); + }); +} + #[test] fn test_sudo_set_dissolve_network_schedule_duration() { new_test_ext().execute_with(|| { diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index 8320052fe1..c248b2eb57 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -66,6 +66,7 @@ pub trait WeightInfo { fn sudo_set_commit_reveal_weights_enabled() -> Weight; fn sudo_set_commit_reveal_version() -> Weight; fn sudo_set_tx_rate_limit() -> Weight; + fn sudo_set_max_epochs_per_block() -> Weight; fn sudo_set_total_issuance() -> Weight; fn sudo_set_rao_recycled() -> Weight; fn sudo_set_stake_threshold() -> Weight; @@ -575,6 +576,16 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(5_500_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `SubtensorModule::MaxEpochsPerBlock` (r:0 w:1) + /// Proof: `SubtensorModule::MaxEpochsPerBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn sudo_set_max_epochs_per_block() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } fn sudo_set_total_issuance() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -1407,6 +1418,16 @@ impl WeightInfo for () { Weight::from_parts(5_500_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `SubtensorModule::MaxEpochsPerBlock` (r:0 w:1) + /// Proof: `SubtensorModule::MaxEpochsPerBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn sudo_set_max_epochs_per_block() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } fn sudo_set_total_issuance() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 53a91769e7..ccdde46320 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -322,7 +322,7 @@ impl Pallet { /// Subnets whose epoch slot is due *this* block but is deferred by the per-block /// cap (`MaxEpochsPerBlock`). pub fn epochs_deferred_this_block(subnets: &[NetUid], current_block: u64) -> BTreeSet { - let cap = Self::get_max_epochs_per_block(); + let cap = Self::get_max_epochs_per_block() as u32; let mut deferred: BTreeSet = BTreeSet::new(); let mut epochs_run_this_block: u32 = 0; @@ -353,7 +353,7 @@ impl Pallet { > = BTreeMap::new(); // Per-block cap on number of epochs that may run; the rest are deferred 1 block forward // by setting `PendingEpochAt`. - let max_epochs_per_block = Self::get_max_epochs_per_block(); + let max_epochs_per_block = Self::get_max_epochs_per_block() as u32; let mut epochs_run_this_block: u32 = 0; for &netuid in subnets.iter() { diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index d7569a2f74..bd0b4ab974 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -925,7 +925,7 @@ pub mod pallet { /// Default per-block epoch cap, seeded from the runtime-configured initial value. #[pallet::type_value] - pub fn DefaultMaxEpochsPerBlock() -> u32 { + pub fn DefaultMaxEpochsPerBlock() -> u8 { T::InitialMaxEpochsPerBlock::get() } @@ -2138,7 +2138,7 @@ pub mod pallet { /// --- ITEM ( max_epochs_per_block ) #[pallet::storage] - pub type MaxEpochsPerBlock = StorageValue<_, u32, ValueQuery, DefaultMaxEpochsPerBlock>; + pub type MaxEpochsPerBlock = StorageValue<_, u8, ValueQuery, DefaultMaxEpochsPerBlock>; /// --- ITEM ( tx_rate_limit ) #[pallet::storage] diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index d7300a98e4..ad372d1e0e 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -286,6 +286,6 @@ mod config { /// execute in a single `block_step`; the rest are deferred 1 block forward via /// `PendingEpochAt`. #[pallet::constant] - type InitialMaxEpochsPerBlock: Get; + type InitialMaxEpochsPerBlock: Get; } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 943348e755..adcd97e0cf 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -110,7 +110,7 @@ mod events { /// setting min burn on a network. MinBurnSet(NetUid, TaoBalance), /// setting the per-block epoch cap (dynamic tempo throttle). - MaxEpochsPerBlockSet(u32), + MaxEpochsPerBlockSet(u8), /// setting the transaction rate limit. TxRateLimitSet(u64), /// setting the delegate take transaction rate limit. diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index b36d1b7f86..8a813fac8d 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -257,7 +257,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 10; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl crate::Config for Test { diff --git a/pallets/subtensor/src/tests/mock_high_ed.rs b/pallets/subtensor/src/tests/mock_high_ed.rs index 1cf29ad746..ac20b4131a 100644 --- a/pallets/subtensor/src/tests/mock_high_ed.rs +++ b/pallets/subtensor/src/tests/mock_high_ed.rs @@ -217,7 +217,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 10; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl crate::Config for Test { diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index 00cb179797..7e62e4c7ec 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -378,10 +378,10 @@ impl Pallet { // ======================== // Per-block epoch cap (dynamic tempo throttle) - pub fn get_max_epochs_per_block() -> u32 { + pub fn get_max_epochs_per_block() -> u8 { MaxEpochsPerBlock::::get() } - pub fn set_max_epochs_per_block(max_epochs_per_block: u32) { + pub fn set_max_epochs_per_block(max_epochs_per_block: u8) { MaxEpochsPerBlock::::put(max_epochs_per_block); Self::deposit_event(Event::MaxEpochsPerBlockSet(max_epochs_per_block)); } diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index bee17be801..7d8508c5c0 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -235,7 +235,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 0; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } impl pallet_subtensor::Config for Test { diff --git a/precompiles/src/mock.rs b/precompiles/src/mock.rs index b77d82db32..ed8e407f88 100644 --- a/precompiles/src/mock.rs +++ b/precompiles/src/mock.rs @@ -157,7 +157,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = 0; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const MaxEpochsPerBlock: u32 = 32; + pub const MaxEpochsPerBlock: u8 = 32; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9e8427539a..542e896369 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1032,7 +1032,7 @@ parameter_types! { pub const EvmKeyAssociateRateLimit: u64 = EVM_KEY_ASSOCIATE_RATELIMIT; pub const SubtensorPalletId: PalletId = PalletId(*b"subtensr"); pub const BurnAccountId: PalletId = PalletId(*b"burntnsr"); - pub const SubtensorMaxEpochsPerBlock: u32 = prod_or_fast!(2, 32); + pub const SubtensorMaxEpochsPerBlock: u8 = prod_or_fast!(2, 32); } impl pallet_subtensor::Config for Runtime { From 7a6899b67c918929dc5df38423c97af2a6257641 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 11:48:05 +0200 Subject: [PATCH 4/9] - CI fix for dev tests --- ts-tests/moonwall.config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ts-tests/moonwall.config.json b/ts-tests/moonwall.config.json index 1ef1793749..63319b2a37 100644 --- a/ts-tests/moonwall.config.json +++ b/ts-tests/moonwall.config.json @@ -29,7 +29,8 @@ "--no-telemetry", "--reserved-only", "--tmp", - "--sealing=manual" + "--sealing=manual", + "--pool-type=single-state" ], "disableDefaultEthProviders": true, "newRpcBehaviour": true, From 49e6ca4f6c20e053b1f47422c97790b111a6569a Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 12:25:54 +0200 Subject: [PATCH 5/9] - test ipv6 resolve error for e2e tests --- .github/workflows/typescript-e2e.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/typescript-e2e.yml b/.github/workflows/typescript-e2e.yml index b73c50c86e..c73f4c3225 100644 --- a/.github/workflows/typescript-e2e.yml +++ b/.github/workflows/typescript-e2e.yml @@ -138,6 +138,18 @@ jobs: run: pnpm install --frozen-lockfile - name: Run tests - run: | + env: + NODE_OPTIONS: --dns-result-order=ipv4first + run: | cd ts-tests pnpm moonwall test ${{ matrix.test }} + + - name: Upload node logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: node-logs-${{ matrix.test }} + path: | + ts-tests/tmp/node_logs/ + ts-tests/tmp/*.log + if-no-files-found: warn From ba15c057df8a7c1f5cc13a40ff482a37811d1737 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 13:08:18 +0200 Subject: [PATCH 6/9] - diagnose the rpc connection (dev only) --- .github/workflows/typescript-e2e.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/typescript-e2e.yml b/.github/workflows/typescript-e2e.yml index c73f4c3225..aad6cf40a0 100644 --- a/.github/workflows/typescript-e2e.yml +++ b/.github/workflows/typescript-e2e.yml @@ -123,6 +123,26 @@ jobs: - name: Make binary executable run: chmod +x target/release/node-subtensor + - name: Diagnose RPC reachability (dev only) + if: matrix.test == 'dev' + run: | + set +e + ( ./target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ + --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ + --pool-type=single-state --rpc-port 9944 > /tmp/n.log 2>&1 & ) + sleep 10 + REQ='{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}' + echo "== what is listening on 9944 =="; ss -ltnp 2>/dev/null | grep -E '9944|State' || true + echo; echo "== curl 127.0.0.1:9944 ==" + curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" http://127.0.0.1:9944 || echo ">>> FAIL 127.0.0.1" + echo; echo "== curl [::1]:9944 ==" + curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" "http://[::1]:9944" || echo ">>> FAIL ::1" + echo; echo "== curl localhost:9944 ==" + curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" http://localhost:9944 || echo ">>> FAIL localhost" + echo; echo "== node log tail =="; tail -8 /tmp/n.log + pkill -f node-subtensor 2>/dev/null || true + true + - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -138,8 +158,6 @@ jobs: run: pnpm install --frozen-lockfile - name: Run tests - env: - NODE_OPTIONS: --dns-result-order=ipv4first run: | cd ts-tests pnpm moonwall test ${{ matrix.test }} From 027bec110cf939d103fe8bfcd1f4d0984a0be751 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 13:40:04 +0200 Subject: [PATCH 7/9] - diagnose the rpc connection (dev only) --- .github/workflows/typescript-e2e.yml | 70 ++++++++++++++++------------ 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/.github/workflows/typescript-e2e.yml b/.github/workflows/typescript-e2e.yml index aad6cf40a0..f34358e44b 100644 --- a/.github/workflows/typescript-e2e.yml +++ b/.github/workflows/typescript-e2e.yml @@ -123,26 +123,6 @@ jobs: - name: Make binary executable run: chmod +x target/release/node-subtensor - - name: Diagnose RPC reachability (dev only) - if: matrix.test == 'dev' - run: | - set +e - ( ./target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ - --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ - --pool-type=single-state --rpc-port 9944 > /tmp/n.log 2>&1 & ) - sleep 10 - REQ='{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}' - echo "== what is listening on 9944 =="; ss -ltnp 2>/dev/null | grep -E '9944|State' || true - echo; echo "== curl 127.0.0.1:9944 ==" - curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" http://127.0.0.1:9944 || echo ">>> FAIL 127.0.0.1" - echo; echo "== curl [::1]:9944 ==" - curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" "http://[::1]:9944" || echo ">>> FAIL ::1" - echo; echo "== curl localhost:9944 ==" - curl -sS -m 5 -H 'Content-Type: application/json' -d "$REQ" http://localhost:9944 || echo ">>> FAIL localhost" - echo; echo "== node log tail =="; tail -8 /tmp/n.log - pkill -f node-subtensor 2>/dev/null || true - true - - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -157,17 +137,47 @@ jobs: working-directory: ts-tests run: pnpm install --frozen-lockfile + - name: Diagnose WS vs HTTP (dev only) + if: matrix.test == 'dev' + working-directory: ts-tests + run: | + set +e + cat > papi.mjs <<'PEOF' + const { ApiPromise, WsProvider } = await import('@polkadot/api'); + const port = process.env.PROBE_PORT || '9944'; + async function probe(url){ + return await new Promise((resolve)=>{ + const t=setTimeout(()=>resolve(url+' => TIMEOUT 20s (never ready)'),20000); + const provider=new WsProvider(url); + provider.on('connected',()=>console.log(url,'=> WS connected')); + provider.on('error',e=>console.log(url,'=> provider error:',(e&&e.message)||String(e))); + ApiPromise.create({provider}) + .then(async(api)=>{const c=(await api.rpc.system.chain()).toString();await api.disconnect();clearTimeout(t);resolve(url+' => READY chain='+c);}) + .catch(e=>{clearTimeout(t);resolve(url+' => FAIL '+((e&&e.message)||e));}); + }); + } + for (const h of ['127.0.0.1','localhost']) console.log(await probe('ws://'+h+':'+port)); + process.exit(0); + PEOF + for PROBE_PORT in 9944 10144; do + echo "######## PORT $PROBE_PORT (9944=control, 10144=moonwall dynamic range) ########" + ( ../target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ + --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ + --pool-type=single-state --rpc-port $PROBE_PORT > /tmp/n_$PROBE_PORT.log 2>&1 & ) + sleep 8 + echo "-- ss listening on $PROBE_PORT --"; ss -ltnp 2>/dev/null | grep ":$PROBE_PORT" || echo "(nothing on $PROBE_PORT)" + echo "-- HTTP curl 127.0.0.1:$PROBE_PORT --" + curl -sS -m 5 -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}' http://127.0.0.1:$PROBE_PORT || echo ">>> HTTP FAIL" + echo; echo "-- polkadot.js WS probe (what moonwall uses) --"; PROBE_PORT=$PROBE_PORT node papi.mjs + echo "-- node log tail --"; tail -4 /tmp/n_$PROBE_PORT.log + pkill -f "rpc-port $PROBE_PORT" 2>/dev/null || true + sleep 2 + done + true + - name: Run tests + env: + DEBUG: api-ws run: | cd ts-tests pnpm moonwall test ${{ matrix.test }} - - - name: Upload node logs - if: always() - uses: actions/upload-artifact@v4 - with: - name: node-logs-${{ matrix.test }} - path: | - ts-tests/tmp/node_logs/ - ts-tests/tmp/*.log - if-no-files-found: warn From 4e400452cd4ba4c6fb7a72e09fc11474cfd9d190 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 14:34:58 +0200 Subject: [PATCH 8/9] - diagnose the rpc connection (dev only) --- .github/workflows/typescript-e2e.yml | 60 +++++++++++++++------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/.github/workflows/typescript-e2e.yml b/.github/workflows/typescript-e2e.yml index f34358e44b..e16bf1b2a5 100644 --- a/.github/workflows/typescript-e2e.yml +++ b/.github/workflows/typescript-e2e.yml @@ -142,37 +142,43 @@ jobs: working-directory: ts-tests run: | set +e - cat > papi.mjs <<'PEOF' - const { ApiPromise, WsProvider } = await import('@polkadot/api'); - const port = process.env.PROBE_PORT || '9944'; - async function probe(url){ - return await new Promise((resolve)=>{ - const t=setTimeout(()=>resolve(url+' => TIMEOUT 20s (never ready)'),20000); - const provider=new WsProvider(url); - provider.on('connected',()=>console.log(url,'=> WS connected')); - provider.on('error',e=>console.log(url,'=> provider error:',(e&&e.message)||String(e))); - ApiPromise.create({provider}) - .then(async(api)=>{const c=(await api.rpc.system.chain()).toString();await api.disconnect();clearTimeout(t);resolve(url+' => READY chain='+c);}) - .catch(e=>{clearTimeout(t);resolve(url+' => FAIL '+((e&&e.message)||e));}); + MWDIR="$PWD/$(find node_modules/.pnpm -maxdepth 1 -type d -name '@moonwall+cli*' | head -1)/node_modules/@moonwall/cli" + echo "moonwall dir: $MWDIR" + cat > probe.mjs <<'PEOF' + import { createRequire } from 'module'; + const req = createRequire(process.env.MWDIR + '/'); + const WebSocket = req('ws'); + const port = process.env.P || '10144'; + console.log('moonwall ws version:', req('ws/package.json').version); + function readiness(host){ + return new Promise((resolve)=>{ + const ws = new WebSocket('ws://'+host+':'+port); + const hard=setTimeout(()=>{try{ws.close()}catch(e){};resolve('[readiness] '+host+' => HANG (no open/error 10s)');},10000); + ws.on('open',()=>{ ws.send(JSON.stringify({jsonrpc:'2.0',id:1,method:'system_chain',params:[]})); + ws.on('message',d=>{try{const r=JSON.parse(d.toString());if(r.jsonrpc==='2.0'&&!r.error){clearTimeout(hard);ws.close();resolve('[readiness] '+host+' => READY ('+r.result+')');}}catch(e){}}); }); + ws.on('error',e=>{clearTimeout(hard);resolve('[readiness] '+host+' => ERROR '+e.message);}); }); } - for (const h of ['127.0.0.1','localhost']) console.log(await probe('ws://'+h+':'+port)); + async function papi(host){ + try{ const { ApiPromise, WsProvider } = await import('@polkadot/api'); + const api=await ApiPromise.create({provider:new WsProvider('ws://'+host+':'+port)}); + const c=(await api.rpc.system.chain()).toString(); await api.disconnect(); + return '[polkadot.js] '+host+' => READY ('+c+')'; + }catch(e){ return '[polkadot.js] '+host+' => FAIL '+((e&&e.message)||e); } + } + for (const h of ['localhost','127.0.0.1']) console.log(await readiness(h)); + for (const h of ['localhost','127.0.0.1']) console.log(await papi(h)); process.exit(0); PEOF - for PROBE_PORT in 9944 10144; do - echo "######## PORT $PROBE_PORT (9944=control, 10144=moonwall dynamic range) ########" - ( ../target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ - --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ - --pool-type=single-state --rpc-port $PROBE_PORT > /tmp/n_$PROBE_PORT.log 2>&1 & ) - sleep 8 - echo "-- ss listening on $PROBE_PORT --"; ss -ltnp 2>/dev/null | grep ":$PROBE_PORT" || echo "(nothing on $PROBE_PORT)" - echo "-- HTTP curl 127.0.0.1:$PROBE_PORT --" - curl -sS -m 5 -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}' http://127.0.0.1:$PROBE_PORT || echo ">>> HTTP FAIL" - echo; echo "-- polkadot.js WS probe (what moonwall uses) --"; PROBE_PORT=$PROBE_PORT node papi.mjs - echo "-- node log tail --"; tail -4 /tmp/n_$PROBE_PORT.log - pkill -f "rpc-port $PROBE_PORT" 2>/dev/null || true - sleep 2 - done + ( ../target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ + --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ + --pool-type=single-state --rpc-port 10144 > /tmp/n.log 2>&1 & ) + sleep 8 + echo "== ss listening on 10144 =="; ss -ltnp 2>/dev/null | grep ':10144' || echo "(nothing)" + echo "== moonwall readiness-gate replica (ws 8.19.0) + polkadot.js control ==" + MWDIR="$MWDIR" P=10144 node probe.mjs 2>&1 | grep -avE "REGISTRY:|API/INIT:" + echo "== node log tail =="; tail -4 /tmp/n.log + pkill -f "rpc-port 10144" 2>/dev/null || true true - name: Run tests From 035e33a9d932eb25b1d15e1137214d90120a85da Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 19 Jun 2026 14:49:14 +0200 Subject: [PATCH 9/9] - revert changes back for dev ts tests --- .github/workflows/typescript-e2e.yml | 48 +--------------------------- ts-tests/moonwall.config.json | 3 +- 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/.github/workflows/typescript-e2e.yml b/.github/workflows/typescript-e2e.yml index e16bf1b2a5..b73c50c86e 100644 --- a/.github/workflows/typescript-e2e.yml +++ b/.github/workflows/typescript-e2e.yml @@ -137,53 +137,7 @@ jobs: working-directory: ts-tests run: pnpm install --frozen-lockfile - - name: Diagnose WS vs HTTP (dev only) - if: matrix.test == 'dev' - working-directory: ts-tests - run: | - set +e - MWDIR="$PWD/$(find node_modules/.pnpm -maxdepth 1 -type d -name '@moonwall+cli*' | head -1)/node_modules/@moonwall/cli" - echo "moonwall dir: $MWDIR" - cat > probe.mjs <<'PEOF' - import { createRequire } from 'module'; - const req = createRequire(process.env.MWDIR + '/'); - const WebSocket = req('ws'); - const port = process.env.P || '10144'; - console.log('moonwall ws version:', req('ws/package.json').version); - function readiness(host){ - return new Promise((resolve)=>{ - const ws = new WebSocket('ws://'+host+':'+port); - const hard=setTimeout(()=>{try{ws.close()}catch(e){};resolve('[readiness] '+host+' => HANG (no open/error 10s)');},10000); - ws.on('open',()=>{ ws.send(JSON.stringify({jsonrpc:'2.0',id:1,method:'system_chain',params:[]})); - ws.on('message',d=>{try{const r=JSON.parse(d.toString());if(r.jsonrpc==='2.0'&&!r.error){clearTimeout(hard);ws.close();resolve('[readiness] '+host+' => READY ('+r.result+')');}}catch(e){}}); }); - ws.on('error',e=>{clearTimeout(hard);resolve('[readiness] '+host+' => ERROR '+e.message);}); - }); - } - async function papi(host){ - try{ const { ApiPromise, WsProvider } = await import('@polkadot/api'); - const api=await ApiPromise.create({provider:new WsProvider('ws://'+host+':'+port)}); - const c=(await api.rpc.system.chain()).toString(); await api.disconnect(); - return '[polkadot.js] '+host+' => READY ('+c+')'; - }catch(e){ return '[polkadot.js] '+host+' => FAIL '+((e&&e.message)||e); } - } - for (const h of ['localhost','127.0.0.1']) console.log(await readiness(h)); - for (const h of ['localhost','127.0.0.1']) console.log(await papi(h)); - process.exit(0); - PEOF - ( ../target/release/node-subtensor --one --dev --force-authoring --rpc-cors=all \ - --no-prometheus --no-telemetry --reserved-only --tmp --sealing=manual \ - --pool-type=single-state --rpc-port 10144 > /tmp/n.log 2>&1 & ) - sleep 8 - echo "== ss listening on 10144 =="; ss -ltnp 2>/dev/null | grep ':10144' || echo "(nothing)" - echo "== moonwall readiness-gate replica (ws 8.19.0) + polkadot.js control ==" - MWDIR="$MWDIR" P=10144 node probe.mjs 2>&1 | grep -avE "REGISTRY:|API/INIT:" - echo "== node log tail =="; tail -4 /tmp/n.log - pkill -f "rpc-port 10144" 2>/dev/null || true - true - - name: Run tests - env: - DEBUG: api-ws - run: | + run: | cd ts-tests pnpm moonwall test ${{ matrix.test }} diff --git a/ts-tests/moonwall.config.json b/ts-tests/moonwall.config.json index 63319b2a37..1ef1793749 100644 --- a/ts-tests/moonwall.config.json +++ b/ts-tests/moonwall.config.json @@ -29,8 +29,7 @@ "--no-telemetry", "--reserved-only", "--tmp", - "--sealing=manual", - "--pool-type=single-state" + "--sealing=manual" ], "disableDefaultEthProviders": true, "newRpcBehaviour": true,