1- //! Submissions API handlers
1+ //! Submissions API handlers - DEPRECATED
2+ //!
3+ //! Submissions have been migrated to term-challenge.
4+ //! These endpoints now return deprecation notices directing users
5+ //! to use the term-challenge API instead.
26
37use crate :: db:: queries;
48use crate :: models:: * ;
@@ -9,13 +13,11 @@ use axum::{
913 Json ,
1014} ;
1115use serde:: Deserialize ;
12- use sha2:: Digest ;
13- use sp_core:: crypto:: Ss58Codec ;
1416use std:: sync:: Arc ;
1517
16- /// Validate that a string is a valid SS58 hotkey address
17- fn is_valid_ss58_hotkey ( hotkey : & str ) -> bool {
18- sp_core :: crypto :: AccountId32 :: from_ss58check ( hotkey ) . is_ok ( )
18+ /// Term-challenge URL for submissions (configured via TERM_CHALLENGE_URL env)
19+ fn get_term_challenge_url ( ) -> String {
20+ std :: env :: var ( "TERM_CHALLENGE_URL" ) . unwrap_or_else ( |_| "http://localhost:8081" . to_string ( ) )
1921}
2022
2123#[ derive( Debug , Deserialize ) ]
@@ -24,10 +26,13 @@ pub struct ListSubmissionsQuery {
2426 pub status : Option < String > ,
2527}
2628
29+ /// DEPRECATED: List submissions
30+ /// Submissions are now managed by term-challenge.
2731pub async fn list_submissions (
2832 State ( state) : State < Arc < AppState > > ,
2933 Query ( query) : Query < ListSubmissionsQuery > ,
3034) -> Result < Json < Vec < Submission > > , StatusCode > {
35+ // Still return data from local DB for backward compatibility during migration
3136 let submissions = if query. status . as_deref ( ) == Some ( "pending" ) {
3237 queries:: get_pending_submissions ( & state. db ) . await
3338 } else {
@@ -40,6 +45,8 @@ pub async fn list_submissions(
4045 Ok ( Json ( limited) )
4146}
4247
48+ /// DEPRECATED: Get submission by ID
49+ /// Submissions are now managed by term-challenge.
4350pub async fn get_submission (
4451 State ( state) : State < Arc < AppState > > ,
4552 Path ( id) : Path < String > ,
@@ -51,165 +58,49 @@ pub async fn get_submission(
5158 Ok ( Json ( submission) )
5259}
5360
61+ /// DEPRECATED: Get submission source code
62+ /// Source code access is now managed by term-challenge with proper authentication.
5463pub async fn get_submission_source (
55- State ( state) : State < Arc < AppState > > ,
56- Path ( id) : Path < String > ,
57- ) -> Result < Json < serde_json:: Value > , StatusCode > {
58- let submission = queries:: get_submission ( & state. db , & id)
59- . await
60- . map_err ( |_| StatusCode :: INTERNAL_SERVER_ERROR ) ?
61- . ok_or ( StatusCode :: NOT_FOUND ) ?;
62-
63- Ok ( Json ( serde_json:: json!( {
64- "agent_hash" : submission. agent_hash,
65- "source_code" : submission. source_code,
66- } ) ) )
64+ State ( _state) : State < Arc < AppState > > ,
65+ Path ( _id) : Path < String > ,
66+ ) -> Result < Json < serde_json:: Value > , ( StatusCode , Json < serde_json:: Value > ) > {
67+ // No longer expose source code from platform-server
68+ // Users must use term-challenge API with proper authentication
69+ Err ( (
70+ StatusCode :: GONE ,
71+ Json ( serde_json:: json!( {
72+ "error" : "Source code access has been migrated to term-challenge" ,
73+ "message" : "Use the term-challenge API to access source code with proper authentication" ,
74+ "term_challenge_url" : get_term_challenge_url( ) ,
75+ "endpoints" : {
76+ "owner_source" : "POST /api/v1/my/agents/:hash/source" ,
77+ "validator_claim" : "POST /api/v1/validator/claim_job"
78+ }
79+ } ) ) ,
80+ ) )
6781}
6882
83+ /// DEPRECATED: Submit agent endpoint
84+ /// Agent submissions have been migrated to term-challenge.
85+ /// This endpoint returns a redirect notice.
6986pub async fn submit_agent (
70- State ( state ) : State < Arc < AppState > > ,
71- Json ( req ) : Json < SubmitAgentRequest > ,
87+ State ( _state ) : State < Arc < AppState > > ,
88+ Json ( _req ) : Json < SubmitAgentRequest > ,
7289) -> Result < Json < SubmitAgentResponse > , ( StatusCode , Json < SubmitAgentResponse > ) > {
73- // Validate miner_hotkey is a valid SS58 address
74- if !is_valid_ss58_hotkey ( & req. miner_hotkey ) {
75- tracing:: warn!(
76- "Invalid miner_hotkey format: {} (expected SS58 address starting with '5')" ,
77- & req. miner_hotkey[ ..32 . min( req. miner_hotkey. len( ) ) ]
78- ) ;
79- return Err ( (
80- StatusCode :: BAD_REQUEST ,
81- Json ( SubmitAgentResponse {
82- success : false ,
83- submission_id : None ,
84- agent_hash : None ,
85- error : Some ( format ! (
86- "Invalid miner_hotkey: must be a valid SS58 address (e.g., '5GrwvaEF...'). Received: {}" ,
87- & req. miner_hotkey[ ..32 . min( req. miner_hotkey. len( ) ) ]
88- ) ) ,
89- } ) ,
90- ) ) ;
91- }
92-
93- // Verify signature: miner must sign their source code hash to prove ownership
94- // Message format: "submit_agent:<sha256_of_source_code>"
95- let source_hash = hex:: encode ( sha2:: Sha256 :: digest ( req. source_code . as_bytes ( ) ) ) ;
96- let message = format ! ( "submit_agent:{}" , source_hash) ;
97-
98- if !crate :: api:: auth:: verify_signature ( & req. miner_hotkey , & message, & req. signature ) {
99- tracing:: warn!(
100- "Invalid signature for submission from {}" ,
101- & req. miner_hotkey[ ..16 . min( req. miner_hotkey. len( ) ) ]
102- ) ;
103- return Err ( (
104- StatusCode :: UNAUTHORIZED ,
105- Json ( SubmitAgentResponse {
106- success : false ,
107- submission_id : None ,
108- agent_hash : None ,
109- error : Some ( format ! (
110- "Invalid signature. Message to sign: '{}'. Use sr25519 signature from your hotkey." ,
111- message
112- ) ) ,
113- } ) ,
114- ) ) ;
115- }
116-
117- let epoch = queries:: get_current_epoch ( & state. db ) . await . unwrap_or ( 0 ) ;
118-
119- // Rate limiting: 0.33 submissions per epoch (1 every 3 epochs)
120- let can_submit = match queries:: can_miner_submit ( & state. db , & req. miner_hotkey , epoch) . await {
121- Ok ( can) => can,
122- Err ( e) => {
123- tracing:: error!( "Rate limit check failed for {}: {}" , req. miner_hotkey, e) ;
124- true // Allow submission if rate limit check fails
125- }
126- } ;
127-
128- tracing:: debug!(
129- "Submission check: miner={}, epoch={}, can_submit={}" ,
130- & req. miner_hotkey[ ..16 . min( req. miner_hotkey. len( ) ) ] ,
131- epoch,
132- can_submit
133- ) ;
134-
135- if !can_submit {
136- return Err ( (
137- StatusCode :: TOO_MANY_REQUESTS ,
138- Json ( SubmitAgentResponse {
139- success : false ,
140- submission_id : None ,
141- agent_hash : None ,
142- error : Some ( "Rate limit: 1 submission per 3 epochs" . to_string ( ) ) ,
143- } ) ,
144- ) ) ;
145- }
146-
147- // Create submission with API key for centralized LLM inference
148- let submission = queries:: create_submission (
149- & state. db ,
150- & req. miner_hotkey ,
151- & req. source_code ,
152- req. name . as_deref ( ) ,
153- req. api_key . as_deref ( ) ,
154- req. api_provider . as_deref ( ) ,
155- req. api_keys_encrypted . as_deref ( ) ,
156- epoch,
157- )
158- . await
159- . map_err ( |e| {
160- (
161- StatusCode :: INTERNAL_SERVER_ERROR ,
162- Json ( SubmitAgentResponse {
163- success : false ,
164- submission_id : None ,
165- agent_hash : None ,
166- error : Some ( e. to_string ( ) ) ,
167- } ) ,
168- )
169- } ) ?;
170-
171- tracing:: info!(
172- "Agent submitted: {} (hash: {}) from {} with provider: {:?}" ,
173- submission. name. as_deref( ) . unwrap_or( "unnamed" ) ,
174- & submission. agent_hash[ ..16 ] ,
175- & req. miner_hotkey,
176- req. api_provider
177- ) ;
178-
179- // Create evaluation job for each active challenge
180- let challenges = queries:: get_challenges ( & state. db ) . await . unwrap_or_default ( ) ;
181-
182- for challenge in challenges. iter ( ) . filter ( |c| c. status == "active" ) {
183- match queries:: create_job ( & state. db , & submission. id , & challenge. id ) . await {
184- Ok ( job) => {
185- tracing:: info!(
186- "Created job {} for submission {} on challenge {}" ,
187- job. id,
188- & submission. id[ ..8 ] ,
189- challenge. id
190- ) ;
191- }
192- Err ( e) => {
193- tracing:: warn!( "Failed to create job for challenge {}: {}" , challenge. id, e) ;
194- }
195- }
196- }
197-
198- // Broadcast submission event
199- state
200- . broadcast_event ( WsEvent :: SubmissionReceived ( SubmissionEvent {
201- submission_id : submission. id . clone ( ) ,
202- agent_hash : submission. agent_hash . clone ( ) ,
203- miner_hotkey : submission. miner_hotkey . clone ( ) ,
204- name : submission. name . clone ( ) ,
205- epoch,
206- } ) )
207- . await ;
208-
209- Ok ( Json ( SubmitAgentResponse {
210- success : true ,
211- submission_id : Some ( submission. id ) ,
212- agent_hash : Some ( submission. agent_hash ) ,
213- error : None ,
214- } ) )
90+ // Submissions are now handled by term-challenge
91+ tracing:: warn!( "Deprecated submit_agent endpoint called - redirecting to term-challenge" ) ;
92+
93+ Err ( (
94+ StatusCode :: GONE ,
95+ Json ( SubmitAgentResponse {
96+ success : false ,
97+ submission_id : None ,
98+ agent_hash : None ,
99+ error : Some ( format ! (
100+ "Agent submissions have been migrated to term-challenge. \
101+ Please use: POST {}/api/v1/submit",
102+ get_term_challenge_url( )
103+ ) ) ,
104+ } ) ,
105+ ) )
215106}
0 commit comments