@@ -21,7 +21,6 @@ use platform_core::{
2121use platform_epoch:: { EpochConfig , EpochPhase , EpochTransition } ;
2222use platform_network:: {
2323 NetworkEvent , NetworkNode , NetworkProtection , NodeConfig , ProtectionConfig , SyncResponse ,
24- MIN_STAKE_RAO , MIN_STAKE_TAO ,
2524} ;
2625use platform_rpc:: { OrchestratorCommand , RpcConfig , RpcServer } ;
2726use platform_storage:: Storage ;
@@ -97,6 +96,11 @@ struct Args {
9796 #[ arg( long, default_value = "1000" ) ]
9897 stake : f64 ,
9998
99+ /// Minimum stake required to participate as validator (in TAO)
100+ /// Default: 1000 TAO. Set lower for testnets or new subnets
101+ #[ arg( long, env = "MIN_STAKE_TAO" , default_value = "1000" ) ]
102+ min_stake : f64 ,
103+
100104 // === Bittensor Options ===
101105 /// Bittensor network endpoint
102106 #[ arg(
@@ -326,9 +330,13 @@ async fn main() -> Result<()> {
326330 Arc :: new ( RwLock :: new ( state) )
327331 } ;
328332
333+ // Calculate minimum stake in RAO from CLI argument
334+ let min_stake_tao = args. min_stake ;
335+ let min_stake_rao = ( args. min_stake * 1_000_000_000.0 ) as u64 ;
336+
329337 // Initialize network protection (DDoS + stake validation)
330338 let protection_config = ProtectionConfig {
331- min_stake_rao : MIN_STAKE_RAO , // 1000 TAO minimum
339+ min_stake_rao, // Configurable minimum stake
332340 rate_limit : 100 , // 100 msg/sec per peer
333341 max_connections_per_ip : 5 , // 5 connections max per IP
334342 blacklist_duration_secs : 3600 , // 1 hour blacklist
@@ -340,18 +348,18 @@ async fn main() -> Result<()> {
340348 let protection = Arc :: new ( NetworkProtection :: new ( protection_config) ) ;
341349 info ! (
342350 "Network protection enabled: min_stake={} TAO, rate_limit={} msg/s" ,
343- MIN_STAKE_TAO , 100
351+ min_stake_tao , 100
344352 ) ;
345353
346354 // Add ourselves as a validator
347355 {
348356 let stake_raw = ( args. stake * 1_000_000_000.0 ) as u64 ;
349357
350358 // Validate our own stake meets minimum
351- if stake_raw < MIN_STAKE_RAO {
359+ if stake_raw < min_stake_rao {
352360 warn ! (
353361 "WARNING: Own stake ({} TAO) is below minimum ({} TAO). You may be rejected by other validators." ,
354- args. stake, MIN_STAKE_TAO
362+ args. stake, min_stake_tao
355363 ) ;
356364 }
357365
@@ -438,7 +446,7 @@ async fn main() -> Result<()> {
438446 addr : rpc_addr. parse ( ) ?,
439447 netuid : args. netuid ,
440448 name : format ! ( "MiniChain-{}" , args. netuid) ,
441- min_stake : MIN_STAKE_RAO ,
449+ min_stake : min_stake_rao ,
442450 cors_enabled : args. rpc_cors ,
443451 } ;
444452
@@ -805,11 +813,15 @@ async fn main() -> Result<()> {
805813 let hotkey_bytes: & [ u8 ; 32 ] = neuron. hotkey . as_ref ( ) ;
806814 let hotkey = Hotkey ( * hotkey_bytes) ;
807815
808- // Get stake (convert from u128 to u64, saturating)
809- let stake_rao = neuron. stake . min ( u64:: MAX as u128 ) as u64 ;
816+ // Get effective stake: alpha stake + root stake (TAO on root subnet)
817+ // This matches how Bittensor calculates validator weight
818+ let alpha_stake = neuron. stake ;
819+ let root_stake = neuron. root_stake ;
820+ let effective_stake = alpha_stake. saturating_add ( root_stake) ;
821+ let stake_rao = effective_stake. min ( u64:: MAX as u128 ) as u64 ;
810822
811823 // Skip if below minimum stake
812- if stake_rao < MIN_STAKE_RAO {
824+ if stake_rao < min_stake_rao {
813825 continue ;
814826 }
815827
@@ -832,7 +844,7 @@ async fn main() -> Result<()> {
832844 }
833845
834846 info ! ( "Metagraph sync complete: {} neurons, {} validators with sufficient stake (min {} TAO)" ,
835- metagraph. n, added, MIN_STAKE_TAO ) ;
847+ metagraph. n, added, min_stake_tao ) ;
836848 info ! ( "Validator identity verification ready - will accept messages from {} known validators" ,
837849 state. validators. len( ) ) ;
838850 sync_success = true ;
@@ -1779,15 +1791,15 @@ async fn main() -> Result<()> {
17791791 let has_sufficient_stake = {
17801792 let state = chain_state_clone. read( ) ;
17811793 if let Some ( validator) = state. get_validator( signed. signer( ) ) {
1782- validator. stake. 0 >= MIN_STAKE_RAO
1794+ validator. stake. 0 >= min_stake_rao
17831795 } else {
17841796 // Unknown validator - check against cached stake or reject
17851797 if let Some ( validation) = protection. check_cached_stake( & signer_hex) {
17861798 validation. is_valid( )
17871799 } else {
17881800 warn!(
17891801 "Unknown validator {}: not in state and no cached stake. Min required: {} TAO" ,
1790- & signer_hex[ ..16 ] , MIN_STAKE_TAO
1802+ & signer_hex[ ..16 ] , min_stake_tao
17911803 ) ;
17921804 false
17931805 }
@@ -1810,7 +1822,7 @@ async fn main() -> Result<()> {
18101822 } else {
18111823 warn!(
18121824 "Rejected message from {} - insufficient stake (min {} TAO required)" ,
1813- & signer_hex[ ..16 ] , MIN_STAKE_TAO
1825+ & signer_hex[ ..16 ] , min_stake_tao
18141826 ) ;
18151827 }
18161828 }
@@ -1972,6 +1984,7 @@ async fn main() -> Result<()> {
19721984 let endpoint = subtensor_endpoint. clone( ) ;
19731985 let chain_state_for_sync = chain_state. clone( ) ;
19741986 let protection_for_sync = protection. clone( ) ;
1987+ let min_stake_for_sync = min_stake_rao;
19751988
19761989 tokio:: spawn( async move {
19771990 match BittensorClient :: new( & endpoint) . await {
@@ -1985,9 +1998,13 @@ async fn main() -> Result<()> {
19851998 for neuron in metagraph. neurons. values( ) {
19861999 let hotkey_bytes: & [ u8 ; 32 ] = neuron. hotkey. as_ref( ) ;
19872000 let hotkey = Hotkey ( * hotkey_bytes) ;
1988- let stake_rao = neuron. stake. min( u64 :: MAX as u128 ) as u64 ;
2001+ // Get effective stake: alpha stake + root stake
2002+ let alpha_stake = neuron. stake;
2003+ let root_stake = neuron. root_stake;
2004+ let effective_stake = alpha_stake. saturating_add( root_stake) ;
2005+ let stake_rao = effective_stake. min( u64 :: MAX as u128 ) as u64 ;
19892006
1990- if stake_rao < MIN_STAKE_RAO {
2007+ if stake_rao < min_stake_for_sync {
19912008 continue ;
19922009 }
19932010
0 commit comments