migrate from anyhow to thiserror (#197)
* migrate from anyhow to thiserror (#190). pending polish error msgs * Add backtrace and compartmentalize errors - Include backtraces in the errors we generate. To get this we can't just return a literal enum, because the backtrace requires a call. - Related to the previous point: add methods to create errors so we can include the backtrace conveniently without changing too much the syntax. So instead of `Err(Error::KeyNotFound(key))` (literal enum) it will be `Err(Error::key_not_found(key))` (method call) - Each error should be local to its scope, and each scope should only return its own error. - The merkle tree should return `TreeError` and not Error - The middleware should return `MiddlewareError` and not Error - With a global Error we can't easily include backend/frontend types in the error fields, so declare a `BackendError` and a `FrontendError` and follow the pattern from the previous point - The Pod traits should be able to return backend errors and will be used in the frontend; for that we change them to use trait object Error: `dyn std::error::Error` * fix error * apply suggestions from @arnaucube * rename XError and XResult to Error and Result * reorg signature * make frontend custom error more ergonomic * remove unnecessary feature --------- Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
parent
58d3c6a236
commit
29545f03fc
31 changed files with 696 additions and 273 deletions
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
use std::{collections::HashMap, convert::From, fmt};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -14,9 +13,11 @@ use crate::middleware::{
|
|||
};
|
||||
|
||||
mod custom;
|
||||
mod error;
|
||||
mod operation;
|
||||
mod serialization;
|
||||
pub use custom::*;
|
||||
pub use error::*;
|
||||
pub use operation::*;
|
||||
use serialization::*;
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ impl SignedPod {
|
|||
self.pod.id()
|
||||
}
|
||||
pub fn verify(&self) -> Result<()> {
|
||||
self.pod.verify()
|
||||
self.pod.verify().map_err(Error::Backend)
|
||||
}
|
||||
pub fn kvs(&self) -> &HashMap<Key, Value> {
|
||||
&self.kvs
|
||||
|
|
@ -276,11 +277,17 @@ impl MainPodBuilder {
|
|||
let container =
|
||||
op.1.get(0)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(anyhow!("Invalid container argument for op {}.", op))?;
|
||||
.ok_or(Error::custom(format!(
|
||||
"Invalid container argument for op {}.",
|
||||
op
|
||||
)))?;
|
||||
let key =
|
||||
op.1.get(1)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(anyhow!("Invalid key argument for op {}.", op))?;
|
||||
.ok_or(Error::custom(format!(
|
||||
"Invalid key argument for op {}.",
|
||||
op
|
||||
)))?;
|
||||
let proof = if op_type == &Native(ContainsFromEntries) {
|
||||
container.prove_existence(key)?.1
|
||||
} else {
|
||||
|
|
@ -292,7 +299,7 @@ impl MainPodBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn op(&mut self, public: bool, op: Operation) -> Result<Statement, anyhow::Error> {
|
||||
fn op(&mut self, public: bool, op: Operation) -> Result<Statement> {
|
||||
use NativeOperation::*;
|
||||
let mut op = Self::fill_in_aux(Self::lower_op(op))?;
|
||||
let Operation(op_type, ref mut args, _) = &mut op;
|
||||
|
|
@ -301,7 +308,7 @@ impl MainPodBuilder {
|
|||
// We are dealing with a copy here.
|
||||
match (args).first() {
|
||||
Some(OperationArg::Statement(s)) if args.len() == 1 => Ok(s.predicate().clone()),
|
||||
_ => Err(anyhow!("Invalid arguments to copy operation: {:?}", args)),
|
||||
_ => Err(Error::op_invalid_args("copy".to_string())),
|
||||
}
|
||||
})?;
|
||||
|
||||
|
|
@ -312,7 +319,7 @@ impl MainPodBuilder {
|
|||
CopyStatement => match &args[0] {
|
||||
OperationArg::Statement(s) => s.args().clone(),
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to copy operation: {}", op));
|
||||
return Err(Error::op_invalid_args("copy".to_string()));
|
||||
}
|
||||
},
|
||||
EqualFromEntries => self.op_args_entries(public, args)?,
|
||||
|
|
@ -331,14 +338,14 @@ impl MainPodBuilder {
|
|||
if ak1 == ak2 {
|
||||
vec![StatementArg::Key(ak0), StatementArg::Key(ak3)]
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Invalid arguments to transitive equality operation"
|
||||
return Err(Error::op_invalid_args(
|
||||
"transitivity equality".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(
|
||||
"Invalid arguments to transitive equality operation"
|
||||
return Err(Error::op_invalid_args(
|
||||
"transitivity equality".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -348,7 +355,7 @@ impl MainPodBuilder {
|
|||
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to gt-to-neq operation"));
|
||||
return Err(Error::op_invalid_args("gt-to-neq".to_string()));
|
||||
}
|
||||
},
|
||||
LtToNotEqual => match args[0].clone() {
|
||||
|
|
@ -356,7 +363,7 @@ impl MainPodBuilder {
|
|||
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to lt-to-neq operation"));
|
||||
return Err(Error::op_invalid_args("lt-to-neq".to_string()));
|
||||
}
|
||||
},
|
||||
SumOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||
|
|
@ -375,11 +382,11 @@ impl MainPodBuilder {
|
|||
StatementArg::Key(ak2),
|
||||
]
|
||||
} else {
|
||||
return Err(anyhow!("Invalid arguments to sum-of operation"));
|
||||
return Err(Error::op_invalid_args("sum-of".to_string()));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to sum-of operation"));
|
||||
return Err(Error::op_invalid_args("sum-of".to_string()));
|
||||
}
|
||||
},
|
||||
ProductOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||
|
|
@ -398,11 +405,11 @@ impl MainPodBuilder {
|
|||
StatementArg::Key(ak2),
|
||||
]
|
||||
} else {
|
||||
return Err(anyhow!("Invalid arguments to product-of operation"));
|
||||
return Err(Error::op_invalid_args("product-of".to_string()));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to product-of operation"));
|
||||
return Err(Error::op_invalid_args("product-of".to_string()));
|
||||
}
|
||||
},
|
||||
MaxOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||
|
|
@ -421,11 +428,11 @@ impl MainPodBuilder {
|
|||
StatementArg::Key(ak2),
|
||||
]
|
||||
} else {
|
||||
return Err(anyhow!("Invalid arguments to max-of operation"));
|
||||
return Err(Error::op_invalid_args("max-of".to_string()));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid arguments to max-of operation"));
|
||||
return Err(Error::op_invalid_args("max-of".to_string()));
|
||||
}
|
||||
},
|
||||
ContainsFromEntries => self.op_args_entries(public, args)?,
|
||||
|
|
@ -441,17 +448,17 @@ impl MainPodBuilder {
|
|||
OperationType::Custom(cpr) => {
|
||||
let pred = &cpr.batch.predicates[cpr.index];
|
||||
if pred.statements.len() != args.len() {
|
||||
return Err(anyhow!(
|
||||
return Err(Error::custom(format!(
|
||||
"Custom predicate operation needs {} statements but has {}.",
|
||||
pred.statements.len(),
|
||||
args.len()
|
||||
));
|
||||
)));
|
||||
}
|
||||
// All args should be statements to be pattern matched against statement templates.
|
||||
let args = args.iter().map(
|
||||
|a| match a {
|
||||
OperationArg::Statement(s) => Ok(s.clone()),
|
||||
_ => Err(anyhow!("Invalid argument {} to operation corresponding to custom predicate {:?}.", a, cpr))
|
||||
_ => Err(Error::custom(format!("Invalid argument {} to operation corresponding to custom predicate {:?}.", a, cpr)))
|
||||
}
|
||||
).collect::<Result<Vec<_>>>()?;
|
||||
|
||||
|
|
@ -462,7 +469,7 @@ impl MainPodBuilder {
|
|||
for (st_tmpl_arg, st_arg) in st_tmpl.args.iter().zip(&st_args) {
|
||||
if !check_st_tmpl(st_tmpl_arg, st_arg, &mut wildcard_map) {
|
||||
// TODO: Add wildcard_map in the error for better context
|
||||
return Err(anyhow!("{} doesn't match {}", st, st_tmpl));
|
||||
return Err(Error::statements_dont_match(st.clone(), st_tmpl.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -563,7 +570,11 @@ impl MainPodBuilder {
|
|||
}
|
||||
_ => None,
|
||||
})
|
||||
.ok_or(anyhow!("Missing POD type information in POD: {:?}", pod))?;
|
||||
.ok_or(Error::custom(format!(
|
||||
// TODO use a specific Error
|
||||
"Missing POD type information in POD: {:?}",
|
||||
pod
|
||||
)))?;
|
||||
// Replace instances of `SELF` with the POD ID for consistency
|
||||
// with `pub_statements` method.
|
||||
let public_statements = [type_statement]
|
||||
|
|
@ -676,7 +687,7 @@ impl MainPodCompiler {
|
|||
op.1.iter()
|
||||
.flat_map(|arg| self.compile_op_arg(arg))
|
||||
.collect_vec();
|
||||
middleware::Operation::op(op.0.clone(), &mop_args, &op.2)
|
||||
Ok(middleware::Operation::op(op.0.clone(), &mop_args, &op.2)?)
|
||||
}
|
||||
|
||||
fn compile_st_op(&mut self, st: &Statement, op: &Operation, params: &Params) -> Result<()> {
|
||||
|
|
@ -684,11 +695,10 @@ impl MainPodCompiler {
|
|||
let is_correct = middle_op.check(params, st)?;
|
||||
if !is_correct {
|
||||
// todo: improve error handling
|
||||
Err(anyhow!(
|
||||
Err(Error::custom(format!(
|
||||
"Compile failed due to invalid deduction:\n {} ⇏ {}",
|
||||
middle_op,
|
||||
st
|
||||
))
|
||||
middle_op, st
|
||||
)))
|
||||
} else {
|
||||
self.push_st_op(st.clone(), middle_op);
|
||||
Ok(())
|
||||
|
|
@ -822,11 +832,10 @@ pub mod tests {
|
|||
if kvs == embedded_kvs {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
Err(Error::custom(format!(
|
||||
"KVs {:?} do not agree with those embedded in the POD: {:?}",
|
||||
kvs,
|
||||
embedded_kvs
|
||||
))
|
||||
kvs, embedded_kvs
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue