1use anvil_zksync_common::sh_err;
2use chrono::{DateTime, Utc};
3use std::fmt;
4use std::future::Future;
5use std::sync::Arc;
6use tokio::runtime::Builder;
7use tokio::sync::{RwLock, RwLockReadGuard};
8use zksync_multivm::interface::{Call, CallType, ExecutionResult, VmExecutionResultAndLogs};
9use zksync_types::{
10 api::{BlockNumber, DebugCall, DebugCallType},
11 web3::Bytes,
12 Transaction, CONTRACT_DEPLOYER_ADDRESS, U256, U64,
13};
14use zksync_web3_decl::error::Web3Error;
15
16pub fn to_human_size(input: U256) -> String {
19 let input = format!("{:?}", input);
20 let tmp: Vec<_> = input
21 .chars()
22 .rev()
23 .enumerate()
24 .flat_map(|(index, val)| {
25 if index > 0 && index % 3 == 0 {
26 vec!['_', val]
27 } else {
28 vec![val]
29 }
30 })
31 .collect();
32 tmp.iter().rev().collect()
33}
34
35pub fn to_real_block_number(block_number: BlockNumber, latest_block_number: U64) -> U64 {
46 match block_number {
47 BlockNumber::FastFinalized
48 | BlockNumber::Finalized
49 | BlockNumber::Pending
50 | BlockNumber::Committed
51 | BlockNumber::L1Committed
52 | BlockNumber::Latest => latest_block_number,
53 BlockNumber::Earliest => U64::zero(),
54 BlockNumber::Number(n) => n,
55 }
56}
57
58pub fn create_debug_output(
60 tx: &Transaction,
61 result: &VmExecutionResultAndLogs,
62 traces: Vec<Call>,
63) -> Result<DebugCall, Web3Error> {
64 let calltype = if tx
65 .recipient_account()
66 .map(|addr| addr == CONTRACT_DEPLOYER_ADDRESS)
67 .unwrap_or_default()
68 {
69 DebugCallType::Create
70 } else {
71 DebugCallType::Call
72 };
73 match &result.result {
74 ExecutionResult::Success { output } => Ok(DebugCall {
75 gas_used: result.statistics.gas_used.into(),
76 output: output.clone().into(),
77 r#type: calltype,
78 from: tx.initiator_account(),
79 to: tx.recipient_account().unwrap_or_default(),
80 gas: tx.gas_limit(),
81 value: tx.execute.value,
82 input: tx.execute.calldata().into(),
83 error: None,
84 revert_reason: None,
85 calls: traces.into_iter().map(call_to_debug_call).collect(),
86 }),
87 ExecutionResult::Revert { output } => Ok(DebugCall {
88 gas_used: result.statistics.gas_used.into(),
89 output: output.encoded_data().into(),
90 r#type: calltype,
91 from: tx.initiator_account(),
92 to: tx.recipient_account().unwrap_or_default(),
93 gas: tx.gas_limit(),
94 value: tx.execute.value,
95 input: tx.execute.calldata().into(),
96 error: None,
97 revert_reason: Some(output.to_string()),
98 calls: traces.into_iter().map(call_to_debug_call).collect(),
99 }),
100 ExecutionResult::Halt { reason } => Err(Web3Error::SubmitTransactionError(
101 reason.to_string(),
102 vec![],
103 )),
104 }
105}
106
107fn call_to_debug_call(value: Call) -> DebugCall {
108 let calls = value.calls.into_iter().map(call_to_debug_call).collect();
109 let debug_type = match value.r#type {
110 CallType::Call(_) => DebugCallType::Call,
111 CallType::Create => DebugCallType::Create,
112 CallType::NearCall => unreachable!("We have to filter our near calls before"),
113 };
114 DebugCall {
115 r#type: debug_type,
116 from: value.from,
117 to: value.to,
118 gas: U256::from(value.gas),
119 gas_used: U256::from(value.gas_used),
120 value: value.value,
121 output: Bytes::from(value.output.clone()),
122 input: Bytes::from(value.input.clone()),
123 error: value.error.clone(),
124 revert_reason: value.revert_reason,
125 calls,
126 }
127}
128
129pub fn utc_datetime_from_epoch_ms(millis: u64) -> DateTime<Utc> {
131 let secs = millis / 1000;
132 let nanos = (millis % 1000) * 1_000_000;
133 DateTime::<Utc>::from_timestamp(secs as i64, nanos as u32).expect("valid timestamp")
135}
136
137#[derive(Debug)]
139pub(crate) struct TransparentError(pub String);
140
141impl fmt::Display for TransparentError {
142 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
143 formatter.write_str(&self.0)
144 }
145}
146
147impl std::error::Error for TransparentError {}
148
149impl From<TransparentError> for Web3Error {
150 fn from(err: TransparentError) -> Self {
151 Self::InternalError(err.into())
152 }
153}
154
155pub fn internal_error(method_name: &'static str, error: impl fmt::Display) -> Web3Error {
156 sh_err!("Internal error in method {method_name}: {error}");
157 Web3Error::InternalError(anyhow::Error::msg(error.to_string()))
158}
159
160pub fn block_on<F: Future + Send + 'static>(future: F) -> F::Output
161where
162 F::Output: Send,
163{
164 std::thread::spawn(move || {
165 let runtime = Builder::new_current_thread()
166 .enable_all()
167 .build()
168 .expect("tokio runtime creation failed");
169 runtime.block_on(future)
170 })
171 .join()
172 .unwrap()
173}
174
175#[derive(Debug)]
177pub struct ArcRLock<T>(Arc<RwLock<T>>);
178
179impl<T> Clone for ArcRLock<T> {
180 fn clone(&self) -> Self {
181 ArcRLock(self.0.clone())
182 }
183}
184
185impl<T> ArcRLock<T> {
186 pub fn wrap(inner: Arc<RwLock<T>>) -> Self {
188 Self(inner)
189 }
190
191 pub async fn read(&self) -> RwLockReadGuard<T> {
194 self.0.read().await
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use zksync_types::U256;
201
202 use super::*;
203
204 #[test]
205 fn test_utc_datetime_from_epoch_ms() {
206 let actual = utc_datetime_from_epoch_ms(1623931200000);
207 assert_eq!(DateTime::from_timestamp(1623931200, 0).unwrap(), actual);
208 }
209
210 #[test]
211 fn test_human_sizes() {
212 assert_eq!("123", to_human_size(U256::from(123u64)));
213 assert_eq!("1_234", to_human_size(U256::from(1234u64)));
214 assert_eq!("12_345", to_human_size(U256::from(12345u64)));
215 assert_eq!("0", to_human_size(U256::from(0)));
216 assert_eq!("1", to_human_size(U256::from(1)));
217 assert_eq!("50_000_000", to_human_size(U256::from(50000000u64)));
218 }
219
220 #[test]
221 fn test_to_real_block_number_finalized() {
222 let actual = to_real_block_number(BlockNumber::Finalized, U64::from(10));
223 assert_eq!(U64::from(10), actual);
224 }
225
226 #[test]
227 fn test_to_real_block_number_pending() {
228 let actual = to_real_block_number(BlockNumber::Pending, U64::from(10));
229 assert_eq!(U64::from(10), actual);
230 }
231
232 #[test]
233 fn test_to_real_block_number_committed() {
234 let actual = to_real_block_number(BlockNumber::Committed, U64::from(10));
235 assert_eq!(U64::from(10), actual);
236 }
237
238 #[test]
239 fn test_to_real_block_number_latest() {
240 let actual = to_real_block_number(BlockNumber::Latest, U64::from(10));
241 assert_eq!(U64::from(10), actual);
242 }
243
244 #[test]
245 fn test_to_real_block_number_earliest() {
246 let actual = to_real_block_number(BlockNumber::Earliest, U64::from(10));
247 assert_eq!(U64::zero(), actual);
248 }
249
250 #[test]
251 fn test_to_real_block_number_number() {
252 let actual = to_real_block_number(BlockNumber::Number(U64::from(5)), U64::from(10));
253 assert_eq!(U64::from(5), actual);
254 }
255}