@@ -686,6 +686,106 @@ impl WasmChallengeExecutor {
686686 Ok ( ( result_data, metrics) )
687687 }
688688
689+ /// Execute get_routes using provided WASM bytes directly (avoids reload)
690+ pub fn execute_get_routes_from_bytes (
691+ & self ,
692+ module_id : & str ,
693+ wasm_bytes : & [ u8 ] ,
694+ network_policy : & NetworkPolicy ,
695+ sandbox_policy : & SandboxPolicy ,
696+ ) -> Result < ( Vec < u8 > , ExecutionMetrics ) > {
697+ let start = Instant :: now ( ) ;
698+
699+ info ! (
700+ module = module_id,
701+ size_bytes = wasm_bytes. len( ) ,
702+ "Compiling WASM module from bytes"
703+ ) ;
704+
705+ let module = self
706+ . runtime
707+ . compile_module ( wasm_bytes)
708+ . map_err ( |e| anyhow:: anyhow!( "Failed to compile WASM module: {}" , e) ) ?;
709+
710+ let network_host_fns = Arc :: new ( NetworkHostFunctions :: all ( ) ) ;
711+
712+ let instance_config = InstanceConfig {
713+ network_policy : network_policy. clone ( ) ,
714+ sandbox_policy : sandbox_policy. clone ( ) ,
715+ exec_policy : ExecPolicy :: default ( ) ,
716+ time_policy : TimePolicy :: default ( ) ,
717+ audit_logger : None ,
718+ memory_export : "memory" . to_string ( ) ,
719+ challenge_id : module_id. to_string ( ) ,
720+ validator_id : "validator" . to_string ( ) ,
721+ restart_id : String :: new ( ) ,
722+ config_version : 0 ,
723+ storage_host_config : StorageHostConfig :: default ( ) ,
724+ storage_backend : Arc :: new ( InMemoryStorageBackend :: new ( ) ) ,
725+ fixed_timestamp_ms : None ,
726+ consensus_policy : ConsensusPolicy :: default ( ) ,
727+ terminal_policy : TerminalPolicy :: default ( ) ,
728+ llm_policy : match & self . config . chutes_api_key {
729+ Some ( key) => LlmPolicy :: with_api_key ( key. clone ( ) ) ,
730+ None => LlmPolicy :: default ( ) ,
731+ } ,
732+ ..Default :: default ( )
733+ } ;
734+
735+ let mut instance = self
736+ . runtime
737+ . instantiate ( & module, instance_config, Some ( network_host_fns) )
738+ . map_err ( |e| anyhow:: anyhow!( "WASM instantiation failed: {}" , e) ) ?;
739+
740+ let initial_fuel = instance. fuel_remaining ( ) ;
741+
742+ let result = instance
743+ . call_return_i64 ( "get_routes" )
744+ . map_err ( |e| anyhow:: anyhow!( "WASM get_routes call failed: {}" , e) ) ?;
745+
746+ let out_len = ( result >> 32 ) as i32 ;
747+ let out_ptr = ( result & 0xFFFF_FFFF ) as i32 ;
748+
749+ if out_len > 0 && out_len as u64 > MAX_ROUTE_OUTPUT_SIZE {
750+ return Err ( anyhow:: anyhow!(
751+ "WASM get_routes output size {} exceeds maximum allowed {}" ,
752+ out_len,
753+ MAX_ROUTE_OUTPUT_SIZE
754+ ) ) ;
755+ }
756+
757+ let result_data = if out_ptr > 0 && out_len > 0 {
758+ instance
759+ . read_memory ( out_ptr as usize , out_len as usize )
760+ . map_err ( |e| {
761+ anyhow:: anyhow!( "failed to read WASM memory for get_routes output: {}" , e)
762+ } ) ?
763+ } else {
764+ Vec :: new ( )
765+ } ;
766+
767+ let fuel_consumed = match ( initial_fuel, instance. fuel_remaining ( ) ) {
768+ ( Some ( initial) , Some ( remaining) ) => Some ( initial. saturating_sub ( remaining) ) ,
769+ _ => None ,
770+ } ;
771+
772+ let metrics = ExecutionMetrics {
773+ execution_time_ms : start. elapsed ( ) . as_millis ( ) ,
774+ memory_used_bytes : instance. memory ( ) . data_size ( instance. store ( ) ) as u64 ,
775+ network_requests_made : instance. network_requests_made ( ) ,
776+ fuel_consumed,
777+ } ;
778+
779+ info ! (
780+ module = module_id,
781+ result_bytes = result_data. len( ) ,
782+ execution_time_ms = metrics. execution_time_ms,
783+ "WASM get_routes from bytes completed"
784+ ) ;
785+
786+ Ok ( ( result_data, metrics) )
787+ }
788+
689789 #[ allow( dead_code) ]
690790 pub fn execute_handle_route (
691791 & self ,
@@ -916,53 +1016,10 @@ impl WasmChallengeExecutor {
9161016 }
9171017 }
9181018
919- // Try to load from distributed storage first
920- let wasm_bytes = if let Some ( ref storage) = self . config . distributed_storage {
921- let storage = Arc :: clone ( storage) ;
922- let key = platform_distributed_storage:: StorageKey :: new ( "wasm" , module_path) ;
923-
924- // Spawn a new thread with its own runtime to avoid nesting runtimes
925- // Use join() to ensure thread completes before returning
926- let handle = std:: thread:: spawn ( move || {
927- let rt = match tokio:: runtime:: Builder :: new_current_thread ( )
928- . enable_all ( )
929- . build ( )
930- {
931- Ok ( rt) => rt,
932- Err ( _) => return None ,
933- } ;
934- let result = rt. block_on ( async {
935- storage
936- . get ( & key, platform_distributed_storage:: GetOptions :: default ( ) )
937- . await
938- . ok ( )
939- . flatten ( )
940- } ) ;
941- // Explicitly shutdown runtime before thread exit
942- drop ( rt) ;
943- result
944- } ) ;
945-
946- match handle. join ( ) {
947- Ok ( Some ( stored) ) => {
948- info ! (
949- module = module_path,
950- size_bytes = stored. data. len( ) ,
951- "Loading WASM module from distributed storage"
952- ) ;
953- Some ( stored. data )
954- }
955- _ => {
956- debug ! (
957- module = module_path,
958- "WASM module not found in distributed storage"
959- ) ;
960- None
961- }
962- }
963- } else {
964- None
965- } ;
1019+ // Note: We don't try distributed storage here because this is a sync function
1020+ // that may be called from async context. The WASM should already be cached
1021+ // locally after upload. Use load_module_async for distributed storage access.
1022+ let wasm_bytes: Option < Vec < u8 > > = None ;
9661023
9671024 // Fallback to filesystem if not in distributed storage
9681025 let wasm_bytes = match wasm_bytes {
0 commit comments