Skip to content

Commit 5934e7d

Browse files
committed
feat(validator-node): authenticate WebSocket connection with signature
Validators now sign ws_connect:{hotkey}:{timestamp} message when connecting to platform-server WebSocket. This ensures only the real owner of the hotkey can register as that validator.
1 parent f18b74b commit 5934e7d

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

bins/validator-node/src/main.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,13 @@ async fn main() -> Result<()> {
433433
// This listens for new_submission events and triggers local evaluation
434434
// Also handles challenge_stopped events to stop local containers
435435
let ws_platform_url = args.platform_server.clone();
436-
let ws_validator_hotkey = keypair.ss58_address();
436+
let ws_keypair = keypair.clone();
437437
let ws_challenge_urls = challenge_urls.clone();
438438
let ws_orchestrator = orchestrator.clone();
439439
tokio::spawn(async move {
440440
start_websocket_listener(
441441
ws_platform_url,
442-
ws_validator_hotkey,
442+
ws_keypair,
443443
ws_challenge_urls,
444444
ws_orchestrator,
445445
)
@@ -743,19 +743,35 @@ async fn handle_block_event(
743743
/// Also handles challenge_stopped events to stop local containers
744744
pub async fn start_websocket_listener(
745745
platform_url: String,
746-
validator_hotkey: String,
746+
keypair: Keypair,
747747
challenge_urls: Arc<RwLock<HashMap<String, String>>>,
748748
orchestrator: Option<Arc<ChallengeOrchestrator>>,
749749
) {
750-
// Convert HTTP URL to WebSocket URL
751-
let ws_url = platform_url
750+
let validator_hotkey = keypair.ss58_address();
751+
752+
// Convert HTTP URL to WebSocket URL with authentication params
753+
let base_ws_url = platform_url
752754
.replace("https://", "wss://")
753755
.replace("http://", "ws://")
754756
+ "/ws";
755757

756-
info!("Starting WebSocket listener: {}", ws_url);
758+
info!("Starting WebSocket listener: {}", base_ws_url);
757759

758760
loop {
761+
// Generate fresh timestamp and signature for each connection attempt
762+
let timestamp = std::time::SystemTime::now()
763+
.duration_since(std::time::UNIX_EPOCH)
764+
.unwrap()
765+
.as_secs() as i64;
766+
767+
let message = format!("ws_connect:{}:{}", validator_hotkey, timestamp);
768+
let signature = hex::encode(keypair.sign_bytes(message.as_bytes()).unwrap_or_default());
769+
770+
let ws_url = format!(
771+
"{}?hotkey={}&timestamp={}&signature={}&role=validator",
772+
base_ws_url, validator_hotkey, timestamp, signature
773+
);
774+
759775
match connect_to_websocket(
760776
&ws_url,
761777
&validator_hotkey,

0 commit comments

Comments
 (0)