linera_execution/
transaction_tracker.rs1use std::vec;
5
6use linera_base::{
7 data_types::{Amount, ArithmeticError, OracleResponse},
8 ensure,
9 identifiers::ApplicationId,
10};
11
12use crate::{
13 ExecutionError, ExecutionOutcome, RawExecutionOutcome, SystemExecutionError, SystemMessage,
14};
15
16#[derive(Debug, Default)]
19pub struct TransactionTracker {
20 replaying_oracle_responses: Option<vec::IntoIter<OracleResponse>>,
21 oracle_responses: Vec<OracleResponse>,
22 outcomes: Vec<ExecutionOutcome>,
23 next_message_index: u32,
24}
25
26impl TransactionTracker {
27 pub fn new(next_message_index: u32, oracle_responses: Option<Vec<OracleResponse>>) -> Self {
28 TransactionTracker {
29 replaying_oracle_responses: oracle_responses.map(Vec::into_iter),
30 next_message_index,
31 oracle_responses: Vec::new(),
32 outcomes: Vec::new(),
33 }
34 }
35
36 pub fn next_message_index(&self) -> u32 {
37 self.next_message_index
38 }
39
40 pub fn add_system_outcome(
41 &mut self,
42 outcome: RawExecutionOutcome<SystemMessage, Amount>,
43 ) -> Result<(), ArithmeticError> {
44 self.add_outcome(ExecutionOutcome::System(outcome))
45 }
46
47 pub fn add_user_outcome(
48 &mut self,
49 application_id: ApplicationId,
50 outcome: RawExecutionOutcome<Vec<u8>, Amount>,
51 ) -> Result<(), ArithmeticError> {
52 self.add_outcome(ExecutionOutcome::User(application_id, outcome))
53 }
54
55 pub fn add_outcomes(
56 &mut self,
57 outcomes: impl IntoIterator<Item = ExecutionOutcome>,
58 ) -> Result<(), ArithmeticError> {
59 for outcome in outcomes {
60 self.add_outcome(outcome)?;
61 }
62 Ok(())
63 }
64
65 fn add_outcome(&mut self, outcome: ExecutionOutcome) -> Result<(), ArithmeticError> {
66 let message_count =
67 u32::try_from(outcome.message_count()).map_err(|_| ArithmeticError::Overflow)?;
68 self.next_message_index = self
69 .next_message_index
70 .checked_add(message_count)
71 .ok_or(ArithmeticError::Overflow)?;
72 self.outcomes.push(outcome);
73 Ok(())
74 }
75
76 pub fn add_oracle_response(&mut self, oracle_response: OracleResponse) {
77 self.oracle_responses.push(oracle_response);
78 }
79
80 pub fn replay_oracle_response(
83 &mut self,
84 oracle_response: OracleResponse,
85 ) -> Result<bool, SystemExecutionError> {
86 let replaying = if let Some(recorded_response) = self.next_replayed_oracle_response()? {
87 ensure!(
88 recorded_response == oracle_response,
89 SystemExecutionError::OracleResponseMismatch
90 );
91 true
92 } else {
93 false
94 };
95 self.add_oracle_response(oracle_response);
96 Ok(replaying)
97 }
98
99 pub fn next_replayed_oracle_response(
100 &mut self,
101 ) -> Result<Option<OracleResponse>, SystemExecutionError> {
102 let Some(responses) = &mut self.replaying_oracle_responses else {
103 return Ok(None); };
105 let response = responses
106 .next()
107 .ok_or_else(|| SystemExecutionError::MissingOracleResponse)?;
108 Ok(Some(response))
109 }
110
111 pub fn destructure(
112 self,
113 ) -> Result<(Vec<ExecutionOutcome>, Vec<OracleResponse>, u32), ExecutionError> {
114 let TransactionTracker {
115 replaying_oracle_responses,
116 oracle_responses,
117 outcomes,
118 next_message_index,
119 } = self;
120 if let Some(mut responses) = replaying_oracle_responses {
121 ensure!(
122 responses.next().is_none(),
123 ExecutionError::UnexpectedOracleResponse
124 );
125 }
126 Ok((outcomes, oracle_responses, next_message_index))
127 }
128
129 pub(crate) fn outcomes_mut(&mut self) -> &mut Vec<ExecutionOutcome> {
130 &mut self.outcomes
131 }
132}