1#![warn(missing_docs)]
3
4use crate::chain_spec::create_domain_spec;
5use crate::{
6 AUTO_ID_DOMAIN_ID, BalanceOf, DomainRuntime, EVM_DOMAIN_ID, EcdsaKeyring, Sr25519Keyring,
7 UncheckedExtrinsicFor, construct_extrinsic_generic, node_config,
8};
9use cross_domain_message_gossip::ChainMsg;
10use domain_block_preprocessor::inherents::CreateInherentDataProvider;
11use domain_client_operator::snap_sync::ConsensusChainSyncParams;
12use domain_client_operator::{BootstrapResult, OperatorStreams, fetch_domain_bootstrap_info};
13use domain_eth_service::provider::EthProvider;
14use domain_eth_service::{DefaultEthConfig, EthConfiguration};
15use domain_runtime_primitives::opaque::Block;
16use domain_runtime_primitives::{Balance, EthereumAccountId};
17use domain_service::providers::DefaultProvider;
18use domain_service::{FullBackend, FullClient, FullPool};
19use domain_test_primitives::{EvmOnchainStateApi, OnchainStateApi};
20use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
21use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
22use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi;
23use sc_client_api::HeaderBackend;
24use sc_domains::RuntimeExecutor;
25use sc_network::service::traits::NetworkService;
26use sc_network::{NetworkStateInfo, ReputationChange};
27use sc_network_sync::SyncingService;
28use sc_service::config::MultiaddrWithPeerId;
29use sc_service::{BasePath, Role, RpcHandlers, TFullBackend, TaskManager, TransactionPool};
30use sc_transaction_pool_api::OffchainTransactionPoolFactory;
31use sc_utils::mpsc::{TracingUnboundedSender, tracing_unbounded};
32use sp_api::{ApiExt, ConstructRuntimeApi, Metadata, ProvideRuntimeApi};
33use sp_block_builder::BlockBuilder;
34use sp_blockchain::HashAndNumber;
35use sp_consensus_subspace::SubspaceApi;
36use sp_core::{Encode, H256};
37use sp_domains::core_api::DomainCoreApi;
38use sp_domains::{DomainId, DomainsApi, OperatorId, PermissionedActionAllowedBy};
39use sp_messenger::messages::{ChainId, ChannelId};
40use sp_messenger::{MessengerApi, RelayerApi};
41use sp_offchain::OffchainWorkerApi;
42use sp_runtime::OpaqueExtrinsic;
43use sp_runtime::traits::{AsSystemOriginSigner, Dispatchable, NumberFor};
44use sp_session::SessionKeys;
45use sp_transaction_pool::runtime_api::TaggedTransactionQueue;
46use std::future::Future;
47use std::net::SocketAddr;
48use std::sync::Arc;
49use std::time::Duration;
50use subspace_runtime_primitives::opaque::Block as CBlock;
51use subspace_runtime_primitives::{BlockHashFor, HeaderFor, Nonce};
52use subspace_test_service::MockConsensusNode;
53use substrate_frame_rpc_system::AccountNonceApi;
54use substrate_test_client::{
55 BlockchainEventsExt, RpcHandlersExt, RpcTransactionError, RpcTransactionOutput,
56};
57use tokio::time::sleep;
58
59pub type Backend = TFullBackend<Block>;
61
62type Client<RuntimeApi> = FullClient<Block, RuntimeApi>;
63
64pub type DomainOperator<RuntimeApi> =
66 domain_service::DomainOperator<Block, CBlock, subspace_test_client::Client, RuntimeApi>;
67
68pub struct DomainNode<Runtime, RuntimeApi>
70where
71 Runtime: DomainRuntime,
72 RuntimeApi: ConstructRuntimeApi<Block, Client<RuntimeApi>> + Send + Sync + 'static,
73 RuntimeApi::RuntimeApi: ApiExt<Block>
74 + Metadata<Block>
75 + BlockBuilder<Block>
76 + OffchainWorkerApi<Block>
77 + SessionKeys<Block>
78 + DomainCoreApi<Block>
79 + MessengerApi<Block, NumberFor<CBlock>, BlockHashFor<CBlock>>
80 + TaggedTransactionQueue<Block>
81 + AccountNonceApi<Block, Runtime::AccountId, Nonce>
82 + TransactionPaymentRuntimeApi<Block, Balance>
83 + RelayerApi<Block, NumberFor<Block>, NumberFor<CBlock>, BlockHashFor<CBlock>>,
84{
85 pub domain_id: DomainId,
87 pub key: Runtime::Keyring,
89 pub task_manager: TaskManager,
91 pub client: Arc<Client<RuntimeApi>>,
93 pub backend: Arc<Backend>,
95 pub code_executor: Arc<RuntimeExecutor>,
97 pub network_service: Arc<dyn NetworkService>,
99 pub sync_service: Arc<SyncingService<Block>>,
101 pub addr: MultiaddrWithPeerId,
104 pub rpc_handlers: RpcHandlers,
106 pub operator: DomainOperator<RuntimeApi>,
108 pub tx_pool_sink: TracingUnboundedSender<ChainMsg>,
110 pub base_path: BasePath,
112}
113
114impl<Runtime, RuntimeApi> DomainNode<Runtime, RuntimeApi>
115where
116 Runtime: frame_system::Config<Hash = H256>
117 + pallet_transaction_payment::Config
118 + DomainRuntime
119 + Send
120 + Sync,
121 Runtime::RuntimeCall:
122 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
123 crate::BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
124 u64: From<BlockNumberFor<Runtime>>,
125 RuntimeApi: ConstructRuntimeApi<Block, Client<RuntimeApi>> + Send + Sync + 'static,
126 RuntimeApi::RuntimeApi: ApiExt<Block>
127 + Metadata<Block>
128 + BlockBuilder<Block>
129 + OffchainWorkerApi<Block>
130 + SessionKeys<Block>
131 + DomainCoreApi<Block>
132 + TaggedTransactionQueue<Block>
133 + AccountNonceApi<Block, <Runtime as DomainRuntime>::AccountId, Nonce>
134 + TransactionPaymentRuntimeApi<Block, Balance>
135 + MessengerApi<Block, NumberFor<CBlock>, BlockHashFor<CBlock>>
136 + RelayerApi<Block, NumberFor<Block>, NumberFor<CBlock>, BlockHashFor<CBlock>>
137 + OnchainStateApi<Block, <Runtime as DomainRuntime>::AccountId, Balance>,
138 <RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
139 AsSystemOriginSigner<<Runtime as frame_system::Config>::AccountId> + Clone,
140{
141 #[allow(clippy::too_many_arguments)]
142 async fn build<Provider>(
143 domain_id: DomainId,
144 tokio_handle: tokio::runtime::Handle,
145 key: Runtime::Keyring,
146 base_path: BasePath,
147 domain_nodes: Vec<MultiaddrWithPeerId>,
148 domain_nodes_exclusive: bool,
149 skip_empty_bundle_production: bool,
150 maybe_operator_id: Option<OperatorId>,
151 role: Role,
152 mock_consensus_node: &mut MockConsensusNode,
153 rpc_addr: Option<SocketAddr>,
154 rpc_port: Option<u16>,
155 provider: Provider,
156 ) -> Self
157 where
158 Provider: domain_service::providers::BlockImportProvider<Block, Client<RuntimeApi>>
159 + domain_service::providers::RpcProvider<
160 Block,
161 Client<RuntimeApi>,
162 FullPool<RuntimeApi>,
163 Backend,
164 <Runtime as DomainRuntime>::AccountId,
165 CreateInherentDataProvider<subspace_test_client::Client, CBlock>,
166 > + 'static,
167 {
168 let mut domain_config = node_config(
169 domain_id,
170 tokio_handle.clone(),
171 Runtime::to_seed(key),
172 domain_nodes,
173 domain_nodes_exclusive,
174 role,
175 base_path.clone(),
176 Box::new(create_domain_spec()) as Box<_>,
177 rpc_addr,
178 rpc_port,
179 )
180 .expect("could not generate domain node Configuration");
181
182 let domain_backend = sc_service::new_db_backend::<Block>(domain_config.db_config())
183 .unwrap_or_else(
184 |err| {
185 tracing::error!("Failed to create domain backend: {domain_id:?} {role:?} {base_path:?} error: {err:?}");
186
187 for dir_path in base_path.path().ancestors() {
189 tracing::error!("{dir_path:?} try_exists: {:?}", dir_path.try_exists());
190 }
191 panic!("Failed to create domain backend: {domain_id:?} {role:?} {base_path:?} error: {err:?}")
192 }
193 );
194
195 let BootstrapResult {
196 domain_instance_data,
197 domain_created_at,
198 imported_block_notification_stream,
199 ..
200 } = fetch_domain_bootstrap_info::<Block, _, _, _>(
201 &*mock_consensus_node.client,
202 &*domain_backend,
203 domain_id,
204 )
205 .await
206 .expect("Failed to get domain instance data");
207
208 domain_config
209 .chain_spec
210 .set_storage(domain_instance_data.raw_genesis.into_storage());
211
212 let span = sc_tracing::tracing::info_span!(
213 sc_tracing::logging::PREFIX_LOG_SPAN,
214 name = domain_config.network.node_name.as_str()
215 );
216 let _enter = span.enter();
217
218 let multiaddr = domain_config.network.listen_addresses[0].clone();
219
220 let operator_streams = OperatorStreams {
221 consensus_block_import_throttling_buffer_size: 0,
224 block_importing_notification_stream: mock_consensus_node
225 .block_importing_notification_stream(),
226 imported_block_notification_stream,
227 new_slot_notification_stream: mock_consensus_node.new_slot_notification_stream(),
228 acknowledgement_sender_stream: mock_consensus_node.new_acknowledgement_sender_stream(),
229 _phantom: Default::default(),
230 };
231
232 let (domain_message_sink, domain_message_receiver) =
233 tracing_unbounded("domain_message_channel", 100);
234 let gossip_msg_sink = mock_consensus_node
235 .xdm_gossip_worker_builder()
236 .gossip_msg_sink();
237
238 let maybe_operator_id = role
239 .is_authority()
240 .then_some(maybe_operator_id.unwrap_or(if domain_id == EVM_DOMAIN_ID { 0 } else { 1 }));
241
242 let consensus_best_hash = mock_consensus_node.client.info().best_hash;
243 let runtime_api = mock_consensus_node.client.runtime_api();
244 let chain_constants = runtime_api.chain_constants(consensus_best_hash).unwrap();
245
246 let domain_block_pruning_depth = runtime_api
247 .block_pruning_depth(consensus_best_hash)
248 .unwrap();
249
250 let domain_params = domain_service::DomainParams {
251 domain_id,
252 domain_config,
253 domain_created_at,
254 consensus_client: mock_consensus_node.client.clone(),
255 consensus_offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(
256 mock_consensus_node.transaction_pool.clone(),
257 ),
258 domain_sync_oracle: mock_consensus_node.sync_service.clone(),
259 consensus_network: mock_consensus_node.network_service.clone(),
260 operator_streams,
261 gossip_message_sink: gossip_msg_sink,
262 domain_message_receiver,
263 provider,
264 skip_empty_bundle_production,
265 skip_out_of_order_slot: true,
266 maybe_operator_id,
267 confirmation_depth_k: chain_constants.confirmation_depth_k(),
268 challenge_period: domain_block_pruning_depth,
269 consensus_chain_sync_params: None::<ConsensusChainSyncParams<_, HeaderFor<Block>>>,
270 domain_backend,
271 };
272
273 let domain_node = domain_service::new_full::<
274 _,
275 _,
276 _,
277 _,
278 _,
279 _,
280 RuntimeApi,
281 <Runtime as DomainRuntime>::AccountId,
282 _,
283 >(domain_params)
284 .await
285 .expect("failed to build domain node");
286
287 let domain_service::NewFull {
288 task_manager,
289 client,
290 backend,
291 code_executor,
292 network_service,
293 sync_service,
294 rpc_handlers,
295 operator,
296 ..
297 } = domain_node;
298
299 if role.is_authority() {
300 mock_consensus_node
301 .xdm_gossip_worker_builder()
302 .push_chain_sink(ChainId::Domain(domain_id), domain_message_sink.clone());
303 }
304
305 let addr = MultiaddrWithPeerId {
306 multiaddr,
307 peer_id: network_service.local_peer_id(),
308 };
309
310 DomainNode {
311 domain_id,
312 key,
313 task_manager,
314 client,
315 backend,
316 code_executor,
317 network_service,
318 sync_service,
319 addr,
320 rpc_handlers,
321 operator,
322 tx_pool_sink: domain_message_sink,
323 base_path,
324 }
325 }
326
327 pub fn wait_for_blocks(&self, count: usize) -> impl Future<Output = ()> {
331 self.client.wait_for_blocks(count)
332 }
333
334 pub fn account_nonce(&self) -> u32 {
336 self.client
337 .runtime_api()
338 .account_nonce(
339 self.client.info().best_hash,
340 <Runtime as DomainRuntime>::account_id(self.key),
341 )
342 .expect("Fail to get account nonce")
343 }
344
345 pub fn account_nonce_of(&self, account_id: <Runtime as DomainRuntime>::AccountId) -> u32 {
347 self.client
348 .runtime_api()
349 .account_nonce(self.client.info().best_hash, account_id)
350 .expect("Fail to get account nonce")
351 }
352
353 pub async fn send_system_remark(&self) {
355 let nonce = self.account_nonce();
356 let _ = self
357 .construct_and_send_extrinsic(frame_system::Call::remark {
358 remark: nonce.encode(),
359 })
360 .await
361 .map(|_| ());
362 }
363
364 pub async fn construct_and_send_extrinsic(
366 &self,
367 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
368 ) -> Result<RpcTransactionOutput, RpcTransactionError> {
369 self.construct_and_send_extrinsic_with(self.account_nonce(), 0.into(), function)
370 .await
371 }
372
373 pub async fn construct_and_send_extrinsic_with(
375 &self,
376 nonce: u32,
377 tip: BalanceOf<Runtime>,
378 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
379 ) -> Result<RpcTransactionOutput, RpcTransactionError> {
380 let extrinsic = construct_extrinsic_generic::<Runtime, _>(
381 &self.client,
382 function,
383 self.key,
384 false,
385 nonce,
386 tip,
387 );
388 self.rpc_handlers.send_transaction(extrinsic.into()).await
389 }
390
391 pub fn construct_extrinsic(
393 &self,
394 nonce: u32,
395 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
396 ) -> UncheckedExtrinsicFor<Runtime> {
397 construct_extrinsic_generic::<Runtime, _>(
398 &self.client,
399 function,
400 self.key,
401 false,
402 nonce,
403 0.into(),
404 )
405 }
406
407 pub fn construct_extrinsic_with_tip(
409 &self,
410 nonce: u32,
411 tip: BalanceOf<Runtime>,
412 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
413 ) -> UncheckedExtrinsicFor<Runtime> {
414 construct_extrinsic_generic::<Runtime, _>(
415 &self.client,
416 function,
417 self.key,
418 false,
419 nonce,
420 tip,
421 )
422 }
423
424 pub async fn send_extrinsic(
426 &self,
427 extrinsic: impl Into<OpaqueExtrinsic>,
428 ) -> Result<RpcTransactionOutput, RpcTransactionError> {
429 self.rpc_handlers.send_transaction(extrinsic.into()).await
430 }
431
432 pub fn free_balance(&self, account_id: <Runtime as DomainRuntime>::AccountId) -> Balance {
434 self.client
435 .runtime_api()
436 .free_balance(self.client.info().best_hash, account_id)
437 .expect("Fail to get account free balance")
438 }
439
440 pub fn get_open_channel_for_chain(&self, chain_id: ChainId) -> Option<ChannelId> {
442 self.client
443 .runtime_api()
444 .get_open_channel_for_chain(self.client.info().best_hash, chain_id)
445 .expect("Fail to get open channel for Chain")
446 }
447
448 pub fn construct_unsigned_extrinsic(
450 &self,
451 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
452 ) -> UncheckedExtrinsicFor<Runtime>
453 where
454 Runtime:
455 frame_system::Config<Hash = H256> + pallet_transaction_payment::Config + Send + Sync,
456 RuntimeCallFor<Runtime>:
457 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
458 BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
459 {
460 let function = function.into();
461 UncheckedExtrinsicFor::<Runtime>::new_bare(function)
462 }
463
464 pub async fn construct_and_send_unsigned_extrinsic(
466 &self,
467 function: impl Into<<Runtime as frame_system::Config>::RuntimeCall>,
468 ) -> Result<RpcTransactionOutput, RpcTransactionError> {
469 let extrinsic = self.construct_unsigned_extrinsic(function);
470 self.rpc_handlers.send_transaction(extrinsic.into()).await
471 }
472
473 pub fn ban_peer(&self, addr: MultiaddrWithPeerId) {
476 self.network_service.report_peer(
479 addr.peer_id,
480 ReputationChange::new_fatal("Peer banned by test (1)"),
481 );
482 self.network_service.report_peer(
483 addr.peer_id,
484 ReputationChange::new_fatal("Peer banned by test (2)"),
485 );
486 }
487
488 pub fn unban_peer(&self, addr: MultiaddrWithPeerId) {
490 self.network_service.report_peer(
493 addr.peer_id,
494 ReputationChange::new(i32::MAX, "Peer unbanned by test (1)"),
495 );
496 self.network_service.report_peer(
497 addr.peer_id,
498 ReputationChange::new(i32::MAX, "Peer unbanned by test (2)"),
499 );
500 }
501
502 pub async fn stop(self) -> Result<(), std::io::Error> {
515 use fs2::FileExt;
516
517 let lock_file_path = self.base_path.path().join("paritydb").join("lock");
518 std::mem::drop(self);
520
521 let deadline = std::time::Instant::now() + Duration::from_secs(30);
522 let mut acquired = false;
523 while std::time::Instant::now() < deadline {
524 if let Ok(file) = std::fs::OpenOptions::new()
525 .read(true)
526 .write(true)
527 .open(&lock_file_path)
528 && file.try_lock_exclusive().is_ok()
529 {
530 let _ = FileExt::unlock(&file);
531 drop(file);
532 acquired = true;
533 break;
534 }
535 sleep(Duration::from_millis(10)).await;
536 }
537
538 if !acquired {
539 tracing::warn!(
540 "stop(): paritydb lock at {} still held after 30s; forcibly removing",
541 lock_file_path.display()
542 );
543 std::fs::remove_file(&lock_file_path).map_err(|err| {
544 tracing::error!(
545 ?err,
546 "stop(): failed to remove paritydb lock at {}",
547 lock_file_path.display()
548 );
549 err
550 })?;
551 return Err(std::io::Error::new(
557 std::io::ErrorKind::TimedOut,
558 format!(
559 "DomainNode::stop(): paritydb lock at {} not released within 30s",
560 lock_file_path.display()
561 ),
562 ));
563 }
564
565 Ok(())
566 }
567
568 pub async fn clear_tx_pool(&self) {
570 let tx_hashes: Vec<_> = self
571 .operator
572 .transaction_pool
573 .ready()
574 .map(|t| self.operator.transaction_pool.hash_of(&t.data))
575 .collect();
576
577 let hash_and_number = HashAndNumber {
578 number: self.client.info().best_number,
579 hash: self.client.info().best_hash,
580 };
581 self.operator
582 .transaction_pool
583 .pool()
584 .prune_known(&hash_and_number, &tx_hashes);
585
586 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
589 self.operator
590 .transaction_pool
591 .pool()
592 .validated_pool()
593 .clear_stale(&hash_and_number);
594 }
595}
596
597impl<Runtime, RuntimeApi> DomainNode<Runtime, RuntimeApi>
598where
599 Runtime: frame_system::Config<Hash = H256>
600 + pallet_transaction_payment::Config
601 + DomainRuntime
602 + Send
603 + Sync,
604 RuntimeApi: ConstructRuntimeApi<Block, Client<RuntimeApi>> + Send + Sync + 'static,
605 RuntimeApi::RuntimeApi: Metadata<Block>
606 + BlockBuilder<Block>
607 + OffchainWorkerApi<Block>
608 + SessionKeys<Block>
609 + DomainCoreApi<Block>
610 + TaggedTransactionQueue<Block>
611 + AccountNonceApi<Block, <Runtime as DomainRuntime>::AccountId, Nonce>
612 + TransactionPaymentRuntimeApi<Block, Balance>
613 + MessengerApi<Block, NumberFor<CBlock>, BlockHashFor<CBlock>>
614 + RelayerApi<Block, NumberFor<Block>, NumberFor<CBlock>, BlockHashFor<CBlock>>
615 + EvmOnchainStateApi<Block>,
616{
617 pub fn evm_contract_creation_allowed_by(
620 &self,
621 ) -> PermissionedActionAllowedBy<EthereumAccountId> {
622 self.client
623 .runtime_api()
624 .evm_contract_creation_allowed_by(self.client.info().best_hash)
625 .expect("Failed to get EVM contact creation allow list")
626 .expect("Should be an EVM domain")
627 }
628}
629
630pub struct DomainNodeBuilder {
632 tokio_handle: tokio::runtime::Handle,
633 domain_nodes: Vec<MultiaddrWithPeerId>,
634 domain_nodes_exclusive: bool,
635 skip_empty_bundle_production: bool,
636 base_path: BasePath,
637 maybe_operator_id: Option<OperatorId>,
638 rpc_addr: Option<SocketAddr>,
639 rpc_port: Option<u16>,
640}
641
642impl DomainNodeBuilder {
643 pub fn new(tokio_handle: tokio::runtime::Handle, base_path: BasePath) -> Self {
648 DomainNodeBuilder {
649 tokio_handle,
650 domain_nodes: Vec::new(),
651 domain_nodes_exclusive: false,
652 skip_empty_bundle_production: false,
653 base_path,
654 maybe_operator_id: None,
655 rpc_addr: None,
656 rpc_port: None,
657 }
658 }
659
660 pub fn exclusively_connect_to_registered_parachain_nodes(mut self) -> Self {
664 self.domain_nodes_exclusive = true;
665 self
666 }
667
668 pub fn connect_to_domain_node(mut self, addr: MultiaddrWithPeerId) -> Self {
673 self.domain_nodes.push(addr);
674 self
675 }
676
677 pub fn skip_empty_bundle(mut self) -> Self {
679 self.skip_empty_bundle_production = true;
680 self
681 }
682
683 pub fn operator_id(mut self, operator_id: OperatorId) -> Self {
685 self.maybe_operator_id = Some(operator_id);
686 self
687 }
688
689 pub fn rpc_addr(mut self, addr: SocketAddr) -> Self {
691 self.rpc_addr = Some(addr);
692 self
693 }
694
695 pub fn rpc_port(mut self, port: u16) -> Self {
697 self.rpc_port = Some(port);
698 self
699 }
700
701 fn evm_eth_provider(
702 base_path: &std::path::Path,
703 ) -> EthProvider<
704 evm_domain_test_runtime::TransactionConverter,
705 DefaultEthConfig<
706 FullClient<Block, evm_domain_test_runtime::RuntimeApi>,
707 FullBackend<Block>,
708 >,
709 > {
710 EthProvider::with_configuration(
711 Some(base_path),
712 EthConfiguration {
713 max_past_logs: 10000,
714 fee_history_limit: 2048,
715 enable_dev_signer: true,
716 target_gas_price: 1,
717 execute_gas_limit_multiplier: 10,
718 eth_log_block_cache: 50,
719 eth_statuses_cache: 50,
720 },
721 )
722 }
723
724 pub async fn build_evm_node(
726 self,
727 role: Role,
728 key: EcdsaKeyring,
729 mock_consensus_node: &mut MockConsensusNode,
730 ) -> EvmDomainNode {
731 let domain_base_path = self
732 .base_path
733 .path()
734 .join(format!("domain-{EVM_DOMAIN_ID}"));
735 let eth_provider = Self::evm_eth_provider(&domain_base_path);
736
737 DomainNode::build(
738 EVM_DOMAIN_ID,
739 self.tokio_handle,
740 key,
741 BasePath::new(domain_base_path),
742 self.domain_nodes,
743 self.domain_nodes_exclusive,
744 self.skip_empty_bundle_production,
745 self.maybe_operator_id,
746 role,
747 mock_consensus_node,
748 self.rpc_addr,
749 self.rpc_port,
750 eth_provider,
751 )
752 .await
753 }
754
755 pub async fn build_auto_id_node(
757 self,
758 role: Role,
759 key: Sr25519Keyring,
760 mock_consensus_node: &mut MockConsensusNode,
761 ) -> AutoIdDomainNode {
762 DomainNode::build(
763 AUTO_ID_DOMAIN_ID,
764 self.tokio_handle,
765 key,
766 BasePath::new(
767 self.base_path
768 .path()
769 .join(format!("domain-{AUTO_ID_DOMAIN_ID}")),
770 ),
771 self.domain_nodes,
772 self.domain_nodes_exclusive,
773 self.skip_empty_bundle_production,
774 self.maybe_operator_id,
775 role,
776 mock_consensus_node,
777 self.rpc_addr,
778 self.rpc_port,
779 DefaultProvider,
780 )
781 .await
782 }
783
784 pub async fn build_evm_node_with(
786 self,
787 role: Role,
788 key: EcdsaKeyring,
789 mock_consensus_node: &mut MockConsensusNode,
790 domain_id: DomainId,
791 ) -> EvmDomainNode {
792 let eth_provider = Self::evm_eth_provider(self.base_path.path());
793
794 DomainNode::build(
795 domain_id,
796 self.tokio_handle,
797 key,
798 self.base_path,
799 self.domain_nodes,
800 self.domain_nodes_exclusive,
801 self.skip_empty_bundle_production,
802 self.maybe_operator_id,
803 role,
804 mock_consensus_node,
805 self.rpc_addr,
806 self.rpc_port,
807 eth_provider,
808 )
809 .await
810 }
811}
812
813pub type EvmDomainNode =
815 DomainNode<evm_domain_test_runtime::Runtime, evm_domain_test_runtime::RuntimeApi>;
816
817pub type EvmDomainClient = Client<evm_domain_test_runtime::RuntimeApi>;
819
820pub type AutoIdDomainNode =
822 DomainNode<auto_id_domain_test_runtime::Runtime, auto_id_domain_test_runtime::RuntimeApi>;
823
824pub type AutoIdDomainClient = Client<auto_id_domain_test_runtime::RuntimeApi>;