essential_check/
predicate.rs

1//! Items related to the validation of [`Predicate`]s.
2
3use crate::sign::secp256k1;
4#[cfg(feature = "tracing")]
5use essential_hash::content_addr;
6use essential_types::{contract, predicate::Predicate};
7use thiserror::Error;
8
9/// [`check_signed_contract`] error.
10#[derive(Debug, Error)]
11pub enum InvalidSignedContract {
12    /// Failed to validate the signature over the contract.
13    #[error("invalid signature: {0}")]
14    Signature(#[from] secp256k1::Error),
15    /// The contract was invalid.
16    #[error("invalid contract: {0}")]
17    Set(#[from] InvalidContract),
18}
19
20/// [`check_contract`] error.
21#[derive(Debug, Error)]
22pub enum InvalidContract {
23    /// The number of predicates in the contract exceeds the limit.
24    #[error("the number of predicates ({0}) exceeds the limit ({MAX_PREDICATES})")]
25    TooManyPredicates(usize),
26    /// The predicate at the given index was invalid.
27    #[error("predicate at index {0} is invalid: {1}")]
28    Predicate(usize, InvalidPredicate),
29}
30
31/// [`check`] error.
32#[derive(Debug, Error)]
33pub enum InvalidPredicate {
34    /// The number of nodes in the predicate exceeds the limit.
35    #[error(
36        "the number of nodes ({0}) exceeds the limit ({})",
37        Predicate::MAX_NODES
38    )]
39    TooManyNodes(usize),
40    /// The number of edges in the predicate exceeds the limit.
41    #[error(
42        "the number of edges ({0}) exceeds the limit ({})",
43        Predicate::MAX_EDGES
44    )]
45    TooManyEdges(usize),
46}
47
48/// Maximum number of predicates in a contract.
49pub const MAX_PREDICATES: usize = 100;
50
51/// Validate a signed contract of predicates.
52///
53/// Verifies the signature and then validates the contract.
54#[cfg_attr(feature = "tracing", tracing::instrument(skip_all, fields(addr = %content_addr(&signed_contract.contract)), err))]
55pub fn check_signed_contract(
56    signed_contract: &contract::SignedContract,
57) -> Result<(), InvalidSignedContract> {
58    essential_sign::contract::verify(signed_contract)?;
59    check_contract(signed_contract.contract.as_ref())?;
60    Ok(())
61}
62
63/// Validate a contract of predicates.
64///
65/// Checks the size of the contract and then validates each predicate.
66pub fn check_contract(predicates: &[Predicate]) -> Result<(), InvalidContract> {
67    if predicates.len() > MAX_PREDICATES {
68        return Err(InvalidContract::TooManyPredicates(predicates.len()));
69    }
70    for (ix, predicate) in predicates.iter().enumerate() {
71        check(predicate).map_err(|e| InvalidContract::Predicate(ix, e))?;
72    }
73    Ok(())
74}
75
76/// Validate a single predicate.
77///
78/// Validates the slots, state reads, and constraints.
79pub fn check(predicate: &Predicate) -> Result<(), InvalidPredicate> {
80    if predicate.nodes.len() > Predicate::MAX_NODES.into() {
81        return Err(InvalidPredicate::TooManyNodes(predicate.nodes.len()));
82    }
83    if predicate.edges.len() > Predicate::MAX_EDGES.into() {
84        return Err(InvalidPredicate::TooManyEdges(predicate.edges.len()));
85    }
86    // FIXME: Update this to check DAG validity.
87    Ok(())
88}