Skip to content

Commit f7e6828

Browse files
committed
refactor: use mutate_and_persist helper everywhere for ChainState mutations
Audit and fix all ChainState mutations to use the helper: - sudo_action from RPC - wasm_upload from local RPC - wasm_upload from P2P broadcast - wasm_upload from consensus This ensures all critical state changes are automatically persisted, preventing issues where rename/deactivate/etc don't survive restarts.
1 parent d3f82bb commit f7e6828

File tree

1 file changed

+102
-76
lines changed

1 file changed

+102
-76
lines changed

bins/validator-node/src/main.rs

Lines changed: 102 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -960,14 +960,18 @@ async fn main() -> Result<()> {
960960
platform_rpc::RpcP2PCommand::BroadcastSudoAction { action } => {
961961
info!("Received sudo action from RPC: {:?}", action);
962962

963-
// Apply to local chain state (RPC server already applied, but handle
964-
// the case where this is received from P2P relay)
965-
{
966-
let mut cs = chain_state.write();
967-
if let Err(e) = cs.apply_sudo_action(&action) {
968-
error!("Failed to apply sudo action: {}", e);
969-
}
970-
}
963+
// Apply to local chain state and persist
964+
mutate_and_persist(
965+
storage.clone(),
966+
chain_state.clone(),
967+
"sudo_action_rpc",
968+
|cs| {
969+
if let Err(e) = cs.apply_sudo_action(&action) {
970+
error!("Failed to apply sudo action: {}", e);
971+
}
972+
},
973+
)
974+
.await;
971975

972976
// Broadcast as a ChallengeUpdate with type "sudo_action"
973977
// so peer validators can receive and apply it
@@ -1102,31 +1106,35 @@ async fn main() -> Result<()> {
11021106
"WASM stored locally in distributed storage"
11031107
);
11041108

1105-
// Sync to ChainState for RPC
1106-
{
1107-
let challenge_name = name.as_deref().unwrap_or(&challenge_id_str).to_string();
1108-
let mut cs = chain_state.write();
1109-
let wasm_config = platform_core::WasmChallengeConfig {
1110-
challenge_id,
1111-
name: challenge_name,
1112-
description: String::new(),
1113-
owner: keypair.hotkey(),
1114-
module: platform_core::WasmModuleMetadata {
1115-
module_path: challenge_id_str.clone(),
1116-
code_hash: hex::encode(metadata.value_hash),
1117-
version: metadata.version.to_string(),
1118-
..Default::default()
1119-
},
1120-
config: platform_core::ChallengeConfig::default(),
1121-
is_active: true,
1122-
};
1123-
cs.register_wasm_challenge(wasm_config);
1124-
}
1125-
1126-
// Persist core state immediately so challenge survives restart
1127-
if let Err(e) = persist_core_state_to_storage(&storage, &chain_state).await {
1128-
warn!("Failed to persist core state after challenge registration: {}", e);
1129-
}
1109+
// Sync to ChainState for RPC and persist
1110+
let challenge_name = name.as_deref().unwrap_or(&challenge_id_str).to_string();
1111+
let owner = keypair.hotkey();
1112+
let code_hash = hex::encode(metadata.value_hash);
1113+
let version = metadata.version.to_string();
1114+
let module_path = challenge_id_str.clone();
1115+
mutate_and_persist(
1116+
storage.clone(),
1117+
chain_state.clone(),
1118+
"wasm_upload_local",
1119+
|cs| {
1120+
let wasm_config = platform_core::WasmChallengeConfig {
1121+
challenge_id,
1122+
name: challenge_name,
1123+
description: String::new(),
1124+
owner,
1125+
module: platform_core::WasmModuleMetadata {
1126+
module_path,
1127+
code_hash,
1128+
version,
1129+
..Default::default()
1130+
},
1131+
config: platform_core::ChallengeConfig::default(),
1132+
is_active: true,
1133+
};
1134+
cs.register_wasm_challenge(wasm_config);
1135+
},
1136+
)
1137+
.await;
11301138

11311139
// Load routes in a blocking thread to avoid tokio runtime issues
11321140
if let Some(ref executor) = wasm_executor {
@@ -2213,33 +2221,39 @@ async fn handle_network_event(
22132221
}
22142222
});
22152223

2216-
// Sync challenge to ChainState for RPC
2217-
{
2218-
let mut cs = chain_state.write();
2219-
let wasm_config = platform_core::WasmChallengeConfig {
2220-
challenge_id: update.challenge_id,
2221-
name: challenge_name,
2222-
description: String::new(),
2223-
owner: update.updater.clone(),
2224-
module: platform_core::WasmModuleMetadata {
2225-
module_path: challenge_id_str.clone(),
2226-
code_hash: hex::encode(metadata.value_hash),
2227-
version: metadata.version.to_string(),
2228-
..Default::default()
2229-
},
2230-
config: platform_core::ChallengeConfig::default(),
2231-
is_active: true,
2232-
};
2233-
cs.register_wasm_challenge(wasm_config);
2234-
}
2235-
2236-
// Persist core state immediately so challenge survives restart
2237-
if let Err(e) =
2238-
persist_core_state_to_storage(storage, chain_state)
2239-
.await
2240-
{
2241-
warn!("Failed to persist core state after P2P challenge registration: {}", e);
2242-
}
2224+
// Sync challenge to ChainState for RPC and persist
2225+
let cid = update.challenge_id;
2226+
let owner = update.updater.clone();
2227+
let code_hash = hex::encode(metadata.value_hash);
2228+
let version = metadata.version.to_string();
2229+
let module_path = challenge_id_str.clone();
2230+
let cname = challenge_name.clone();
2231+
mutate_and_persist(
2232+
storage.clone(),
2233+
chain_state.clone(),
2234+
"wasm_upload_p2p",
2235+
|cs| {
2236+
let wasm_config =
2237+
platform_core::WasmChallengeConfig {
2238+
challenge_id: cid,
2239+
name: cname,
2240+
description: String::new(),
2241+
owner,
2242+
module: platform_core::WasmModuleMetadata {
2243+
module_path,
2244+
code_hash,
2245+
version,
2246+
..Default::default()
2247+
},
2248+
config:
2249+
platform_core::ChallengeConfig::default(
2250+
),
2251+
is_active: true,
2252+
};
2253+
cs.register_wasm_challenge(wasm_config);
2254+
},
2255+
)
2256+
.await;
22432257

22442258
// Load routes in a blocking thread to avoid tokio runtime issues
22452259
if let Some(ref executor) = wasm_executor_ref {
@@ -2790,23 +2804,35 @@ async fn handle_network_event(
27902804
let wasm_key = StorageKey::new("wasm", &challenge_id_str);
27912805
match storage.put(wasm_key, entry.data.clone(), PutOptions::default()).await {
27922806
Ok(metadata) => {
2793-
let mut cs = chain_state.write();
2794-
let wasm_config = platform_core::WasmChallengeConfig {
2795-
challenge_id: *challenge_id,
2796-
name: challenge_id_str.clone(),
2797-
description: String::new(),
2798-
owner: entry.proposer.clone(),
2799-
module: platform_core::WasmModuleMetadata {
2800-
module_path: challenge_id_str.clone(),
2801-
code_hash: hex::encode(metadata.value_hash),
2802-
version: metadata.version.to_string(),
2803-
..Default::default()
2807+
let cid = *challenge_id;
2808+
let owner = entry.proposer.clone();
2809+
let code_hash = hex::encode(metadata.value_hash);
2810+
let version = metadata.version.to_string();
2811+
let module_path = challenge_id_str.clone();
2812+
let cname = challenge_id_str.clone();
2813+
mutate_and_persist(
2814+
storage.clone(),
2815+
chain_state.clone(),
2816+
"wasm_consensus",
2817+
|cs| {
2818+
let wasm_config = platform_core::WasmChallengeConfig {
2819+
challenge_id: cid,
2820+
name: cname,
2821+
description: String::new(),
2822+
owner,
2823+
module: platform_core::WasmModuleMetadata {
2824+
module_path,
2825+
code_hash,
2826+
version,
2827+
..Default::default()
2828+
},
2829+
config: platform_core::ChallengeConfig::default(),
2830+
is_active: true,
2831+
};
2832+
cs.register_wasm_challenge(wasm_config);
28042833
},
2805-
config: platform_core::ChallengeConfig::default(),
2806-
is_active: true,
2807-
};
2808-
cs.register_wasm_challenge(wasm_config);
2809-
drop(cs);
2834+
)
2835+
.await;
28102836

28112837
info!(
28122838
challenge_id = %challenge_id,

0 commit comments

Comments
 (0)