Skip to main content

anvil_polkadot/api_server/
revive_conversions.rs

1use alloy_eips::{BlockId, BlockNumberOrTag};
2use alloy_primitives::{Address, B256};
3use alloy_rpc_types::{
4    AccessList, FilterBlockOption, FilterSet, SignedAuthorization, Topic, TransactionRequest,
5    trace::geth::{
6        AccountState, CallFrame, CallLogFrame, DiffMode, GethDebugBuiltInTracerType,
7        GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace,
8        PreStateFrame, PreStateMode,
9    },
10};
11use polkadot_sdk::{
12    pallet_revive::evm::{
13        self, AccessListEntry, AddressOrAddresses, AuthorizationListEntry, BlockNumberOrTagOrHash,
14        BlockTag, Byte, Bytes, CallLog, CallTrace, CallTracerConfig, Filter, FilterTopic,
15        FilterTopics, GenericTransaction, InputOrData, PrestateTrace, PrestateTraceInfo,
16        PrestateTracerConfig, Trace, TracerType,
17    },
18    sp_core,
19};
20use serde::{Deserialize, Serialize};
21use subxt::utils::{H160, H256};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct AlloyU256(alloy_primitives::U256);
25
26impl From<polkadot_sdk::sp_core::U256> for AlloyU256 {
27    fn from(value: polkadot_sdk::sp_core::U256) -> Self {
28        let mut bytes = [0u8; 32];
29        value.write_as_big_endian(&mut bytes);
30        Self(alloy_primitives::U256::from_be_bytes(bytes))
31    }
32}
33
34impl AlloyU256 {
35    pub fn inner(&self) -> alloy_primitives::U256 {
36        self.0
37    }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct SubstrateU256(sp_core::U256);
42
43impl From<alloy_primitives::U256> for SubstrateU256 {
44    fn from(value: alloy_primitives::U256) -> Self {
45        Self(sp_core::U256::from_big_endian(&value.to_be_bytes::<32>()))
46    }
47}
48
49impl SubstrateU256 {
50    pub fn inner(&self) -> sp_core::U256 {
51        self.0
52    }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct ReviveAddress(H160);
57
58impl ReviveAddress {
59    pub fn new(addr: H160) -> Self {
60        Self(addr)
61    }
62
63    pub fn inner(&self) -> H160 {
64        self.0
65    }
66}
67
68impl From<Address> for ReviveAddress {
69    fn from(addr: Address) -> Self {
70        Self(H160::from_slice(addr.0.as_ref()))
71    }
72}
73
74impl From<ReviveAddress> for Address {
75    fn from(value: ReviveAddress) -> Self {
76        Self(alloy_primitives::U160::from_be_bytes(*value.0.as_fixed_bytes()).into())
77    }
78}
79
80pub struct ReviveBlockNumberOrTag(pub evm::BlockNumberOrTag);
81
82impl From<BlockNumberOrTag> for ReviveBlockNumberOrTag {
83    fn from(value: BlockNumberOrTag) -> Self {
84        Self(match value {
85            BlockNumberOrTag::Latest => evm::BlockNumberOrTag::BlockTag(BlockTag::Latest),
86            BlockNumberOrTag::Finalized => evm::BlockNumberOrTag::BlockTag(BlockTag::Finalized),
87            BlockNumberOrTag::Safe => evm::BlockNumberOrTag::BlockTag(BlockTag::Safe),
88            BlockNumberOrTag::Earliest => evm::BlockNumberOrTag::BlockTag(BlockTag::Earliest),
89            BlockNumberOrTag::Pending => evm::BlockNumberOrTag::BlockTag(BlockTag::Pending),
90            BlockNumberOrTag::Number(num) => evm::BlockNumberOrTag::U256(evm::U256::from(num)),
91        })
92    }
93}
94
95impl ReviveBlockNumberOrTag {
96    pub fn inner(self) -> evm::BlockNumberOrTag {
97        self.0
98    }
99}
100
101#[derive(Debug, Clone)]
102pub struct ReviveBlockId(BlockNumberOrTagOrHash);
103
104impl ReviveBlockId {
105    pub fn inner(self) -> BlockNumberOrTagOrHash {
106        self.0
107    }
108}
109
110impl From<Option<BlockId>> for ReviveBlockId {
111    fn from(block_id: Option<BlockId>) -> Self {
112        Self(block_id.map_or(
113            BlockNumberOrTagOrHash::BlockTag(BlockTag::Latest),
114            |b_id| match b_id {
115                BlockId::Hash(rpc_hash) => BlockNumberOrTagOrHash::BlockHash(H256::from_slice(
116                    rpc_hash.block_hash.as_slice(),
117                )),
118                BlockId::Number(number_or_tag) => {
119                    ReviveBlockNumberOrTag::from(number_or_tag).inner().into()
120                }
121            },
122        ))
123    }
124}
125
126#[derive(Debug, Clone)]
127pub struct ReviveAccessList(Vec<AccessListEntry>);
128
129impl ReviveAccessList {
130    pub fn inner(self) -> Vec<AccessListEntry> {
131        self.0
132    }
133}
134
135impl From<AccessList> for ReviveAccessList {
136    fn from(value: AccessList) -> Self {
137        Self(
138            value
139                .0
140                .into_iter()
141                .map(|access_list_entry| AccessListEntry {
142                    address: ReviveAddress::from(access_list_entry.address).inner(),
143                    storage_keys: access_list_entry
144                        .storage_keys
145                        .into_iter()
146                        .map(|key| H256::from_slice(key.as_ref()))
147                        .collect(),
148                })
149                .collect(),
150        )
151    }
152}
153
154#[derive(Debug, Clone)]
155pub struct ReviveAuthorizationListEntry(AuthorizationListEntry);
156
157impl ReviveAuthorizationListEntry {
158    pub fn inner(self) -> AuthorizationListEntry {
159        self.0
160    }
161}
162
163impl From<SignedAuthorization> for ReviveAuthorizationListEntry {
164    fn from(value: SignedAuthorization) -> Self {
165        Self(AuthorizationListEntry {
166            chain_id: SubstrateU256::from(value.inner().chain_id).inner(),
167            address: ReviveAddress::from(value.inner().address).inner(),
168            nonce: value.inner().nonce.into(),
169            y_parity: value.y_parity().into(),
170            r: SubstrateU256::from(value.r()).inner(),
171            s: SubstrateU256::from(value.s()).inner(),
172        })
173    }
174}
175
176#[derive(Debug, Clone)]
177pub struct ReviveBytes(Bytes);
178
179impl From<alloy_primitives::Bytes> for ReviveBytes {
180    fn from(value: alloy_primitives::Bytes) -> Self {
181        Self(Bytes::from(value.to_vec()))
182    }
183}
184
185impl ReviveBytes {
186    pub fn inner(self) -> Bytes {
187        self.0
188    }
189}
190
191pub(crate) fn convert_to_generic_transaction(
192    transaction_request: TransactionRequest,
193) -> GenericTransaction {
194    GenericTransaction {
195        access_list: transaction_request
196            .access_list
197            .map(|access_list| ReviveAccessList::from(access_list).inner()),
198        authorization_list: transaction_request.authorization_list.map_or(
199            Default::default(),
200            |authorization_list| {
201                authorization_list
202                    .into_iter()
203                    .map(|entry| ReviveAuthorizationListEntry::from(entry).inner())
204                    .collect()
205            },
206        ),
207        blob_versioned_hashes: transaction_request
208            .blob_versioned_hashes
209            .unwrap_or_default()
210            .into_iter()
211            .map(|b256| H256::from_slice(b256.as_ref()))
212            .collect(),
213        blobs: transaction_request
214            .sidecar
215            .unwrap_or_default()
216            .blobs
217            .into_iter()
218            .map(|blob| Bytes::from(blob.0.to_vec()))
219            .collect(),
220        chain_id: transaction_request.chain_id.map(sp_core::U256::from),
221        from: transaction_request.from.map(|addr| ReviveAddress::from(addr).inner()),
222        gas: transaction_request.gas.map(sp_core::U256::from),
223        gas_price: transaction_request.gas_price.map(sp_core::U256::from),
224        input: InputOrData::from(
225            ReviveBytes::from(transaction_request.input.into_input().unwrap_or_default()).inner(),
226        ),
227        max_fee_per_blob_gas: transaction_request.max_fee_per_blob_gas.map(sp_core::U256::from),
228        max_fee_per_gas: transaction_request.max_fee_per_gas.map(sp_core::U256::from),
229        max_priority_fee_per_gas: transaction_request
230            .max_priority_fee_per_gas
231            .map(sp_core::U256::from),
232        nonce: transaction_request.nonce.map(sp_core::U256::from),
233        to: transaction_request
234            .to
235            .and_then(|tx_kind| tx_kind.into_to())
236            .map(|addr| ReviveAddress::from(addr).inner()),
237        r#type: transaction_request.transaction_type.map(Byte::from),
238        value: transaction_request.value.map(|value| SubstrateU256::from(value).inner()),
239    }
240}
241
242struct ReviveFilterTopics(FilterTopics);
243
244impl ReviveFilterTopics {
245    fn into_inner(self) -> FilterTopics {
246        self.0
247    }
248}
249
250impl From<[Topic; 4]> for ReviveFilterTopics {
251    fn from(value: [Topic; 4]) -> Self {
252        let topics: Vec<FilterTopic> = value
253            .into_iter()
254            .filter(|t| !t.is_empty())
255            .map(|topic| {
256                let hashes: Vec<H256> =
257                    topic.into_iter().map(|hash| H256::from_slice(hash.as_ref())).collect();
258                match hashes.len() {
259                    1 => FilterTopic::Single(hashes[0]),
260                    _ => FilterTopic::Multiple(hashes),
261                }
262            })
263            .collect();
264        Self(topics)
265    }
266}
267
268struct ReviveAddressOrAddresses(AddressOrAddresses);
269
270impl ReviveAddressOrAddresses {
271    fn into_inner(self) -> AddressOrAddresses {
272        self.0
273    }
274}
275
276impl From<FilterSet<Address>> for ReviveAddressOrAddresses {
277    fn from(value: FilterSet<Address>) -> Self {
278        let addresses: Vec<Address> = value.into_iter().collect();
279        let address_or_addresses = match addresses.len() {
280            0 => AddressOrAddresses::Address(Default::default()),
281            1 => AddressOrAddresses::Address(ReviveAddress::from(addresses[0]).inner()),
282            _ => AddressOrAddresses::Addresses(
283                addresses.into_iter().map(|address| ReviveAddress::from(address).inner()).collect(),
284            ),
285        };
286        Self(address_or_addresses)
287    }
288}
289
290pub struct ReviveFilter(Filter);
291
292impl ReviveFilter {
293    pub fn into_inner(self) -> Filter {
294        self.0
295    }
296}
297
298impl From<alloy_rpc_types::Filter> for ReviveFilter {
299    fn from(value: alloy_rpc_types::Filter) -> Self {
300        let address = if value.address.is_empty() {
301            None
302        } else {
303            Some(ReviveAddressOrAddresses::from(value.address).into_inner())
304        };
305        let topics = if value.topics.iter().all(|t| t.is_empty()) {
306            None
307        } else {
308            Some(ReviveFilterTopics::from(value.topics).into_inner())
309        };
310        let (from_block, to_block, block_hash) = match value.block_option {
311            FilterBlockOption::Range { from_block, to_block } => (
312                from_block.map(|fb| ReviveBlockNumberOrTag::from(fb).inner()),
313                to_block.map(|tb| ReviveBlockNumberOrTag::from(tb).inner()),
314                None,
315            ),
316            FilterBlockOption::AtBlockHash(hash) => {
317                (None, None, Some(H256::from_slice(hash.as_ref())))
318            }
319        };
320        Self(Filter { address, from_block, to_block, block_hash, topics })
321    }
322}
323
324#[derive(Debug, Clone, PartialEq)]
325pub struct ReviveTracerType(TracerType);
326
327impl ReviveTracerType {
328    pub fn new(tracer_type: TracerType) -> Self {
329        Self(tracer_type)
330    }
331
332    pub fn inner(self) -> TracerType {
333        self.0
334    }
335}
336
337impl From<GethDebugTracingOptions> for ReviveTracerType {
338    fn from(tracing_options: GethDebugTracingOptions) -> Self {
339        let tracer_type = if let Some(GethDebugTracerType::BuiltInTracer(geth_tracer_type)) =
340            tracing_options.tracer
341        {
342            match geth_tracer_type {
343                GethDebugBuiltInTracerType::CallTracer => {
344                    TracerType::CallTracer(Some(CallTracerConfig::default()))
345                }
346                GethDebugBuiltInTracerType::PreStateTracer => {
347                    let mut prestate_config = PrestateTracerConfig::default();
348                    if tracing_options.config.disable_storage.unwrap_or(false) {
349                        prestate_config.disable_storage = true;
350                    }
351                    TracerType::PrestateTracer(Some(prestate_config))
352                }
353                _ => Default::default(),
354            }
355        } else {
356            Default::default()
357        };
358        Self(tracer_type)
359    }
360}
361
362impl From<GethDebugTracingCallOptions> for ReviveTracerType {
363    fn from(tracing_call_options: GethDebugTracingCallOptions) -> Self {
364        Self::from(tracing_call_options.tracing_options)
365    }
366}
367
368#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
369pub struct ReviveCallLog(CallLog);
370
371impl ReviveCallLog {
372    pub fn new(call_log: CallLog) -> Self {
373        Self(call_log)
374    }
375
376    pub fn inner(self) -> CallLog {
377        self.0
378    }
379}
380
381impl From<ReviveCallLog> for CallLogFrame {
382    fn from(value: ReviveCallLog) -> Self {
383        let call_log = value.inner();
384        Self {
385            address: Some(Address::from_slice(call_log.address.as_ref())),
386            topics: Some(
387                call_log.topics.into_iter().map(|topic| B256::from_slice(topic.as_ref())).collect(),
388            ),
389            data: Some(call_log.data.0.into()),
390            position: Some(call_log.position.into()),
391            // Revive CallLog currently does not provide the log index.
392            index: None,
393        }
394    }
395}
396
397#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
398pub struct RevivePrestateTraceInfo(PrestateTraceInfo);
399
400impl RevivePrestateTraceInfo {
401    pub fn new(prestate_trace_info: PrestateTraceInfo) -> Self {
402        Self(prestate_trace_info)
403    }
404
405    pub fn inner(self) -> PrestateTraceInfo {
406        self.0
407    }
408}
409
410impl From<RevivePrestateTraceInfo> for AccountState {
411    fn from(value: RevivePrestateTraceInfo) -> Self {
412        let prestate_trace_info = value.inner();
413        Self {
414            balance: prestate_trace_info.balance.map(|b| AlloyU256::from(b).inner()),
415            code: prestate_trace_info.code.map(|c| c.0.into()),
416            nonce: prestate_trace_info.nonce.map(|n| n.into()),
417            storage: prestate_trace_info
418                .storage
419                .into_iter()
420                .map(|(k, v)| {
421                    (
422                        B256::from_slice(k.0.as_slice()),
423                        B256::from_slice(v.unwrap_or(Bytes(vec![0u8; 32])).0.as_slice()),
424                    )
425                })
426                .collect(),
427        }
428    }
429}
430
431#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
432pub struct ReviveCallTrace(CallTrace);
433
434impl ReviveCallTrace {
435    pub fn new(call_trace: CallTrace) -> Self {
436        Self(call_trace)
437    }
438
439    pub fn inner(self) -> CallTrace {
440        self.0
441    }
442}
443
444impl From<ReviveCallTrace> for CallFrame {
445    fn from(value: ReviveCallTrace) -> Self {
446        let call_trace = value.inner();
447        Self {
448            from: Address::from_slice(call_trace.from.as_ref()),
449            gas: AlloyU256::from(call_trace.gas).inner(),
450            gas_used: AlloyU256::from(call_trace.gas_used).inner(),
451            to: Some(Address::from_slice(call_trace.to.as_ref())),
452            input: call_trace.input.0.into(),
453            output: Some(call_trace.output.0.into()),
454            error: call_trace.error,
455            revert_reason: call_trace.revert_reason,
456            calls: call_trace
457                .calls
458                .into_iter()
459                .map(|c_t| ReviveCallTrace::new(c_t).into())
460                .collect(),
461            logs: call_trace.logs.into_iter().map(|c_l| ReviveCallLog::new(c_l).into()).collect(),
462            value: call_trace.value.map(|v| AlloyU256::from(v).inner()),
463            typ: serde_json::to_string(&call_trace.call_type)
464                .unwrap()
465                .trim_matches('"')
466                .to_string(),
467        }
468    }
469}
470
471#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
472pub struct ReviveTrace(Trace);
473
474impl ReviveTrace {
475    pub fn new(trace: Trace) -> Self {
476        Self(trace)
477    }
478
479    pub fn inner(self) -> Trace {
480        self.0
481    }
482}
483
484impl From<ReviveTrace> for GethTrace {
485    fn from(value: ReviveTrace) -> Self {
486        match value.inner() {
487            Trace::Call(call_trace) => Self::CallTracer(ReviveCallTrace::new(call_trace).into()),
488            Trace::Prestate(PrestateTrace::Prestate(prestate_map)) => {
489                Self::PreStateTracer(PreStateFrame::Default(PreStateMode(
490                    prestate_map
491                        .into_iter()
492                        .map(|(account_address, prestate_trace_info)| {
493                            (
494                                Address::from_slice(account_address.as_ref()),
495                                RevivePrestateTraceInfo::new(prestate_trace_info).into(),
496                            )
497                        })
498                        .collect(),
499                )))
500            }
501            Trace::Prestate(PrestateTrace::DiffMode { pre, post }) => {
502                Self::PreStateTracer(PreStateFrame::Diff(DiffMode {
503                    pre: pre
504                        .into_iter()
505                        .map(|(account_address, prestate_trace_info)| {
506                            (
507                                Address::from_slice(account_address.as_ref()),
508                                RevivePrestateTraceInfo::new(prestate_trace_info).into(),
509                            )
510                        })
511                        .collect(),
512                    post: post
513                        .into_iter()
514                        .map(|(account_address, prestate_trace_info)| {
515                            (
516                                Address::from_slice(account_address.as_ref()),
517                                RevivePrestateTraceInfo::new(prestate_trace_info).into(),
518                            )
519                        })
520                        .collect(),
521                }))
522            }
523        }
524    }
525}