@@ -1141,8 +1141,8 @@ fn recycle_alpha_clamps_to_available_when_amount_exceeds_stake() {
11411141
11421142 let returned_amount = AlphaBalance :: decode ( & mut env. output ( ) ) . unwrap ( ) ;
11431143 assert_eq ! (
1144- returned_amount, alpha_before ,
1145- "should clamp to available alpha "
1144+ returned_amount, huge_amount ,
1145+ "should return requested amount "
11461146 ) ;
11471147
11481148 let alpha_after =
@@ -1242,8 +1242,8 @@ fn burn_alpha_clamps_to_available_when_amount_exceeds_stake() {
12421242
12431243 let returned_amount = AlphaBalance :: decode ( & mut env. output ( ) ) . unwrap ( ) ;
12441244 assert_eq ! (
1245- returned_amount, alpha_before ,
1246- "should clamp to available alpha "
1245+ returned_amount, huge_amount ,
1246+ "should return requested amount "
12471247 ) ;
12481248
12491249 let alpha_after =
@@ -1321,6 +1321,144 @@ fn assert_success(ret: RetVal) {
13211321 }
13221322}
13231323
1324+ #[ test]
1325+ fn add_stake_recycle_rollback_on_recycle_failure ( ) {
1326+ mock:: new_test_ext ( 1 ) . execute_with ( || {
1327+ let owner_hotkey = U256 :: from ( 12001 ) ;
1328+ let owner_coldkey = U256 :: from ( 12002 ) ;
1329+ let coldkey = U256 :: from ( 12101 ) ;
1330+ let hotkey = U256 :: from ( 12102 ) ;
1331+ let min_stake = DefaultMinStake :: < mock:: Test > :: get ( ) ;
1332+ let tao_amount_raw = min_stake. to_u64 ( ) . saturating_mul ( 200 ) ;
1333+
1334+ let netuid = mock:: add_dynamic_network ( & owner_hotkey, & owner_coldkey) ;
1335+
1336+ // Set up very low reserves so recycle will fail with InsufficientLiquidity
1337+ mock:: setup_reserves (
1338+ netuid,
1339+ TaoBalance :: from ( 1_000_u64 ) ,
1340+ AlphaBalance :: from ( 1_000_u64 ) ,
1341+ ) ;
1342+
1343+ mock:: register_ok_neuron ( netuid, hotkey, coldkey, 0 ) ;
1344+
1345+ pallet_subtensor:: Pallet :: < mock:: Test > :: add_balance_to_coldkey_account (
1346+ & coldkey,
1347+ TaoBalance :: from ( tao_amount_raw. saturating_add ( 1_000_000_000 ) ) ,
1348+ ) ;
1349+
1350+ let balance_before = pallet_subtensor:: Pallet :: < mock:: Test > :: get_coldkey_balance ( & coldkey) ;
1351+ let alpha_before =
1352+ pallet_subtensor:: Pallet :: < mock:: Test > :: get_stake_for_hotkey_and_coldkey_on_subnet (
1353+ & hotkey, & coldkey, netuid,
1354+ ) ;
1355+
1356+ let expected_weight = Weight :: from_parts ( 454_200_000 , 0 )
1357+ . saturating_add ( <mock:: Test as frame_system:: Config >:: DbWeight :: get ( ) . reads ( 33 ) )
1358+ . saturating_add ( <mock:: Test as frame_system:: Config >:: DbWeight :: get ( ) . writes ( 19 ) ) ;
1359+
1360+ let mut env = MockEnv :: new (
1361+ FunctionId :: AddStakeRecycleV1 ,
1362+ coldkey,
1363+ ( hotkey, netuid, TaoBalance :: from ( tao_amount_raw) ) . encode ( ) ,
1364+ )
1365+ . with_expected_weight ( expected_weight) ;
1366+
1367+ let ret = SubtensorChainExtension :: < mock:: Test > :: dispatch ( & mut env) . unwrap ( ) ;
1368+ match ret {
1369+ RetVal :: Converging ( code) => {
1370+ assert_ne ! ( code, Output :: Success as u32 , "should not succeed" )
1371+ }
1372+ _ => panic ! ( "unexpected return value" ) ,
1373+ }
1374+
1375+ // Verify full rollback: balance and stake unchanged
1376+ let balance_after = pallet_subtensor:: Pallet :: < mock:: Test > :: get_coldkey_balance ( & coldkey) ;
1377+ let alpha_after =
1378+ pallet_subtensor:: Pallet :: < mock:: Test > :: get_stake_for_hotkey_and_coldkey_on_subnet (
1379+ & hotkey, & coldkey, netuid,
1380+ ) ;
1381+
1382+ assert_eq ! (
1383+ balance_before, balance_after,
1384+ "balance should be unchanged after rollback"
1385+ ) ;
1386+ assert_eq ! (
1387+ alpha_before, alpha_after,
1388+ "stake should be unchanged after rollback"
1389+ ) ;
1390+ } ) ;
1391+ }
1392+
1393+ #[ test]
1394+ fn add_stake_burn_rollback_on_burn_failure ( ) {
1395+ mock:: new_test_ext ( 1 ) . execute_with ( || {
1396+ let owner_hotkey = U256 :: from ( 12201 ) ;
1397+ let owner_coldkey = U256 :: from ( 12202 ) ;
1398+ let coldkey = U256 :: from ( 12301 ) ;
1399+ let hotkey = U256 :: from ( 12302 ) ;
1400+ let min_stake = DefaultMinStake :: < mock:: Test > :: get ( ) ;
1401+ let tao_amount_raw = min_stake. to_u64 ( ) . saturating_mul ( 200 ) ;
1402+
1403+ let netuid = mock:: add_dynamic_network ( & owner_hotkey, & owner_coldkey) ;
1404+
1405+ // Set up very low reserves so burn will fail with InsufficientLiquidity
1406+ mock:: setup_reserves (
1407+ netuid,
1408+ TaoBalance :: from ( 1_000_u64 ) ,
1409+ AlphaBalance :: from ( 1_000_u64 ) ,
1410+ ) ;
1411+
1412+ mock:: register_ok_neuron ( netuid, hotkey, coldkey, 0 ) ;
1413+
1414+ pallet_subtensor:: Pallet :: < mock:: Test > :: add_balance_to_coldkey_account (
1415+ & coldkey,
1416+ TaoBalance :: from ( tao_amount_raw. saturating_add ( 1_000_000_000 ) ) ,
1417+ ) ;
1418+
1419+ let balance_before = pallet_subtensor:: Pallet :: < mock:: Test > :: get_coldkey_balance ( & coldkey) ;
1420+ let alpha_before =
1421+ pallet_subtensor:: Pallet :: < mock:: Test > :: get_stake_for_hotkey_and_coldkey_on_subnet (
1422+ & hotkey, & coldkey, netuid,
1423+ ) ;
1424+
1425+ let expected_weight = Weight :: from_parts ( 453_000_000 , 0 )
1426+ . saturating_add ( <mock:: Test as frame_system:: Config >:: DbWeight :: get ( ) . reads ( 33 ) )
1427+ . saturating_add ( <mock:: Test as frame_system:: Config >:: DbWeight :: get ( ) . writes ( 18 ) ) ;
1428+
1429+ let mut env = MockEnv :: new (
1430+ FunctionId :: AddStakeBurnV1 ,
1431+ coldkey,
1432+ ( hotkey, netuid, TaoBalance :: from ( tao_amount_raw) ) . encode ( ) ,
1433+ )
1434+ . with_expected_weight ( expected_weight) ;
1435+
1436+ let ret = SubtensorChainExtension :: < mock:: Test > :: dispatch ( & mut env) . unwrap ( ) ;
1437+ match ret {
1438+ RetVal :: Converging ( code) => {
1439+ assert_ne ! ( code, Output :: Success as u32 , "should not succeed" )
1440+ }
1441+ _ => panic ! ( "unexpected return value" ) ,
1442+ }
1443+
1444+ // Verify full rollback: balance and stake unchanged
1445+ let balance_after = pallet_subtensor:: Pallet :: < mock:: Test > :: get_coldkey_balance ( & coldkey) ;
1446+ let alpha_after =
1447+ pallet_subtensor:: Pallet :: < mock:: Test > :: get_stake_for_hotkey_and_coldkey_on_subnet (
1448+ & hotkey, & coldkey, netuid,
1449+ ) ;
1450+
1451+ assert_eq ! (
1452+ balance_before, balance_after,
1453+ "balance should be unchanged after rollback"
1454+ ) ;
1455+ assert_eq ! (
1456+ alpha_before, alpha_after,
1457+ "stake should be unchanged after rollback"
1458+ ) ;
1459+ } ) ;
1460+ }
1461+
13241462#[ test]
13251463fn get_stake_info_returns_encoded_runtime_value ( ) {
13261464 mock:: new_test_ext ( 1 ) . execute_with ( || {
0 commit comments