feat(server::evm::engine): return meaning on error path
This commit is contained in:
@@ -24,28 +24,37 @@ use crate::{
|
|||||||
pub mod policies;
|
pub mod policies;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
/// Errors that can only occur once the transaction meaning is known (during policy evaluation)
|
||||||
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
|
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
|
||||||
pub enum VetError {
|
pub enum PolicyError {
|
||||||
#[error("Database connection pool error")]
|
#[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),
|
Pool(#[from] db::PoolError),
|
||||||
#[error("Database returned error")]
|
#[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),
|
Database(#[from] diesel::result::Error),
|
||||||
#[error("Transaction violates policy: {0:?}")]
|
#[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>),
|
Violations(Vec<EvalViolation>),
|
||||||
#[error("No matching grant found")]
|
#[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,
|
NoMatchingGrant,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
|
||||||
|
pub enum VetError {
|
||||||
#[error("Contract creation transactions are not supported")]
|
#[error("Contract creation transactions are not supported")]
|
||||||
#[diagnostic(code(arbiter_server::evm::vet_error::contract_creation_unsupported))]
|
#[diagnostic(code(arbiter_server::evm::vet_error::contract_creation_unsupported))]
|
||||||
ContractCreationNotSupported,
|
ContractCreationNotSupported,
|
||||||
#[error("Engine can't classify this transaction")]
|
#[error("Engine can't classify this transaction")]
|
||||||
#[diagnostic(code(arbiter_server::evm::vet_error::unsupported))]
|
#[diagnostic(code(arbiter_server::evm::vet_error::unsupported))]
|
||||||
UnsupportedTransactionType,
|
UnsupportedTransactionType,
|
||||||
|
#[error("Policy evaluation failed: {1}")]
|
||||||
|
#[diagnostic(code(arbiter_server::evm::vet_error::evaluated))]
|
||||||
|
Evaluated(SpecificMeaning, #[source] PolicyError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
|
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
|
||||||
pub enum SignError {
|
pub enum SignError {
|
||||||
#[error("Database connection pool error")]
|
#[error("Database connection pool error")]
|
||||||
@@ -89,16 +98,16 @@ impl Engine {
|
|||||||
context: EvalContext,
|
context: EvalContext,
|
||||||
meaning: &P::Meaning,
|
meaning: &P::Meaning,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> Result<(), VetError> {
|
) -> Result<(), PolicyError> {
|
||||||
let mut conn = self.db.get().await?;
|
let mut conn = self.db.get().await?;
|
||||||
|
|
||||||
let grant = P::try_find_grant(&context, &mut conn)
|
let grant = P::try_find_grant(&context, &mut conn)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(VetError::NoMatchingGrant)?;
|
.ok_or(PolicyError::NoMatchingGrant)?;
|
||||||
|
|
||||||
let violations = P::evaluate(&context, meaning, &grant, &mut conn).await?;
|
let violations = P::evaluate(&context, meaning, &grant, &mut conn).await?;
|
||||||
if !violations.is_empty() {
|
if !violations.is_empty() {
|
||||||
return Err(VetError::Violations(violations));
|
return Err(PolicyError::Violations(violations));
|
||||||
} else if !dry_run {
|
} else if !dry_run {
|
||||||
conn.transaction(|conn| {
|
conn.transaction(|conn| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@@ -190,7 +199,7 @@ impl Engine {
|
|||||||
transaction: TxEip1559,
|
transaction: TxEip1559,
|
||||||
// don't log
|
// don't log
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> Result<(), VetError> {
|
) -> Result<SpecificMeaning, VetError> {
|
||||||
let TxKind::Call(to) = transaction.to else {
|
let TxKind::Call(to) = transaction.to else {
|
||||||
return Err(VetError::ContractCreationNotSupported);
|
return Err(VetError::ContractCreationNotSupported);
|
||||||
};
|
};
|
||||||
@@ -204,14 +213,22 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(meaning) = EtherTransfer::analyze(&context) {
|
if let Some(meaning) = EtherTransfer::analyze(&context) {
|
||||||
return self
|
return match self
|
||||||
.vet_transaction::<EtherTransfer>(context, &meaning, dry_run)
|
.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) {
|
if let Some(meaning) = TokenTransfer::analyze(&context) {
|
||||||
return self
|
return match self
|
||||||
.vet_transaction::<TokenTransfer>(context, &meaning, dry_run)
|
.vet_transaction::<TokenTransfer>(context, &meaning, dry_run)
|
||||||
.await;
|
.await
|
||||||
|
{
|
||||||
|
Ok(()) => Ok(meaning.into()),
|
||||||
|
Err(e) => Err(VetError::Evaluated(meaning.into(), e)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(VetError::UnsupportedTransactionType)
|
Err(VetError::UnsupportedTransactionType)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ pub struct Grant<PolicySettings> {
|
|||||||
|
|
||||||
pub trait Policy: Sized {
|
pub trait Policy: Sized {
|
||||||
type Settings: Send + Sync + 'static + Into<SpecificGrant>;
|
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>;
|
fn analyze(context: &EvalContext) -> Option<Self::Meaning>;
|
||||||
|
|
||||||
@@ -114,6 +114,7 @@ pub enum ReceiverTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Classification of what transaction does
|
// Classification of what transaction does
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum SpecificMeaning {
|
pub enum SpecificMeaning {
|
||||||
EtherTransfer(ether_transfer::Meaning),
|
EtherTransfer(ether_transfer::Meaning),
|
||||||
TokenTransfer(token_transfers::Meaning),
|
TokenTransfer(token_transfers::Meaning),
|
||||||
|
|||||||
Reference in New Issue
Block a user