Skip to content

Commit 5598a57

Browse files
authored
Merge of #2170
2 parents bc3e177 + 7afe56e commit 5598a57

File tree

7 files changed

+189
-13
lines changed

7 files changed

+189
-13
lines changed

coprocessor/fhevm-engine/.sqlx/query-1e3fb703be1a08661ebe7dc0b7517a96f9fa8b5c9c9388fb5fdb06fbcad1a944.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coprocessor/fhevm-engine/scheduler/src/dfg/scheduler.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -458,13 +458,24 @@ fn try_execute_node(
458458
RERAND_LATENCY_BATCH_HISTOGRAM.observe(elapsed.as_secs_f64());
459459
}
460460
let opcode = node.opcode;
461-
Ok(run_computation(
462-
opcode,
463-
cts,
464-
node_index,
465-
gpu_idx,
466-
transaction_id,
467-
))
461+
let result = std::panic::catch_unwind(|| {
462+
run_computation(opcode, cts, node_index, gpu_idx, transaction_id)
463+
});
464+
match result {
465+
Err(e) => {
466+
let msg = e
467+
.downcast_ref::<&str>()
468+
.map(|s| s.to_string())
469+
.or_else(|| e.downcast_ref::<String>().cloned())
470+
.unwrap_or_else(|| "unknown panic payload".to_string());
471+
eprintln!("Panic while executing operation: {msg}");
472+
error!(target: "scheduler", { handle = ?hex::encode(&node.result_handle), msg },
473+
"Panic while executing operation");
474+
telemetry::set_current_span_error(&msg);
475+
Err(SchedulerError::ExecutionPanic(msg).into())
476+
}
477+
Ok(r) => Ok(r),
478+
}
468479
}
469480

470481
type OpResult = Result<CompressedCiphertext>;

coprocessor/fhevm-engine/scheduler/src/dfg/types.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ impl std::fmt::Debug for DFGTaskInput {
6262
}
6363
}
6464

65-
#[derive(Debug, Copy, Clone)]
65+
#[derive(Debug, Clone)]
6666
pub enum SchedulerError {
6767
CyclicDependence,
6868
DataflowGraphError,
6969
MissingInputs,
7070
DecompressionError,
7171
ReRandomisationError,
7272
SchedulerError,
73+
ExecutionPanic(String),
7374
}
7475

7576
impl std::error::Error for SchedulerError {}
@@ -95,6 +96,9 @@ impl std::fmt::Display for SchedulerError {
9596
Self::SchedulerError => {
9697
write!(f, "Generic scheduler error")
9798
}
99+
Self::ExecutionPanic(s) => {
100+
write!(f, "Panic during execution of operation: {}", s)
101+
}
98102
}
99103
}
100104
}

coprocessor/fhevm-engine/tfhe-worker/src/tests/operators_from_events.rs

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ use crate::tests::event_helpers::{
1010
zero_address, EventHarness,
1111
};
1212
use crate::tests::test_cases::{
13-
generate_binary_test_cases, generate_unary_test_cases, BinaryOperatorTestCase,
14-
UnaryOperatorTestCase,
13+
generate_binary_test_cases, generate_panic_binary_test_cases, generate_unary_test_cases,
14+
BinaryOperatorTestCase, UnaryOperatorTestCase,
15+
};
16+
use crate::tests::utils::{
17+
decrypt_ciphertexts, errors_on_allowed_handles, wait_until_all_allowed_handles_computed,
1518
};
16-
use crate::tests::utils::{decrypt_ciphertexts, wait_until_all_allowed_handles_computed};
1719

1820
const LOCAL_SUPPORTED_TYPES: &[i32] = &[
1921
0, // bool
@@ -319,6 +321,93 @@ async fn test_fhe_binary_operands_events() -> Result<(), Box<dyn std::error::Err
319321
Ok(())
320322
}
321323

