Skip to main content

anvil_polkadot/substrate_node/service/
mod.rs

1use crate::{
2    AnvilNodeConfig,
3    substrate_node::{
4        mining_engine::{MiningEngine, MiningMode, run_mining_engine},
5        rpc::spawn_rpc_server,
6        service::consensus::SameSlotConsensusDataProvider,
7    },
8};
9use anvil::eth::backend::time::TimeManager;
10use parking_lot::Mutex;
11use polkadot_sdk::{
12    parachains_common::opaque::Block,
13    sc_basic_authorship, sc_consensus,
14    sc_consensus_manual_seal::{self},
15    sc_service::{
16        self, Configuration, RpcHandlers, SpawnTaskHandle, TaskManager,
17        error::Error as ServiceError,
18    },
19    sc_transaction_pool, sp_timestamp,
20};
21use std::sync::Arc;
22use tokio_stream::wrappers::ReceiverStream;
23
24pub use backend::{BackendError, BackendWithOverlay, StorageOverrides};
25pub use client::Client;
26
27mod backend;
28mod client;
29mod consensus;
30mod executor;
31pub mod storage;
32
33pub type Backend = sc_service::TFullBackend<Block>;
34
35pub type TransactionPoolHandle = sc_transaction_pool::TransactionPoolHandle<Block, Client>;
36
37type SelectChain = sc_consensus::LongestChain<Backend, Block>;
38
39#[derive(Clone)]
40pub struct Service {
41    pub spawn_handle: SpawnTaskHandle,
42    pub client: Arc<Client>,
43    pub backend: Arc<Backend>,
44    pub tx_pool: Arc<TransactionPoolHandle>,
45    pub rpc_handlers: RpcHandlers,
46    pub mining_engine: Arc<MiningEngine>,
47    pub storage_overrides: Arc<Mutex<StorageOverrides>>,
48    pub genesis_block_number: u64,
49}
50
51/// Builds a new service for a full client.
52pub fn new(
53    anvil_config: &AnvilNodeConfig,
54    config: Configuration,
55) -> Result<(Service, TaskManager), ServiceError> {
56    let storage_overrides =
57        Arc::new(Mutex::new(StorageOverrides::new(anvil_config.revive_rpc_block_limit)));
58
59    let (client, backend, keystore, mut task_manager) = client::new_client(
60        anvil_config.get_genesis_number(),
61        &config,
62        sc_service::new_wasm_executor(&config.executor),
63        storage_overrides.clone(),
64    )?;
65
66    let transaction_pool = Arc::from(
67        sc_transaction_pool::Builder::new(
68            task_manager.spawn_essential_handle(),
69            client.clone(),
70            config.role.is_authority().into(),
71        )
72        .with_options(config.transaction_pool.clone())
73        .build(),
74    );
75
76    // Inform the tx pool about imported and finalized blocks.
77    task_manager.spawn_handle().spawn(
78        "txpool-notifications",
79        Some("transaction-pool"),
80        sc_transaction_pool::notification_future(client.clone(), transaction_pool.clone()),
81    );
82
83    let (seal_engine_command_sender, commands_stream) = tokio::sync::mpsc::channel(1024);
84    let commands_stream = ReceiverStream::new(commands_stream);
85
86    let mining_mode =
87        MiningMode::new(anvil_config.block_time, anvil_config.mixed_mining, anvil_config.no_mining);
88    let time_manager = Arc::new(TimeManager::new_with_milliseconds(
89        sp_timestamp::Timestamp::from(
90            anvil_config
91                .get_genesis_timestamp()
92                .checked_mul(1000)
93                .ok_or(ServiceError::Application("Genesis timestamp overflow".into()))?,
94        )
95        .into(),
96    ));
97
98    let mining_engine = Arc::new(MiningEngine::new(
99        mining_mode,
100        transaction_pool.clone(),
101        time_manager.clone(),
102        seal_engine_command_sender,
103    ));
104
105    let rpc_handlers = spawn_rpc_server(
106        anvil_config.get_genesis_number(),
107        &mut task_manager,
108        client.clone(),
109        config,
110        transaction_pool.clone(),
111        keystore,
112        backend.clone(),
113    )?;
114
115    task_manager.spawn_handle().spawn(
116        "mining_engine_task",
117        Some("consensus"),
118        run_mining_engine(mining_engine.clone()),
119    );
120
121    let proposer = sc_basic_authorship::ProposerFactory::new(
122        task_manager.spawn_handle(),
123        client.clone(),
124        transaction_pool.clone(),
125        None,
126        None,
127    );
128
129    let create_inherent_data_providers = {
130        move |_, ()| {
131            let next_timestamp = time_manager.next_timestamp();
132            async move { Ok(sp_timestamp::InherentDataProvider::new(next_timestamp.into())) }
133        }
134    };
135
136    let params = sc_consensus_manual_seal::ManualSealParams {
137        block_import: client.clone(),
138        env: proposer,
139        client: client.clone(),
140        pool: transaction_pool.clone(),
141        select_chain: SelectChain::new(backend.clone()),
142        commands_stream: Box::pin(commands_stream),
143        consensus_data_provider: Some(Box::new(SameSlotConsensusDataProvider::new())),
144        create_inherent_data_providers,
145    };
146    let authorship_future = sc_consensus_manual_seal::run_manual_seal(params);
147
148    task_manager.spawn_essential_handle().spawn_blocking(
149        "manual-seal",
150        "substrate",
151        authorship_future,
152    );
153
154    Ok((
155        Service {
156            spawn_handle: task_manager.spawn_handle(),
157            client,
158            backend,
159            tx_pool: transaction_pool,
160            rpc_handlers,
161            mining_engine,
162            storage_overrides,
163            genesis_block_number: anvil_config.get_genesis_number(),
164        },
165        task_manager,
166    ))
167}