u280_hardware_promoter/
result.rs1use crate::canonical::canonical_line;
4use crate::{FailureCode, PromotionError, PromotionResult, PromotionTransactionIdentity};
5use serde::Serialize;
6
7const FAILURE_KIND: &str = "hashsigs-u280-hardware-promotion-failure-v1";
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
10struct TerminalClaims {
11 hardware_execution: bool,
12 card_validated: bool,
13 cryptographic_outputs_valid: bool,
14 performance_validated: bool,
15 hardware_completion_promotable: bool,
16}
17
18impl TerminalClaims {
19 const fn failure() -> Self {
20 Self {
21 hardware_execution: false,
22 card_validated: false,
23 cryptographic_outputs_valid: false,
24 performance_validated: false,
25 hardware_completion_promotable: false,
26 }
27 }
28}
29
30#[derive(Clone, Debug, Serialize)]
33pub struct PromotionFailure {
34 schema: u64,
35 kind: &'static str,
36 transaction: PromotionTransactionIdentity,
37 failure_code: FailureCode,
38 error: String,
39 #[serde(flatten)]
40 terminal: TerminalClaims,
41}
42
43impl PromotionFailure {
44 #[must_use]
46 pub fn new(transaction: &PromotionTransactionIdentity, error: &PromotionError) -> Self {
47 Self {
48 schema: 1,
49 kind: FAILURE_KIND,
50 transaction: transaction.clone(),
51 failure_code: error.code(),
52 error: error.message().to_owned(),
53 terminal: TerminalClaims::failure(),
54 }
55 }
56}
57
58#[derive(Clone, Debug)]
67pub enum PromotionDocument {
68 Failure(PromotionFailure),
70}
71
72impl PromotionDocument {
73 #[must_use]
75 pub const fn transaction_identity(&self) -> &PromotionTransactionIdentity {
76 match self {
77 Self::Failure(failure) => &failure.transaction,
78 }
79 }
80
81 pub fn canonical_bytes(&self) -> PromotionResult<Vec<u8>> {
87 match self {
88 Self::Failure(failure) => canonical_line(failure),
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::{FAILURE_KIND, PromotionDocument, PromotionFailure};
96 use crate::journal::synthetic_identity;
97 use crate::{FailureCode, PromotionError};
98
99 #[test]
100 fn failure_serialization_has_five_false_terminal_claims() {
101 let error = PromotionError::new(FailureCode::RouteUnaccepted, "probe required");
102 let transaction = synthetic_identity(1).transaction_identity();
103 let document = PromotionDocument::Failure(PromotionFailure::new(&transaction, &error));
104 let value: serde_json::Value =
105 serde_json::from_slice(&document.canonical_bytes().unwrap()).unwrap();
106 for key in [
107 "hardware_execution",
108 "card_validated",
109 "cryptographic_outputs_valid",
110 "performance_validated",
111 "hardware_completion_promotable",
112 ] {
113 assert_eq!(value[key], false, "{key} was not false");
114 }
115 assert_eq!(value["kind"], FAILURE_KIND);
116 assert_eq!(value["failure_code"], "ROUTE_UNACCEPTED");
117 }
118}