1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// This file is part of Astar.

// Copyright (C) Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

///! EVM tracing RPC support.
use crate::evm_tracing_types::{EthApi as EthApiCmd, EvmTracingConfig};

use fc_rpc_core::types::FilterPool;
use fc_storage::StorageOverride;
use fp_rpc::EthereumRuntimeRPCApi;
use moonbeam_rpc_debug::{DebugHandler, DebugRequester};
use moonbeam_rpc_trace::{CacheRequester as TraceFilterCacheRequester, CacheTask};
use sc_client_api::{
    Backend, BlockOf, BlockchainEvents, HeaderBackend, StateBackend, StorageProvider,
};
use sc_service::TaskManager;
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderMetadata};
use sp_core::H256;
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Header as HeaderT};
use std::sync::Arc;
use substrate_prometheus_endpoint::Registry as PrometheusRegistry;
use tokio::sync::Semaphore;

#[derive(Clone)]
pub struct RpcRequesters {
    pub debug: Option<DebugRequester>,
    pub trace: Option<TraceFilterCacheRequester>,
}

pub struct SpawnTasksParams<'a, B: BlockT, C, BE> {
    pub task_manager: &'a TaskManager,
    pub client: Arc<C>,
    pub substrate_backend: Arc<BE>,
    pub frontier_backend: Arc<dyn fc_api::Backend<B> + Send + Sync>,
    pub filter_pool: Option<FilterPool>,
    pub storage_override: Arc<dyn StorageOverride<B>>,
}

/// Spawn the tasks that are required to run a EVM tracing.
pub fn spawn_tracing_tasks<B, C, BE>(
    rpc_config: &EvmTracingConfig,
    prometheus: Option<PrometheusRegistry>,
    params: SpawnTasksParams<B, C, BE>,
) -> RpcRequesters
where
    C: ProvideRuntimeApi<B> + BlockOf,
    C: StorageProvider<B, BE>,
    C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
    C: BlockchainEvents<B>,
    C: Send + Sync + 'static,
    C::Api: EthereumRuntimeRPCApi<B> + moonbeam_rpc_primitives_debug::DebugRuntimeApi<B>,
    C::Api: BlockBuilder<B>,
    B: BlockT<Hash = H256> + Send + Sync + 'static,
    B::Header: HeaderT<Number = u32>,
    BE: Backend<B> + 'static,
    BE::State: StateBackend<BlakeTwo256>,
{
    let permit_pool = Arc::new(Semaphore::new(rpc_config.ethapi_max_permits as usize));

    let (trace_filter_task, trace_filter_requester) =
        if rpc_config.ethapi.contains(&EthApiCmd::Trace) {
            let (trace_filter_task, trace_filter_requester) = CacheTask::create(
                Arc::clone(&params.client),
                Arc::clone(&params.substrate_backend),
                core::time::Duration::from_secs(rpc_config.ethapi_trace_cache_duration),
                Arc::clone(&permit_pool),
                Arc::clone(&params.storage_override),
                prometheus,
            );
            (Some(trace_filter_task), Some(trace_filter_requester))
        } else {
            (None, None)
        };

    let (debug_task, debug_requester) = if rpc_config.ethapi.contains(&EthApiCmd::Debug) {
        let (debug_task, debug_requester) = DebugHandler::task(
            Arc::clone(&params.client),
            Arc::clone(&params.substrate_backend),
            Arc::clone(&params.frontier_backend),
            Arc::clone(&permit_pool),
            Arc::clone(&params.storage_override),
            rpc_config.tracing_raw_max_memory_usage,
        );
        (Some(debug_task), Some(debug_requester))
    } else {
        (None, None)
    };

    // `trace_filter` cache task. Essential.
    // Proxies rpc requests to it's handler.
    if let Some(trace_filter_task) = trace_filter_task {
        params.task_manager.spawn_essential_handle().spawn(
            "trace-filter-cache",
            Some("eth-tracing"),
            trace_filter_task,
        );
    }

    // `debug` task if enabled. Essential.
    // Proxies rpc requests to it's handler.
    if let Some(debug_task) = debug_task {
        params.task_manager.spawn_essential_handle().spawn(
            "ethapi-debug",
            Some("eth-tracing"),
            debug_task,
        );
    }

    RpcRequesters {
        debug: debug_requester,
        trace: trace_filter_requester,
    }
}