@@ -1766,6 +1766,72 @@ async fn handle_network_event(
17661766 data_type = %req. data_type,
17671767 "Received data request"
17681768 ) ;
1769+
1770+ if !validator_set. is_validator ( & req. requester ) {
1771+ warn ! ( requester = %req. requester. to_hex( ) , "Data request from unknown validator" ) ;
1772+ } else if req. data_type == "challenge_storage" {
1773+ // Respond with storage data for the requested challenge
1774+ let challenge_id_str = req. challenge_id . to_string ( ) ;
1775+
1776+ // List all keys in this challenge's namespace using list_prefix
1777+ let list_result = storage
1778+ . list_prefix ( & challenge_id_str, None , 10000 , None )
1779+ . await ;
1780+
1781+ match list_result {
1782+ Ok ( list_result) => {
1783+ // Collect all key-value pairs for this challenge
1784+ let mut storage_entries: Vec < ( String , Vec < u8 > ) > = Vec :: new ( ) ;
1785+ for ( key, stored) in list_result. items {
1786+ // Store key as hex-encoded string (matches our key format)
1787+ let key_str = String :: from_utf8 ( key. key . clone ( ) )
1788+ . unwrap_or_else ( |_| hex:: encode ( & key. key ) ) ;
1789+ storage_entries. push ( ( key_str, stored. data ) ) ;
1790+ }
1791+
1792+ let data = bincode:: serialize ( & storage_entries) . unwrap_or_default ( ) ;
1793+ let timestamp = chrono:: Utc :: now ( ) . timestamp_millis ( ) ;
1794+ let request_id = req. request_id . clone ( ) ;
1795+ let challenge_id = req. challenge_id ;
1796+ let sign_data = bincode:: serialize ( & ( & request_id, & data, timestamp) )
1797+ . unwrap_or_default ( ) ;
1798+ let signature = keypair. sign_bytes ( & sign_data) . unwrap_or_default ( ) ;
1799+
1800+ let response = P2PMessage :: DataResponse (
1801+ platform_p2p_consensus:: DataResponseMessage {
1802+ request_id : request_id. clone ( ) ,
1803+ responder : keypair. hotkey ( ) ,
1804+ challenge_id,
1805+ data_type : "challenge_storage" . to_string ( ) ,
1806+ data,
1807+ timestamp,
1808+ signature,
1809+ } ,
1810+ ) ;
1811+
1812+ if let Err ( e) = p2p_cmd_tx
1813+ . send ( platform_p2p_consensus:: P2PCommand :: Broadcast ( response) )
1814+ . await
1815+ {
1816+ warn ! ( error = %e, "Failed to send storage data response" ) ;
1817+ } else {
1818+ info ! (
1819+ request_id = %request_id,
1820+ challenge_id = %challenge_id,
1821+ entries = storage_entries. len( ) ,
1822+ "Sent challenge storage data response"
1823+ ) ;
1824+ }
1825+ }
1826+ Err ( e) => {
1827+ warn ! (
1828+ challenge_id = %req. challenge_id,
1829+ error = %e,
1830+ "Failed to list storage entries for data request"
1831+ ) ;
1832+ }
1833+ }
1834+ }
17691835 }
17701836 P2PMessage :: DataResponse ( resp) => {
17711837 debug ! (
@@ -1775,6 +1841,61 @@ async fn handle_network_event(
17751841 data_bytes = resp. data. len( ) ,
17761842 "Received data response"
17771843 ) ;
1844+
1845+ if !validator_set. is_validator ( & resp. responder ) {
1846+ warn ! ( responder = %resp. responder. to_hex( ) , "Data response from unknown validator" ) ;
1847+ } else if resp. data_type == "challenge_storage" {
1848+ // Merge storage data from peer
1849+ match bincode:: deserialize :: < Vec < ( String , Vec < u8 > ) > > ( & resp. data ) {
1850+ Ok ( entries) => {
1851+ let challenge_id_str = resp. challenge_id . to_string ( ) ;
1852+ let mut imported = 0 ;
1853+
1854+ for ( key, value) in entries {
1855+ let storage_key = StorageKey :: new ( & challenge_id_str, key) ;
1856+ // Only import if we don't have this key
1857+ match storage
1858+ . get (
1859+ & storage_key,
1860+ platform_distributed_storage:: GetOptions :: default ( ) ,
1861+ )
1862+ . await
1863+ {
1864+ Ok ( None ) => {
1865+ if let Err ( e) = storage
1866+ . put ( storage_key, value, PutOptions :: default ( ) )
1867+ . await
1868+ {
1869+ warn ! ( error = %e, "Failed to import storage entry" ) ;
1870+ } else {
1871+ imported += 1 ;
1872+ }
1873+ }
1874+ Ok ( Some ( _) ) => {
1875+ // Already have this key, skip
1876+ }
1877+ Err ( e) => {
1878+ warn ! ( error = %e, "Failed to check existing storage entry" ) ;
1879+ }
1880+ }
1881+ }
1882+
1883+ if imported > 0 {
1884+ info ! (
1885+ challenge_id = %resp. challenge_id,
1886+ imported = imported,
1887+ "Imported storage entries from peer"
1888+ ) ;
1889+ }
1890+ }
1891+ Err ( e) => {
1892+ warn ! (
1893+ error = %e,
1894+ "Failed to deserialize challenge storage data response"
1895+ ) ;
1896+ }
1897+ }
1898+ }
17781899 }
17791900 P2PMessage :: TaskProgress ( progress) => {
17801901 debug ! (
@@ -1926,7 +2047,7 @@ async fn handle_network_event(
19262047
19272048 // Persist core state immediately so challenge survives restart
19282049 if let Err ( e) =
1929- persist_core_state_to_storage ( storage, & chain_state)
2050+ persist_core_state_to_storage ( storage, chain_state)
19302051 . await
19312052 {
19322053 warn ! ( "Failed to persist core state after P2P challenge registration: {}" , e) ;
@@ -2169,9 +2290,11 @@ async fn handle_network_event(
21692290 . apply ( |state| state. remove_storage_proposal ( & vote. proposal_id ) ) ;
21702291
21712292 if let Some ( proposal) = proposal_opt {
2293+ // Use same key format as ChallengeStorageBackend:
2294+ // namespace = challenge_id.to_string(), key = hex::encode(key_bytes)
21722295 let storage_key = StorageKey :: new (
2173- & format ! ( "challenge:{}" , proposal. challenge_id) ,
2174- & proposal. key ,
2296+ & proposal. challenge_id . to_string ( ) ,
2297+ hex :: encode ( & proposal. key ) ,
21752298 ) ;
21762299
21772300 match storage
@@ -2267,15 +2390,46 @@ async fn handle_network_event(
22672390 let local_map: std:: collections:: HashMap < _ , _ > =
22682391 local_roots. into_iter ( ) . collect ( ) ;
22692392 for ( cid, remote_root) in & msg. roots {
2270- if let Some ( local_root) = local_map. get ( cid) {
2271- if local_root != remote_root {
2272- warn ! (
2273- challenge_id = %cid,
2274- local = %hex:: encode( & local_root[ ..8 ] ) ,
2275- remote = %hex:: encode( & remote_root[ ..8 ] ) ,
2276- remote_validator = %msg. validator. to_hex( ) ,
2277- "Storage root divergence detected"
2278- ) ;
2393+ let needs_sync = match local_map. get ( cid) {
2394+ Some ( local_root) => local_root != remote_root,
2395+ None => true , // We don't have this challenge's storage at all
2396+ } ;
2397+
2398+ if needs_sync {
2399+ info ! (
2400+ challenge_id = %cid,
2401+ remote_validator = %msg. validator. to_hex( ) ,
2402+ "Storage divergence detected, requesting challenge data"
2403+ ) ;
2404+
2405+ // Request storage data for this challenge
2406+ let request_id = format ! (
2407+ "storage_sync_{}_{}" ,
2408+ cid,
2409+ chrono:: Utc :: now( ) . timestamp_millis( )
2410+ ) ;
2411+ let timestamp = chrono:: Utc :: now ( ) . timestamp_millis ( ) ;
2412+ let sign_data =
2413+ bincode:: serialize ( & ( & request_id, timestamp) ) . unwrap_or_default ( ) ;
2414+ let signature = keypair. sign_bytes ( & sign_data) . unwrap_or_default ( ) ;
2415+
2416+ let req = P2PMessage :: DataRequest (
2417+ platform_p2p_consensus:: DataRequestMessage {
2418+ request_id,
2419+ requester : keypair. hotkey ( ) ,
2420+ challenge_id : * cid,
2421+ data_type : "challenge_storage" . to_string ( ) ,
2422+ data_key : "all" . to_string ( ) ,
2423+ timestamp,
2424+ signature,
2425+ } ,
2426+ ) ;
2427+
2428+ if let Err ( e) = p2p_cmd_tx
2429+ . send ( platform_p2p_consensus:: P2PCommand :: Broadcast ( req) )
2430+ . await
2431+ {
2432+ warn ! ( error = %e, "Failed to send storage sync request" ) ;
22792433 }
22802434 }
22812435 }
@@ -2452,7 +2606,7 @@ async fn handle_network_event(
24522606
24532607 // Persist immediately after consensus-approved mutation
24542608 if let Err ( e) =
2455- persist_core_state_to_storage ( storage, & chain_state) . await
2609+ persist_core_state_to_storage ( storage, chain_state) . await
24562610 {
24572611 warn ! (
24582612 "Failed to persist core state after consensus mutation: {}" ,
@@ -2533,7 +2687,7 @@ async fn handle_network_event(
25332687
25342688 // Persist merged state
25352689 if let Err ( e) =
2536- persist_core_state_to_storage ( storage, & chain_state) . await
2690+ persist_core_state_to_storage ( storage, chain_state) . await
25372691 {
25382692 warn ! ( "Failed to persist merged core state: {}" , e) ;
25392693 }
0 commit comments