1use openmina_core::log::{
2 inner::{
3 field::{display, DisplayValue},
4 Value,
5 },
6 time_to_str, ActionEvent, EventContext,
7};
8use p2p::{
9 connection::P2pConnectionEffectfulAction, P2pNetworkConnectionError, P2pNetworkSchedulerAction,
10 PeerId,
11};
12
13use crate::{
14 p2p::{
15 channels::P2pChannelsAction, connection::P2pConnectionAction, network::P2pNetworkAction,
16 P2pAction,
17 },
18 snark::SnarkAction,
19 transition_frontier::candidate::TransitionFrontierCandidateAction,
20 Action, ActionWithMetaRef, BlockProducerAction, Service, Store, TransitionFrontierAction,
21};
22
23struct ActionLoggerContext {
24 time: redux::Timestamp,
25 time_str: String,
26 node_id: DisplayValue<PeerId>,
27 log_node_id: bool,
28}
29
30impl ActionLoggerContext {
31 fn new(time: redux::Timestamp, node_id: PeerId, log_node_id: bool) -> Self {
32 ActionLoggerContext {
33 time,
34 time_str: time_to_str(time),
35 node_id: display(node_id),
36 log_node_id,
37 }
38 }
39}
40
41impl EventContext for ActionLoggerContext {
42 fn timestamp(&self) -> redux::Timestamp {
43 self.time
44 }
45
46 fn time(&self) -> &'_ dyn Value {
47 &self.time_str
48 }
49
50 fn log_node_id(&self) -> bool {
51 self.log_node_id
52 }
53
54 fn node_id(&self) -> &'_ dyn Value {
55 &self.node_id
56 }
57}
58
59pub fn logger_effects<S: Service>(store: &Store<S>, action: ActionWithMetaRef<'_>) {
60 let (action, meta) = action.split();
61 let context = ActionLoggerContext::new(
62 meta.time(),
63 store.state().p2p.my_id(),
64 store.state().should_log_node_id(),
65 );
66
67 match action {
68 Action::P2p(action) => match action {
69 P2pAction::Initialization(action) => action.action_event(&context),
70 P2pAction::Connection(action) => match action {
71 P2pConnectionAction::Outgoing(action) => action.action_event(&context),
72 P2pConnectionAction::Incoming(action) => action.action_event(&context),
73 },
74 P2pAction::Disconnection(action) => action.action_event(&context),
75 P2pAction::Identify(action) => action.action_event(&context),
76 P2pAction::Channels(action) => match action {
77 P2pChannelsAction::MessageReceived(action) => action.action_event(&context),
78 P2pChannelsAction::SignalingDiscovery(action) => action.action_event(&context),
79 P2pChannelsAction::SignalingExchange(action) => action.action_event(&context),
80 P2pChannelsAction::BestTip(action) => action.action_event(&context),
81 P2pChannelsAction::Transaction(action) => action.action_event(&context),
82 P2pChannelsAction::Snark(action) => action.action_event(&context),
83 P2pChannelsAction::SnarkJobCommitment(action) => action.action_event(&context),
84 P2pChannelsAction::Rpc(action) => action.action_event(&context),
85 P2pChannelsAction::StreamingRpc(action) => action.action_event(&context),
86 },
87 P2pAction::Peer(action) => action.action_event(&context),
88 P2pAction::Network(action) => match action {
89 P2pNetworkAction::Scheduler(action) => match action {
90 P2pNetworkSchedulerAction::Error {
92 error: P2pNetworkConnectionError::MioError(summary),
93 addr,
94 } => {
95 openmina_core::action_debug!(
96 context,
97 kind = "P2pNetworkSchedulerError",
98 summary = display(summary),
99 addr = display(addr)
100 );
101 }
102 action => action.action_event(&context),
103 },
104 P2pNetworkAction::Pnet(action) => action.action_event(&context),
105 P2pNetworkAction::Select(action) => action.action_event(&context),
106 P2pNetworkAction::Noise(action) => action.action_event(&context),
107 P2pNetworkAction::Yamux(action) => action.action_event(&context),
108 P2pNetworkAction::Rpc(action) => action.action_event(&context),
109 P2pNetworkAction::Kad(action) => action.action_event(&context),
110 P2pNetworkAction::Pubsub(action) => action.action_event(&context),
111 P2pNetworkAction::Identify(action) => action.action_event(&context),
112 },
113 },
114 Action::P2pEffectful(action) => match action {
115 p2p::P2pEffectfulAction::Channels(action) => action.action_event(&context),
116 p2p::P2pEffectfulAction::Connection(action) => match action {
117 P2pConnectionEffectfulAction::Outgoing(action) => action.action_event(&context),
118 P2pConnectionEffectfulAction::Incoming(action) => action.action_event(&context),
119 },
120 p2p::P2pEffectfulAction::Disconnection(action) => action.action_event(&context),
121 p2p::P2pEffectfulAction::Network(action) => action.action_event(&context),
122 p2p::P2pEffectfulAction::Initialize => {}
123 },
124 Action::ExternalSnarkWorker(action) => action.action_event(&context),
125 Action::SnarkPool(action) => action.action_event(&context),
126 Action::Snark(SnarkAction::WorkVerify(a)) => a.action_event(&context),
127 Action::Snark(SnarkAction::UserCommandVerify(a)) => a.action_event(&context),
128 Action::TransitionFrontier(a) => match a {
129 TransitionFrontierAction::Candidate(
130 TransitionFrontierCandidateAction::BlockReceived { block, chain_proof },
131 ) => {
132 openmina_core::action_info!(
133 context,
134 kind = action.kind().to_string(),
135 summary = "candidate block received",
136 block_hash = block.hash().to_string(),
137 block_height = block.height(),
138 has_chain_proof = chain_proof.is_some(),
139 );
140 }
141 TransitionFrontierAction::Synced { .. } => {
142 let tip = store.state().transition_frontier.best_tip().unwrap();
143
144 if store.state().block_producer.is_produced_by_me(tip) {
145 openmina_core::action_info!(
146 context,
147 kind = "BlockProducerBlockIntegrated",
148 summary = "produced block integrated into frontier",
149 block_hash = tip.hash().to_string(),
150 block_height = tip.height(),
151 );
152 }
153
154 openmina_core::action_info!(
155 context,
156 kind = action.kind().to_string(),
157 summary = "transition frontier synced",
158 block_hash = tip.hash().to_string(),
159 block_height = tip.height(),
160 );
161 }
162 TransitionFrontierAction::SyncFailed { best_tip, error } => {
163 openmina_core::action_error!(
164 context,
165 kind = action.kind().to_string(),
166 summary = "transition frontier failed to sync",
167 block_hash = best_tip.hash().to_string(),
168 block_height = best_tip.height(),
169 error = error.to_string(),
170 );
171 }
172 a => a.action_event(&context),
173 },
174 Action::BlockProducer(a) => match a {
175 BlockProducerAction::BlockProduced => {
176 let block = store.state().block_producer.produced_block().unwrap();
177 openmina_core::action_info!(
178 context,
179 kind = action.kind().to_string(),
180 summary = "produced a block",
181 block_hash = block.hash().to_string(),
182 block_height = block.height(),
183 );
184 }
185 BlockProducerAction::BlockInjected => {
186 let block = store.state().transition_frontier.sync.best_tip().unwrap();
187 openmina_core::action_info!(
188 context,
189 kind = action.kind().to_string(),
190 summary = "produced block injected",
191 block_hash = block.hash().to_string(),
192 block_height = block.height(),
193 );
194 }
195 a => a.action_event(&context),
196 },
197 Action::Rpc(a) => a.action_event(&context),
198 Action::TransactionPool(a) => a.action_event(&context),
199 _ => {}
200 }
201}