Skip to main content

ferrum_interfaces/vnext/event/
foundation.rs

1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use std::fmt;
4
5use super::{ContractVersion, VNextError};
6
7pub const EXECUTION_IDENTITY_VERSION: ContractVersion = ContractVersion::new(3, 0);
8pub const MAX_EXECUTION_EVENT_WIRE_BYTES: usize = 1024 * 1024;
9pub const MAX_REPLAY_IDENTITY_WIRE_BYTES: usize = 1024 * 1024;
10pub const MAX_RESOURCE_POOL_EVENT_WIRE_BYTES: usize = 16 * 1024 * 1024;
11
12pub(super) fn invalid_event(reason: impl Into<String>) -> VNextError {
13    VNextError::InvalidExecutionPlan {
14        reason: reason.into(),
15    }
16}
17
18pub(super) fn canonical_fingerprint(value: &impl Serialize) -> String {
19    format!(
20        "{:x}",
21        Sha256::digest(serde_json::to_vec(value).expect("trusted event evidence must serialize"))
22    )
23}
24
25pub(super) fn sha256_bytes(bytes: &[u8]) -> String {
26    format!("{:x}", Sha256::digest(bytes))
27}
28
29pub(super) fn validate_sha256(value: &str, label: &str) -> Result<(), VNextError> {
30    if value.len() != 64
31        || !value
32            .bytes()
33            .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
34    {
35        return Err(invalid_event(format!(
36            "{label} must be a canonical lowercase SHA256"
37        )));
38    }
39    Ok(())
40}
41
42macro_rules! nonzero_execution_id {
43    ($name:ident, $label:literal) => {
44        #[derive(
45            Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
46        )]
47        #[serde(try_from = "u64", into = "u64")]
48        pub struct $name(u64);
49
50        impl $name {
51            pub const fn get(self) -> u64 {
52                self.0
53            }
54        }
55
56        impl TryFrom<u64> for $name {
57            type Error = VNextError;
58
59            fn try_from(value: u64) -> Result<Self, Self::Error> {
60                if value == 0 {
61                    return Err(invalid_event(concat!($label, " must be non-zero")));
62                }
63                Ok(Self(value))
64            }
65        }
66
67        impl From<$name> for u64 {
68            fn from(value: $name) -> Self {
69                value.0
70            }
71        }
72
73        impl fmt::Display for $name {
74            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75                write!(formatter, "{}", self.0)
76            }
77        }
78    };
79}
80
81nonzero_execution_id!(ExecutionFrameId, "execution frame id");
82nonzero_execution_id!(BatchStepId, "batch step id");
83nonzero_execution_id!(BatchInvocationId, "batch invocation id");
84nonzero_execution_id!(NodeInvocationId, "node invocation id");
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
87#[serde(rename_all = "snake_case")]
88pub enum ExecutionEventKind {
89    RequestAccepted,
90    PlanBuilt,
91    FrameStarted,
92    NodeStarted,
93    OperationSubmitted,
94    NodeRetired,
95    FrameCompleted,
96    FailureObserved,
97    SequenceCompleted,
98    SequenceAborted,
99    RequestCompleted,
100    RequestFailed,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(rename_all = "snake_case")]
105pub enum ExecutionPhase {
106    Resolution,
107    Planning,
108    Execution,
109    Completion,
110}
111
112impl ExecutionPhase {
113    pub(super) const fn rank(self) -> u8 {
114        match self {
115            Self::Resolution => 0,
116            Self::Planning => 1,
117            Self::Execution => 2,
118            Self::Completion => 3,
119        }
120    }
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
124#[serde(deny_unknown_fields)]
125pub struct MonotonicTimestamp {
126    pub nanos_since_run_start: u64,
127}