feat(server::evm::engine): return meaning on error path

This commit is contained in:
hdbg
2026-03-09 20:58:04 +01:00
parent 23f60cc98e
commit 1c7fe46595
2 changed files with 32 additions and 14 deletions

View File

@@ -24,28 +24,37 @@ use crate::{
pub mod policies;
mod utils;
/// Errors that can only occur once the transaction meaning is known (during policy evaluation)
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
pub enum VetError {
pub enum PolicyError {
#[error("Database connection pool error")]
#[diagnostic(code(arbiter_server::evm::vet_error::database_error))]
#[diagnostic(code(arbiter_server::evm::policy_error::pool))]
Pool(#[from] db::PoolError),
#[error("Database returned error")]
#[diagnostic(code(arbiter_server::evm::vet_error::database_error))]
#[diagnostic(code(arbiter_server::evm::policy_error::database))]
Database(#[from] diesel::result::Error),
#[error("Transaction violates policy: {0:?}")]
#[diagnostic(code(arbiter_server::evm::vet_error::policy_violation))]
#[diagnostic(code(arbiter_server::evm::policy_error::violation))]
Violations(Vec<EvalViolation>),
#[error("No matching grant found")]
#[diagnostic(code(arbiter_server::evm::vet_error::no_matching_grant))]
#[diagnostic(code(arbiter_server::evm::policy_error::no_matching_grant))]
NoMatchingGrant,
}
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
pub enum VetError {
#[error("Contract creation transactions are not supported")]
#[diagnostic(code(arbiter_server::evm::vet_error::contract_creation_unsupported))]
ContractCreationNotSupported,
#[error("Engine can't classify this transaction")]
#[diagnostic(code(arbiter_server::evm::vet_error::unsupported))]
UnsupportedTransactionType,
#[error("Policy evaluation failed: {1}")]
#[diagnostic(code(arbiter_server::evm::vet_error::evaluated))]
Evaluated(SpecificMeaning, #[source] PolicyError),
}
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
pub enum SignError {
#[error("Database connection pool error")]
@@ -89,16 +98,16 @@ impl Engine {
context: EvalContext,
meaning: &P::Meaning,
dry_run: bool,
) -> Result<(), VetError> {
) -> Result<(), PolicyError> {
let mut conn = self.db.get().await?;
let grant = P::try_find_grant(&context, &mut conn)
.await?
.ok_or(VetError::NoMatchingGrant)?;
.ok_or(PolicyError::NoMatchingGrant)?;
let violations = P::evaluate(&context, meaning, &grant, &mut conn).await?;
if !violations.is_empty() {
return Err(VetError::Violations(violations));
return Err(PolicyError::Violations(violations));
} else if !dry_run {
conn.transaction(|conn| {
Box::pin(async move {
@@ -190,7 +199,7 @@ impl Engine {
transaction: TxEip1559,
// don't log
dry_run: bool,
) -> Result<(), VetError> {
) -> Result<SpecificMeaning, VetError> {
let TxKind::Call(to) = transaction.to else {
return Err(VetError::ContractCreationNotSupported);
};
@@ -204,14 +213,22 @@ impl Engine {
};
if let Some(meaning) = EtherTransfer::analyze(&context) {
return self
return match self
.vet_transaction::<EtherTransfer>(context, &meaning, dry_run)
.await;
.await
{
Ok(()) => Ok(meaning.into()),
Err(e) => Err(VetError::Evaluated(meaning.into(), e)),
};
}
if let Some(meaning) = TokenTransfer::analyze(&context) {
return self
return match self
.vet_transaction::<TokenTransfer>(context, &meaning, dry_run)
.await;
.await
{
Ok(()) => Ok(meaning.into()),
Err(e) => Err(VetError::Evaluated(meaning.into(), e)),
};
}
Err(VetError::UnsupportedTransactionType)

View File

@@ -70,7 +70,7 @@ pub struct Grant<PolicySettings> {
pub trait Policy: Sized {
type Settings: Send + Sync + 'static + Into<SpecificGrant>;
type Meaning: Display + Send + Sync + 'static + Into<SpecificMeaning>;
type Meaning: Display + std::fmt::Debug + Send + Sync + 'static + Into<SpecificMeaning>;
fn analyze(context: &EvalContext) -> Option<Self::Meaning>;
@@ -114,6 +114,7 @@ pub enum ReceiverTarget {
}
// Classification of what transaction does
#[derive(Debug)]
pub enum SpecificMeaning {
EtherTransfer(ether_transfer::Meaning),
TokenTransfer(token_transfers::Meaning),