|
1 | 1 | #![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)]
|
2 | 2 | use crate::mock::*;
|
3 | 3 | mod mock;
|
4 |
| -// use frame_support::{assert_err, assert_ok}; |
| 4 | +use frame_support::assert_ok; |
| 5 | +use pallet_subtensor::LastAddStakeIncrease; |
5 | 6 | use sp_core::U256;
|
| 7 | +use substrate_fixed::types::I64F64; |
6 | 8 |
|
7 | 9 | // Test the ability to hash all sorts of hotkeys.
|
8 | 10 | #[test]
|
@@ -154,3 +156,317 @@ fn test_set_and_get_hotkey_emission_tempo() {
|
154 | 156 | assert_eq!(updated_tempo, new_tempo);
|
155 | 157 | });
|
156 | 158 | }
|
| 159 | + |
| 160 | +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --test coinbase test_coinbase_nominator_drainage_overflow -- --nocapture |
| 161 | +#[test] |
| 162 | +fn test_coinbase_nominator_drainage_overflow() { |
| 163 | + new_test_ext(1).execute_with(|| { |
| 164 | + // 1. Set up the network and accounts |
| 165 | + let netuid: u16 = 1; |
| 166 | + let hotkey = U256::from(0); |
| 167 | + let coldkey = U256::from(3); |
| 168 | + let nominator1 = U256::from(1); |
| 169 | + let nominator2 = U256::from(2); |
| 170 | + |
| 171 | + log::debug!("Setting up network with netuid: {}", netuid); |
| 172 | + log::debug!("Hotkey: {:?}, Coldkey: {:?}", hotkey, coldkey); |
| 173 | + log::debug!("Nominators: {:?}, {:?}", nominator1, nominator2); |
| 174 | + |
| 175 | + // 2. Create network and register neuron |
| 176 | + add_network(netuid, 1, 0); |
| 177 | + register_ok_neuron(netuid, hotkey, coldkey, 100000); |
| 178 | + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); |
| 179 | + |
| 180 | + log::debug!("Network created and neuron registered"); |
| 181 | + |
| 182 | + // 3. Set up balances and stakes |
| 183 | + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1000); |
| 184 | + SubtensorModule::add_balance_to_coldkey_account(&nominator1, 1500); |
| 185 | + SubtensorModule::add_balance_to_coldkey_account(&nominator2, 1500); |
| 186 | + |
| 187 | + log::debug!("Balances added to accounts"); |
| 188 | + |
| 189 | + // 4. Make the hotkey a delegate |
| 190 | + let vali_take = (u16::MAX as u64 / 10); |
| 191 | + assert_ok!(SubtensorModule::do_become_delegate( |
| 192 | + RuntimeOrigin::signed(coldkey), |
| 193 | + hotkey, |
| 194 | + vali_take as u16 |
| 195 | + )); |
| 196 | + |
| 197 | + log::debug!("Hotkey became a delegate with minimum take"); |
| 198 | + |
| 199 | + // Add stakes for nominators |
| 200 | + // Add the stake directly to their coldkey-hotkey account |
| 201 | + // This bypasses the accounting in stake delta |
| 202 | + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&nominator1, &hotkey, 5e9 as u64); |
| 203 | + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&nominator2, &hotkey, 5e9 as u64); |
| 204 | + let initial_stake = 5e9 as u64; |
| 205 | + |
| 206 | + // Log the stakes for hotkey, nominator1, and nominator2 |
| 207 | + log::debug!( |
| 208 | + "Initial stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", |
| 209 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey), |
| 210 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey), |
| 211 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey) |
| 212 | + ); |
| 213 | + log::debug!("Stakes added for nominators"); |
| 214 | + |
| 215 | + // 5. Set emission and verify initial states |
| 216 | + let to_emit = 20_000e9 as u64; |
| 217 | + SubtensorModule::set_emission_values(&[netuid], vec![to_emit]).unwrap(); |
| 218 | + assert_eq!(SubtensorModule::get_subnet_emission_value(netuid), to_emit); |
| 219 | + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); |
| 220 | + assert_eq!( |
| 221 | + SubtensorModule::get_total_stake_for_hotkey(&hotkey), |
| 222 | + initial_stake * 2 |
| 223 | + ); |
| 224 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); |
| 225 | + |
| 226 | + log::debug!("Emission set and initial states verified"); |
| 227 | + |
| 228 | + // 6. Set hotkey emission tempo |
| 229 | + SubtensorModule::set_hotkey_emission_tempo(1); |
| 230 | + log::debug!("Hotkey emission tempo set to 1"); |
| 231 | + |
| 232 | + // 7. Simulate blocks and check emissions |
| 233 | + next_block(); |
| 234 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), to_emit); |
| 235 | + log::debug!( |
| 236 | + "After first block, pending emission: {}", |
| 237 | + SubtensorModule::get_pending_emission(netuid) |
| 238 | + ); |
| 239 | + |
| 240 | + next_block(); |
| 241 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); |
| 242 | + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); |
| 243 | + log::debug!("After second block, pending emission drained"); |
| 244 | + |
| 245 | + // 8. Check final stakes |
| 246 | + let hotkey_stake = SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); |
| 247 | + let nominator1_stake = |
| 248 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey); |
| 249 | + let nominator2_stake = |
| 250 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey); |
| 251 | + |
| 252 | + log::debug!( |
| 253 | + "Final stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", |
| 254 | + hotkey_stake, |
| 255 | + nominator1_stake, |
| 256 | + nominator2_stake |
| 257 | + ); |
| 258 | + |
| 259 | + // 9. Verify distribution |
| 260 | + let total_emission = to_emit * 2; // to_emit per block for 2 blocks |
| 261 | + let hotkey_emission = (I64F64::from_num(total_emission) / I64F64::from_num(u16::MAX) |
| 262 | + * I64F64::from_num(vali_take)) |
| 263 | + .to_num::<u64>(); |
| 264 | + let remaining_emission = total_emission - hotkey_emission; |
| 265 | + let nominator_emission = remaining_emission / 2; |
| 266 | + |
| 267 | + log::debug!( |
| 268 | + "Calculated emissions - Hotkey: {}, Each Nominator: {}", |
| 269 | + hotkey_emission, |
| 270 | + nominator_emission |
| 271 | + ); |
| 272 | + |
| 273 | + // Debug: Print the actual stakes |
| 274 | + log::debug!("Actual hotkey stake: {}", hotkey_stake); |
| 275 | + log::debug!("Actual nominator1 stake: {}", nominator1_stake); |
| 276 | + log::debug!("Actual nominator2 stake: {}", nominator2_stake); |
| 277 | + |
| 278 | + // Debug: Check the total stake for the hotkey |
| 279 | + let total_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey); |
| 280 | + log::debug!("Total stake for hotkey: {}", total_stake); |
| 281 | + |
| 282 | + // Assertions |
| 283 | + let expected_hotkey_stake = 4_000e9 as u64; |
| 284 | + let eps = 0.5e9 as u64; |
| 285 | + assert!( |
| 286 | + hotkey_stake >= expected_hotkey_stake - eps |
| 287 | + && hotkey_stake <= expected_hotkey_stake + eps, |
| 288 | + "Hotkey stake mismatch - expected: {}, actual: {}", |
| 289 | + expected_hotkey_stake, |
| 290 | + hotkey_stake |
| 291 | + ); |
| 292 | + assert_eq!( |
| 293 | + nominator1_stake, |
| 294 | + initial_stake + nominator_emission, |
| 295 | + "Nominator1 stake mismatch" |
| 296 | + ); |
| 297 | + assert_eq!( |
| 298 | + nominator2_stake, |
| 299 | + initial_stake + nominator_emission, |
| 300 | + "Nominator2 stake mismatch" |
| 301 | + ); |
| 302 | + |
| 303 | + // 10. Check total stake |
| 304 | + assert_eq!( |
| 305 | + total_stake, |
| 306 | + initial_stake + initial_stake + total_emission, |
| 307 | + "Total stake mismatch" |
| 308 | + ); |
| 309 | + |
| 310 | + log::debug!("Test completed"); |
| 311 | + }); |
| 312 | +} |
| 313 | + |
| 314 | +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --test coinbase test_coinbase_nominator_drainage_no_affected_by_last_add_stake -- --nocapture |
| 315 | +#[test] |
| 316 | +fn test_coinbase_nominator_drainage_no_affected_by_last_add_stake() { |
| 317 | + new_test_ext(1).execute_with(|| { |
| 318 | + // 1. Set up the network and accounts |
| 319 | + let netuid: u16 = 1; |
| 320 | + let hotkey = U256::from(0); |
| 321 | + let coldkey = U256::from(3); |
| 322 | + let nominator1 = U256::from(1); |
| 323 | + let nominator2 = U256::from(2); |
| 324 | + |
| 325 | + log::debug!("Setting up network with netuid: {}", netuid); |
| 326 | + log::debug!("Hotkey: {:?}, Coldkey: {:?}", hotkey, coldkey); |
| 327 | + log::debug!("Nominators: {:?}, {:?}", nominator1, nominator2); |
| 328 | + |
| 329 | + // 2. Create network and register neuron |
| 330 | + add_network(netuid, 1, 0); |
| 331 | + register_ok_neuron(netuid, hotkey, coldkey, 100000); |
| 332 | + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); |
| 333 | + |
| 334 | + log::debug!("Network created and neuron registered"); |
| 335 | + |
| 336 | + // 3. Set up balances and stakes |
| 337 | + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1000); |
| 338 | + SubtensorModule::add_balance_to_coldkey_account(&nominator1, 1500); |
| 339 | + SubtensorModule::add_balance_to_coldkey_account(&nominator2, 1500); |
| 340 | + |
| 341 | + log::debug!("Balances added to accounts"); |
| 342 | + |
| 343 | + // 4. Make the hotkey a delegate |
| 344 | + let vali_take = (u16::MAX as u64 / 10); |
| 345 | + assert_ok!(SubtensorModule::do_become_delegate( |
| 346 | + RuntimeOrigin::signed(coldkey), |
| 347 | + hotkey, |
| 348 | + vali_take as u16 |
| 349 | + )); |
| 350 | + |
| 351 | + log::debug!("Hotkey became a delegate with minimum take"); |
| 352 | + |
| 353 | + // Add stakes for nominators |
| 354 | + // Add the stake directly to their coldkey-hotkey account |
| 355 | + // This bypasses the accounting in stake delta |
| 356 | + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&nominator1, &hotkey, 5e9 as u64); |
| 357 | + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&nominator2, &hotkey, 5e9 as u64); |
| 358 | + let initial_stake = 5e9 as u64; |
| 359 | + |
| 360 | + // Make add_stake call for nominator1 |
| 361 | + // This should not affect the emission distribution |
| 362 | + |
| 363 | + // Will be greater than the bock emission |
| 364 | + LastAddStakeIncrease::<Test>::insert(hotkey, nominator1, 100); |
| 365 | + |
| 366 | + // Log the stakes for hotkey, nominator1, and nominator2 |
| 367 | + log::debug!( |
| 368 | + "Initial stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", |
| 369 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey), |
| 370 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey), |
| 371 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey) |
| 372 | + ); |
| 373 | + log::debug!("Stakes added for nominators"); |
| 374 | + |
| 375 | + // 5. Set emission and verify initial states |
| 376 | + let to_emit = 20_000e9 as u64; |
| 377 | + SubtensorModule::set_emission_values(&[netuid], vec![to_emit]).unwrap(); |
| 378 | + assert_eq!(SubtensorModule::get_subnet_emission_value(netuid), to_emit); |
| 379 | + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); |
| 380 | + assert_eq!( |
| 381 | + SubtensorModule::get_total_stake_for_hotkey(&hotkey), |
| 382 | + initial_stake * 2 |
| 383 | + ); |
| 384 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); |
| 385 | + |
| 386 | + log::debug!("Emission set and initial states verified"); |
| 387 | + |
| 388 | + // 6. Set hotkey emission tempo |
| 389 | + SubtensorModule::set_hotkey_emission_tempo(1); |
| 390 | + log::debug!("Hotkey emission tempo set to 1"); |
| 391 | + |
| 392 | + // 7. Simulate blocks and check emissions |
| 393 | + next_block(); |
| 394 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), to_emit); |
| 395 | + log::debug!( |
| 396 | + "After first block, pending emission: {}", |
| 397 | + SubtensorModule::get_pending_emission(netuid) |
| 398 | + ); |
| 399 | + |
| 400 | + next_block(); |
| 401 | + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); |
| 402 | + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); |
| 403 | + log::debug!("After second block, pending emission drained"); |
| 404 | + |
| 405 | + // 8. Check final stakes |
| 406 | + let hotkey_stake = SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); |
| 407 | + let nominator1_stake = |
| 408 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey); |
| 409 | + let nominator2_stake = |
| 410 | + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey); |
| 411 | + |
| 412 | + log::debug!( |
| 413 | + "Final stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", |
| 414 | + hotkey_stake, |
| 415 | + nominator1_stake, |
| 416 | + nominator2_stake |
| 417 | + ); |
| 418 | + |
| 419 | + // 9. Verify distribution |
| 420 | + let total_emission = to_emit * 2; // to_emit per block for 2 blocks |
| 421 | + let hotkey_emission = (I64F64::from_num(total_emission) / I64F64::from_num(u16::MAX) |
| 422 | + * I64F64::from_num(vali_take)) |
| 423 | + .to_num::<u64>(); |
| 424 | + let remaining_emission = total_emission - hotkey_emission; |
| 425 | + let nominator_emission = remaining_emission / 2; |
| 426 | + |
| 427 | + log::debug!( |
| 428 | + "Calculated emissions - Hotkey: {}, Each Nominator: {}", |
| 429 | + hotkey_emission, |
| 430 | + nominator_emission |
| 431 | + ); |
| 432 | + |
| 433 | + // Debug: Print the actual stakes |
| 434 | + log::debug!("Actual hotkey stake: {}", hotkey_stake); |
| 435 | + log::debug!("Actual nominator1 stake: {}", nominator1_stake); |
| 436 | + log::debug!("Actual nominator2 stake: {}", nominator2_stake); |
| 437 | + |
| 438 | + // Debug: Check the total stake for the hotkey |
| 439 | + let total_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey); |
| 440 | + log::debug!("Total stake for hotkey: {}", total_stake); |
| 441 | + |
| 442 | + // Assertions |
| 443 | + let expected_hotkey_stake = 4_000e9 as u64; |
| 444 | + let eps = 0.5e9 as u64; |
| 445 | + assert!( |
| 446 | + hotkey_stake >= expected_hotkey_stake - eps |
| 447 | + && hotkey_stake <= expected_hotkey_stake + eps, |
| 448 | + "Hotkey stake mismatch - expected: {}, actual: {}", |
| 449 | + expected_hotkey_stake, |
| 450 | + hotkey_stake |
| 451 | + ); |
| 452 | + assert_eq!( |
| 453 | + nominator1_stake, |
| 454 | + initial_stake + nominator_emission, |
| 455 | + "Nominator1 stake mismatch" |
| 456 | + ); |
| 457 | + assert_eq!( |
| 458 | + nominator2_stake, |
| 459 | + initial_stake + nominator_emission, |
| 460 | + "Nominator2 stake mismatch" |
| 461 | + ); |
| 462 | + |
| 463 | + // 10. Check total stake |
| 464 | + assert_eq!( |
| 465 | + total_stake, |
| 466 | + initial_stake + initial_stake + total_emission, |
| 467 | + "Total stake mismatch" |
| 468 | + ); |
| 469 | + |
| 470 | + log::debug!("Test completed"); |
| 471 | + }); |
| 472 | +} |
0 commit comments