ferrum_interfaces/vnext/event/
foundation.rs1use 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}