Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 56 additions & 23 deletions tooling/nargo/src/foreign_calls/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub struct RPCForeignCallExecutor {
id: u64,
/// JSON RPC client to resolve foreign calls
external_resolver: HttpClient,
/// External resolver target. We are keeping it to be able to restart httpClient if necessary
///
/// See [`noir-lang/noir#7463`][<https://github.com/noir-lang/noir/issues/7463>]
resolver_url: String,
/// Root path to the program or workspace in execution.
root_path: Option<PathBuf>,
/// Name of the package in execution
Expand Down Expand Up @@ -59,17 +63,7 @@ impl RPCForeignCallExecutor {
root_path: Option<PathBuf>,
package_name: Option<String>,
) -> Self {
let mut client_builder = HttpClientBuilder::new();

if let Some(Ok(timeout)) =
std::env::var("NARGO_FOREIGN_CALL_TIMEOUT").ok().map(|timeout| timeout.parse())
{
let timeout_duration = std::time::Duration::from_millis(timeout);
client_builder = client_builder.request_timeout(timeout_duration);
};

let oracle_resolver =
client_builder.build(resolver_url).expect("Invalid oracle resolver URL");
let oracle_resolver = build_http_client(resolver_url);

// Opcodes are executed in the `ProgramExecutor::execute_circuit` one by one in a loop,
// we don't need a concurrent thread pool.
Expand All @@ -81,12 +75,49 @@ impl RPCForeignCallExecutor {

RPCForeignCallExecutor {
external_resolver: oracle_resolver,
resolver_url: resolver_url.to_string(),
id,
root_path,
package_name,
runtime,
}
}

fn send_foreign_call<F>(
&mut self,
foreign_call: &ForeignCallWaitInfo<F>,
) -> Result<ForeignCallResult<F>, jsonrpsee::core::ClientError>
where
F: AcirField + Serialize + for<'a> Deserialize<'a>,
{
let params = ResolveForeignCallRequest {
session_id: self.id,
function_call: foreign_call.clone(),
root_path: self
.root_path
.clone()
.map(|path| path.to_str().unwrap().to_string())
.or(Some(String::new())),
package_name: self.package_name.clone().or(Some(String::new())),
};
let encoded_params = rpc_params!(params);
self.runtime.block_on(async {
self.external_resolver.request("resolve_foreign_call", encoded_params).await
})
}
}

fn build_http_client(target: &str) -> HttpClient {
let mut client_builder = HttpClientBuilder::new();

if let Some(Ok(timeout)) =
std::env::var("NARGO_FOREIGN_CALL_TIMEOUT").ok().map(|timeout| timeout.parse())
{
let timeout_duration = std::time::Duration::from_millis(timeout);
client_builder = client_builder.request_timeout(timeout_duration);
};

client_builder.build(target).expect("Invalid oracle resolver URL")
}

impl<F> ForeignCallExecutor<F> for RPCForeignCallExecutor
Expand All @@ -97,18 +128,20 @@ where
/// This method cannot be called from inside a `tokio` runtime, for that to work
/// we need to offload the execution into a different thread; see the tests.
fn execute(&mut self, foreign_call: &ForeignCallWaitInfo<F>) -> ResolveForeignCallResult<F> {
let encoded_params = rpc_params!(ResolveForeignCallRequest {
session_id: self.id,
function_call: foreign_call.clone(),
root_path: self.root_path.clone().map(|path| path.to_str().unwrap().to_string()),
package_name: self.package_name.clone(),
});

let parsed_response = self.runtime.block_on(async {
self.external_resolver.request("resolve_foreign_call", encoded_params).await
})?;

Ok(parsed_response)
let result = self.send_foreign_call(foreign_call);

match result {
Ok(parsed_response) => Ok(parsed_response),
// TODO: This is a workaround for noir-lang/noir#7463
// The client is losing connection with the server and it's not being able to manage it
// so we are re-creating the HttpClient when it happens
Err(jsonrpsee::core::ClientError::Transport(_)) => {
self.external_resolver = build_http_client(&self.resolver_url);
let parsed_response = self.send_foreign_call(foreign_call)?;
Ok(parsed_response)
}
Err(other) => Err(ForeignCallError::from(other)),
}
}
}

Expand Down
Loading