@@ -1459,26 +1459,27 @@ mod tests {
14591459 ..Default :: default ( )
14601460 } ;
14611461
1462- let file_sha = "c257e3d3fe866a00df1285f8bbbe601fed6b85229d983bbbb75e19a068346641" ;
1463- let group_id = "3450756714426841564" ;
1462+ const FILE_SHA : & str = "c257e3d3fe866a00df1285f8bbbe601fed6b85229d983bbbb75e19a068346641" ;
1463+ const GROUP_ID : & str = "3450756714426841564" ;
1464+ const NODE_ADDRESS : & str = "0x0000000000000000000000000000000000000000" ;
14641465
14651466 let mock_storage = MockStorageProvider :: new ( ) ;
14661467 mock_storage. add_file (
1467- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-1-0-0.parquet" , group_id ) ,
1468+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-1-0-0.parquet" , GROUP_ID ) ,
14681469 "file1" ,
14691470 ) ;
14701471 mock_storage. add_mapping_file (
1471- file_sha ,
1472- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-1-0-0.parquet" , group_id ) ,
1472+ FILE_SHA ,
1473+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-1-0-0.parquet" , GROUP_ID ) ,
14731474 ) ;
14741475 server
14751476 . mock (
14761477 "POST" ,
1477- "/validategroup/dataset/samplingn-3450756714426841564 -1-0.parquet" ,
1478+ format ! ( "/validategroup/dataset/samplingn-{} -1-0.parquet" , GROUP_ID ) . as_str ( ) ,
14781479 )
14791480 . match_body ( mockito:: Matcher :: Json ( serde_json:: json!( {
1480- "file_shas" : [ file_sha ] ,
1481- "group_id" : group_id ,
1481+ "file_shas" : [ FILE_SHA ] ,
1482+ "group_id" : GROUP_ID ,
14821483 "file_number" : 0 ,
14831484 "group_size" : 1
14841485 } ) ) )
@@ -1488,7 +1489,7 @@ mod tests {
14881489 server
14891490 . mock (
14901491 "GET" ,
1491- "/statusgroup/dataset/samplingn-3450756714426841564 -1-0.parquet" ,
1492+ format ! ( "/statusgroup/dataset/samplingn-{} -1-0.parquet" , GROUP_ID ) . as_str ( ) ,
14921493 )
14931494 . with_status ( 200 )
14941495 . with_body ( r#"{"status": "accept"}"# )
@@ -1515,12 +1516,10 @@ mod tests {
15151516 Some ( metrics_context) ,
15161517 ) ;
15171518
1518- let work_keys: Vec < String > = vec ! [ file_sha. to_string( ) ] ;
1519- let work_keys_2: Vec < String > = work_keys. clone ( ) ;
1520- let work_keys_3: Vec < String > = work_keys. clone ( ) ;
1519+ let work_keys: Vec < String > = vec ! [ FILE_SHA . to_string( ) ] ;
15211520
15221521 let work_info = WorkInfo {
1523- node_id : Address :: from_str ( "0x0000000000000000000000000000000000000000" ) . unwrap ( ) ,
1522+ node_id : Address :: from_str ( NODE_ADDRESS ) . unwrap ( ) ,
15241523 ..Default :: default ( )
15251524 } ;
15261525 for work_key in work_keys. clone ( ) {
@@ -1529,29 +1528,29 @@ mod tests {
15291528 . await ?;
15301529 }
15311530
1532- let plan = validator. build_validation_plan ( work_keys) . await ?;
1531+ let plan = validator. build_validation_plan ( work_keys. clone ( ) ) . await ?;
15331532 assert_eq ! ( plan. group_trigger_tasks. len( ) , 1 ) ;
1534- assert_eq ! ( plan. group_trigger_tasks[ 0 ] . group_id, group_id ) ;
1533+ assert_eq ! ( plan. group_trigger_tasks[ 0 ] . group_id, GROUP_ID ) ;
15351534 let metrics_0 = export_metrics ( ) . unwrap ( ) ;
15361535 assert ! ( metrics_0
15371536 . contains( "validator_work_keys_to_process{pool_id=\" 0\" ,validator_id=\" 0\" } 1" ) ) ;
15381537
1539- let group = validator. get_group ( file_sha ) . await ?;
1538+ let group = validator. get_group ( FILE_SHA ) . await ?;
15401539 assert ! ( group. is_some( ) ) ;
15411540 let group = group. unwrap ( ) ;
1542- assert_eq ! ( group. group_id, group_id ) ;
1541+ assert_eq ! ( group. group_id, GROUP_ID ) ;
15431542 assert_eq ! ( group. group_size, 1 ) ;
15441543 assert_eq ! ( group. file_number, 0 ) ;
15451544
15461545 let result = validator. process_group_task ( group) . await ;
15471546 assert ! ( result. is_ok( ) ) ;
15481547
15491548 let cache_status = validator
1550- . get_work_validation_status_from_redis ( file_sha )
1549+ . get_work_validation_status_from_redis ( FILE_SHA )
15511550 . await ?;
15521551 assert_eq ! ( cache_status, Some ( ValidationResult :: Unknown ) ) ;
15531552
1554- let plan_2 = validator. build_validation_plan ( work_keys_2 ) . await ?;
1553+ let plan_2 = validator. build_validation_plan ( work_keys . clone ( ) ) . await ?;
15551554 assert_eq ! ( plan_2. group_trigger_tasks. len( ) , 0 ) ;
15561555 assert_eq ! ( plan_2. group_status_check_tasks. len( ) , 1 ) ;
15571556
@@ -1566,23 +1565,26 @@ mod tests {
15661565 assert ! ( result. is_ok( ) ) ;
15671566
15681567 let cache_status = validator
1569- . get_work_validation_status_from_redis ( file_sha )
1568+ . get_work_validation_status_from_redis ( FILE_SHA )
15701569 . await ?;
15711570 assert_eq ! ( cache_status, Some ( ValidationResult :: Accept ) ) ;
15721571
1573- let plan_3 = validator. build_validation_plan ( work_keys_3 ) . await ?;
1572+ let plan_3 = validator. build_validation_plan ( work_keys . clone ( ) ) . await ?;
15741573 assert_eq ! ( plan_3. group_trigger_tasks. len( ) , 0 ) ;
15751574 assert_eq ! ( plan_3. group_status_check_tasks. len( ) , 0 ) ;
15761575 let metrics_2 = export_metrics ( ) . unwrap ( ) ;
15771576 assert ! ( metrics_2
15781577 . contains( "validator_work_keys_to_process{pool_id=\" 0\" ,validator_id=\" 0\" } 0" ) ) ;
15791578 assert ! ( metrics_2. contains( "toploc_config_name=\" Qwen/Qwen0.6\" " ) ) ;
1580- assert ! ( metrics_2. contains( "validator_group_work_units_check_total{group_id=\" 3450756714426841564 \" ,pool_id=\" 0\" ,result=\" match\" ,toploc_config_name=\" Qwen/Qwen0.6\" ,validator_id=\" 0\" } 1" ) ) ;
1579+ assert ! ( metrics_2. contains( & format! ( "validator_group_work_units_check_total{{ group_id=\" {} \" ,pool_id=\" 0\" ,result=\" match\" ,toploc_config_name=\" Qwen/Qwen0.6\" ,validator_id=\" 0\" }} 1" , GROUP_ID ) ) ) ;
15811580
15821581 Ok ( ( ) )
15831582 }
15841583
15851584 #[ tokio:: test]
1585+ // This test accepts a groups submission via the toploc server which returns a total output flops count
1586+ // One of the nodes claims more work units than the output_flops_count / number of nodes
1587+ // The validator should reject the node and accept the other node
15861588 async fn test_group_e2e_work_unit_mismatch ( ) -> Result < ( ) , Error > {
15871589 let mut server = Server :: new_async ( ) . await ;
15881590 let ( store, contracts) = setup_test_env ( ) ?;
@@ -1593,35 +1595,39 @@ mod tests {
15931595 ..Default :: default ( )
15941596 } ;
15951597
1596- let file_sha_1 = "c257e3d3fe866a00df1285f8bbbe601fed6b85229d983bbbb75e19a068346641" ;
1597- let file_sha_2 = "88e4672c19e5a10bff2e23d223f8bfc38ae1425feaa18db9480e631a4fd98edf" ;
1598- let group_id = "3450756714426841564" ;
1598+ const HONEST_NODE_ADDRESS : & str = "0x0000000000000000000000000000000000000001" ;
1599+ const HONEST_FILE_SHA : & str =
1600+ "c257e3d3fe866a00df1285f8bbbe601fed6b85229d983bbbb75e19a068346641" ;
1601+ const EXCESSIVE_FILE_SHA : & str =
1602+ "88e4672c19e5a10bff2e23d223f8bfc38ae1425feaa18db9480e631a4fd98edf" ;
1603+ const EXCESSIVE_NODE_ADDRESS : & str = "0x0000000000000000000000000000000000000002" ;
1604+ const GROUP_ID : & str = "3456714426841564" ;
15991605
16001606 let mock_storage = MockStorageProvider :: new ( ) ;
16011607 mock_storage. add_file (
1602- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-0.parquet" , group_id ) ,
1608+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-0.parquet" , GROUP_ID ) ,
16031609 "file1" ,
16041610 ) ;
16051611 mock_storage. add_file (
1606- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-1.parquet" , group_id ) ,
1612+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-1.parquet" , GROUP_ID ) ,
16071613 "file2" ,
16081614 ) ;
16091615 mock_storage. add_mapping_file (
1610- file_sha_1 ,
1611- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-0.parquet" , group_id ) ,
1616+ HONEST_FILE_SHA ,
1617+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-0.parquet" , GROUP_ID ) ,
16121618 ) ;
16131619 mock_storage. add_mapping_file (
1614- file_sha_2 ,
1615- & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-1.parquet" , group_id ) ,
1620+ EXCESSIVE_FILE_SHA ,
1621+ & format ! ( "Qwen/Qwen0.6/dataset/samplingn-{}-2-0-1.parquet" , GROUP_ID ) ,
16161622 ) ;
16171623 server
16181624 . mock (
16191625 "POST" ,
1620- "/validategroup/dataset/samplingn-3450756714426841564 -2-0.parquet" ,
1626+ format ! ( "/validategroup/dataset/samplingn-{} -2-0.parquet" , GROUP_ID ) . as_str ( ) ,
16211627 )
16221628 . match_body ( mockito:: Matcher :: Json ( serde_json:: json!( {
1623- "file_shas" : [ file_sha_1 , file_sha_2 ] ,
1624- "group_id" : group_id ,
1629+ "file_shas" : [ HONEST_FILE_SHA , EXCESSIVE_FILE_SHA ] ,
1630+ "group_id" : GROUP_ID ,
16251631 "file_number" : 0 ,
16261632 "group_size" : 2
16271633 } ) ) )
@@ -1631,7 +1637,7 @@ mod tests {
16311637 server
16321638 . mock (
16331639 "GET" ,
1634- "/statusgroup/dataset/samplingn-3450756714426841564 -2-0.parquet" ,
1640+ format ! ( "/statusgroup/dataset/samplingn-{} -2-0.parquet" , GROUP_ID ) . as_str ( ) ,
16351641 )
16361642 . with_status ( 200 )
16371643 . with_body ( r#"{"status": "accept", "input_flops": 1, "output_flops": 2000}"# )
@@ -1658,57 +1664,58 @@ mod tests {
16581664 Some ( metrics_context) ,
16591665 ) ;
16601666
1661- let work_keys: Vec < String > = vec ! [ file_sha_1. to_string( ) , file_sha_2. to_string( ) ] ;
1662- let work_keys_2: Vec < String > = work_keys. clone ( ) ;
1663- let work_keys_3: Vec < String > = work_keys. clone ( ) ;
1667+ let work_keys: Vec < String > =
1668+ vec ! [ HONEST_FILE_SHA . to_string( ) , EXCESSIVE_FILE_SHA . to_string( ) ] ;
16641669
16651670 // Node 1 claims exact amount (1000 work units)
1671+ const EXPECTED_WORK_UNITS : u64 = 1000 ;
1672+ const EXCESSIVE_WORK_UNITS : u64 = 1500 ;
16661673 let work_info_1 = WorkInfo {
1667- node_id : Address :: from_str ( "0x0000000000000000000000000000000000000001" ) . unwrap ( ) ,
1668- work_units : U256 :: from ( 1000 ) ,
1674+ node_id : Address :: from_str ( HONEST_NODE_ADDRESS ) . unwrap ( ) ,
1675+ work_units : U256 :: from ( EXPECTED_WORK_UNITS ) ,
16691676 ..Default :: default ( )
16701677 } ;
16711678 // Node 2 claims too much (1500 work units instead of 1000)
16721679 let work_info_2 = WorkInfo {
1673- node_id : Address :: from_str ( "0x0000000000000000000000000000000000000002" ) . unwrap ( ) ,
1674- work_units : U256 :: from ( 1500 ) ,
1680+ node_id : Address :: from_str ( EXCESSIVE_NODE_ADDRESS ) . unwrap ( ) ,
1681+ work_units : U256 :: from ( EXCESSIVE_WORK_UNITS ) ,
16751682 ..Default :: default ( )
16761683 } ;
16771684
16781685 validator
1679- . update_work_info_in_redis ( file_sha_1 , & work_info_1)
1686+ . update_work_info_in_redis ( HONEST_FILE_SHA , & work_info_1)
16801687 . await ?;
16811688 validator
1682- . update_work_info_in_redis ( file_sha_2 , & work_info_2)
1689+ . update_work_info_in_redis ( EXCESSIVE_FILE_SHA , & work_info_2)
16831690 . await ?;
16841691
1685- let plan = validator. build_validation_plan ( work_keys) . await ?;
1692+ let plan = validator. build_validation_plan ( work_keys. clone ( ) ) . await ?;
16861693 assert_eq ! ( plan. group_trigger_tasks. len( ) , 1 ) ;
1687- assert_eq ! ( plan. group_trigger_tasks[ 0 ] . group_id, group_id ) ;
1694+ assert_eq ! ( plan. group_trigger_tasks[ 0 ] . group_id, GROUP_ID ) ;
16881695 let metrics_0 = export_metrics ( ) . unwrap ( ) ;
16891696 assert ! ( metrics_0
16901697 . contains( "validator_work_keys_to_process{pool_id=\" 0\" ,validator_id=\" 0\" } 2" ) ) ;
16911698
1692- let group = validator. get_group ( file_sha_1 ) . await ?;
1699+ let group = validator. get_group ( HONEST_FILE_SHA ) . await ?;
16931700 assert ! ( group. is_some( ) ) ;
16941701 let group = group. unwrap ( ) ;
1695- assert_eq ! ( group. group_id, group_id ) ;
1702+ assert_eq ! ( group. group_id, GROUP_ID ) ;
16961703 assert_eq ! ( group. group_size, 2 ) ;
16971704 assert_eq ! ( group. file_number, 0 ) ;
16981705
16991706 let result = validator. process_group_task ( group) . await ;
17001707 assert ! ( result. is_ok( ) ) ;
17011708
17021709 let cache_status_1 = validator
1703- . get_work_validation_status_from_redis ( file_sha_1 )
1710+ . get_work_validation_status_from_redis ( HONEST_FILE_SHA )
17041711 . await ?;
17051712 assert_eq ! ( cache_status_1, Some ( ValidationResult :: Unknown ) ) ;
17061713 let cache_status_2 = validator
1707- . get_work_validation_status_from_redis ( file_sha_2 )
1714+ . get_work_validation_status_from_redis ( EXCESSIVE_FILE_SHA )
17081715 . await ?;
17091716 assert_eq ! ( cache_status_2, Some ( ValidationResult :: Unknown ) ) ;
17101717
1711- let plan_2 = validator. build_validation_plan ( work_keys_2 ) . await ?;
1718+ let plan_2 = validator. build_validation_plan ( work_keys . clone ( ) ) . await ?;
17121719 assert_eq ! ( plan_2. group_trigger_tasks. len( ) , 0 ) ;
17131720 assert_eq ! ( plan_2. group_status_check_tasks. len( ) , 1 ) ;
17141721
@@ -1720,31 +1727,30 @@ mod tests {
17201727 let result = validator
17211728 . process_group_status_check ( plan_2. group_status_check_tasks [ 0 ] . clone ( ) )
17221729 . await ;
1723- println ! ( "result: {:?}" , result) ;
17241730 assert ! ( result. is_ok( ) ) ;
17251731
17261732 // Node 1 should be accepted (exact claim)
17271733 let cache_status_1 = validator
1728- . get_work_validation_status_from_redis ( file_sha_1 )
1734+ . get_work_validation_status_from_redis ( HONEST_FILE_SHA )
17291735 . await ?;
17301736 assert_eq ! ( cache_status_1, Some ( ValidationResult :: Accept ) ) ;
17311737
1732- // Node 2 should be rejected (wrong claim)
1738+ // Node 2 should be rejected (excessive claim)
17331739 let cache_status_2 = validator
1734- . get_work_validation_status_from_redis ( file_sha_2 )
1740+ . get_work_validation_status_from_redis ( EXCESSIVE_FILE_SHA )
17351741 . await ?;
17361742 assert_eq ! ( cache_status_2, Some ( ValidationResult :: Reject ) ) ;
17371743
1738- let plan_3 = validator. build_validation_plan ( work_keys_3) . await ?;
1744+ // Make sure there is no more work to process
1745+ let plan_3 = validator. build_validation_plan ( work_keys. clone ( ) ) . await ?;
17391746 assert_eq ! ( plan_3. group_trigger_tasks. len( ) , 0 ) ;
17401747 assert_eq ! ( plan_3. group_status_check_tasks. len( ) , 0 ) ;
17411748 let metrics_2 = export_metrics ( ) . unwrap ( ) ;
1742- println ! ( " metrics_2: {}" , metrics_2 ) ;
1749+ assert ! ( metrics_2. contains ( & format! ( "validator_group_validations_total{{group_id= \" {} \" ,pool_id= \" 0 \" ,result= \" accept \" ,toploc_config_name= \" Qwen/Qwen0.6 \" ,validator_id= \" 0 \" }} 1" , GROUP_ID ) ) ) ;
17431750 assert ! ( metrics_2
17441751 . contains( "validator_work_keys_to_process{pool_id=\" 0\" ,validator_id=\" 0\" } 0" ) ) ;
17451752 assert ! ( metrics_2. contains( "toploc_config_name=\" Qwen/Qwen0.6\" " ) ) ;
1746- assert ! ( metrics_2. contains( "validator_group_work_units_check_total{group_id=\" 3450756714426841564\" ,pool_id=\" 0\" ,result=\" mismatch\" ,toploc_config_name=\" Qwen/Qwen0.6\" ,validator_id=\" 0\" } 1" ) ) ;
1747- assert ! ( metrics_2. contains( "validator_group_work_units_check_total{group_id=\" 3450756714426841564\" ,pool_id=\" 0\" ,result=\" match\" ,toploc_config_name=\" Qwen/Qwen0.6\" ,validator_id=\" 0\" } 1" ) ) ;
1753+ assert ! ( metrics_2. contains( & format!( "validator_group_work_units_check_total{{group_id=\" {}\" ,pool_id=\" 0\" ,result=\" mismatch\" ,toploc_config_name=\" Qwen/Qwen0.6\" ,validator_id=\" 0\" }} 1" , GROUP_ID ) ) ) ;
17481754
17491755 Ok ( ( ) )
17501756 }
0 commit comments