324+
#[tokio::test]
325+
#[serial(db)]
326+
async fn test_fhe_binary_operands_events_panic() -> Result<(), Box<dyn std::error::Error>> {
327+
let EventHarness {
328+
app,
329+
pool: _,
330+
listener_db,
331+
} = setup_event_harness().await?;
332+
333+
let mut cases = vec![];
334+
for op in generate_panic_binary_test_cases() {
335+
if !supported_types().contains(&op.input_types) {
336+
continue;
337+
}
338+
// TrivialEncrypt test setup uses ClearConst (up to 256-bit payloads).
339+
if op.bits > 256 {
340+
continue;
341+
}
342+
let lhs_handle = next_handle();
343+
let rhs_handle = next_handle();
344+
let output_handle = next_handle();
345+
let transaction_id = next_handle();
346+
347+
let lhs_bytes = as_scalar_uint(&op.lhs);
348+
let rhs_bytes = as_scalar_uint(&op.rhs);
349+
350+
println!(
351+
"Operations for binary test bits:{} op:{} is_scalar:{} lhs:{} rhs:{}",
352+
op.bits, op.operator, op.is_scalar, op.lhs, op.rhs
353+
);
354+
let caller = zero_address();
355+
356+
let mut tx = listener_db.new_transaction().await?;
357+
insert_event(
358+
&listener_db,
359+
&mut tx,
360+
transaction_id,
361+
TfheContractEvents::TrivialEncrypt(TfheContract::TrivialEncrypt {
362+
caller,
363+
pt: lhs_bytes,
364+
toType: to_ty(op.input_types),
365+
result: lhs_handle,
366+
}),
367+
true,
368+
)
369+
.await?;
370+
allow_handle(&listener_db, &mut tx, &lhs_handle).await?;
371+
if !op.is_scalar {
372+
insert_event(
373+
&listener_db,
374+
&mut tx,
375+
transaction_id,
376+
TfheContractEvents::TrivialEncrypt(TfheContract::TrivialEncrypt {
377+
caller,
378+
pt: rhs_bytes,
379+
toType: to_ty(op.input_types),
380+
result: rhs_handle,
381+
}),
382+
true,
383+
)
384+
.await?;
385+
allow_handle(&listener_db, &mut tx, &rhs_handle).await?;
386+
}
387+
let op_event = binary_op_to_event(&op, &lhs_handle, &rhs_handle, &op.rhs, &output_handle);
388+
insert_event(&listener_db, &mut tx, transaction_id, op_event, true).await?;
389+
allow_handle(&listener_db, &mut tx, &output_handle).await?;
390+
tx.commit().await?;
391+
392+
cases.push((op, output_handle));
393+
}
394+
395+
wait_until_all_allowed_handles_computed(&app).await?;
396+
let errors = errors_on_allowed_handles(&app).await?;
397+
for msg in &errors {
398+
assert!(
399+
msg.contains("ExecutionPanic"),
400+
"Expected error message to contain 'ExecutionPanic', but got: {msg}"
401+
);
402+
}
403+
assert_eq!(
404+
errors.len(),
405+
cases.len(),
406+
"Expected all computations to have errors, but some succeeded"
407+
);
408+
Ok(())
409+
}
410+
322411
fn unary_op_to_event(
323412
op: &UnaryOperatorTestCase,
324413
input: &Handle,

coprocessor/fhevm-engine/tfhe-worker/src/tests/test_cases.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use fhevm_engine_common::types::{is_ebytes_type, FheOperationType, SupportedFheO
66
use std::ops::Not;
77
use strum::IntoEnumIterator;
88

9+
#[derive(Clone, Debug)]
910
pub struct BinaryOperatorTestCase {
1011
pub bits: i32,
1112
pub operator: i32,
@@ -47,6 +48,32 @@ fn supported_bits_to_bit_type_in_db(inp: i32) -> i32 {
4748
}
4849
}
4950

51+
pub fn generate_panic_binary_test_cases() -> Vec<BinaryOperatorTestCase> {
52+
let mut new_cases = vec![];
53+
for mut op in generate_binary_test_cases() {
54+
if op.bits >= 256 {
55+
// avoid non supported scalar in test
56+
continue;
57+
}
58+
if !op.is_scalar {
59+
continue;
60+
}
61+
let operator = SupportedFheOperations::try_from(op.operator).unwrap();
62+
if op.operator != SupportedFheOperations::FheDiv as i32
63+
&& op.operator != SupportedFheOperations::FheRem as i32
64+
{
65+
continue;
66+
}
67+
let modulo = BigInt::from(1) << op.bits;
68+
op.lhs = BigInt::from(1) << (op.bits - 1); // max positive value for signed integer of op.bits bits
69+
op.rhs = modulo;
70+
op.expected_output = compute_expected_binary_output(&op.lhs, &op.rhs, operator)
71+
% (BigInt::from(1) << op.bits); // expected result
72+
new_cases.push(op);
73+
}
74+
new_cases
75+
}
76+
5077
pub fn generate_binary_test_cases() -> Vec<BinaryOperatorTestCase> {
5178
let mut cases = Vec::new();
5279
let bit_shift_ops = [

coprocessor/fhevm-engine/tfhe-worker/src/tests/utils.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,30 @@ async fn setup_test_app_custom_docker() -> Result<TestInstance, Box<dyn std::err
150150
})
151151
}
152152

153+
pub async fn errors_on_allowed_handles(
154+
test_instance: &TestInstance,
155+
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
156+
let pool = sqlx::postgres::PgPoolOptions::new()
157+
.max_connections(2)
158+
.connect(test_instance.db_url())
159+
.await?;
160+
let records = sqlx::query!(
161+
"SELECT error_message FROM computations WHERE is_allowed = TRUE AND is_error = TRUE",
162+
)
163+
.fetch_all(&pool)
164+
.await?;
165+
let mut errors: Vec<String> = vec![];
166+
for error in &records {
167+
errors.push(
168+
error
169+
.error_message
170+
.clone()
171+
.unwrap_or_else(|| "No error message".to_string()),
172+
);
173+
}
174+
Ok(errors)
175+
}
176+
153177
pub async fn wait_until_all_allowed_handles_computed(
154178
test_instance: &TestInstance,
155179
) -> Result<(), Box<dyn std::error::Error>> {

coprocessor/fhevm-engine/tfhe-worker/src/tfhe_worker.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,9 @@ async fn upload_transaction_graph_results<'a>(
557557
CoprocessorError::FhevmError(swap_val).into()
558558
} else {
559559
CoprocessorError::SchedulerError(
560-
*err.downcast_ref::<SchedulerError>()
561-
.unwrap_or(&SchedulerError::SchedulerError),
560+
err.downcast_ref::<SchedulerError>()
561+
.cloned()
562+
.unwrap_or(SchedulerError::SchedulerError),
562563
)
563564
.into()
564565
};

0 commit comments

Comments
 (0)