1#![allow(clippy::result_large_err)]
2
3use bitcoin::Block;
4use bitcoin::consensus::Decodable;
5use bitcoin::hex::FromHex;
6use sc_consensus_nakamoto::{
7 BitcoinBlockImport, BitcoinBlockImporter, BlockVerification, ImportConfig, ImportStatus,
8 ScriptEngine,
9};
10use sc_service::config::{
11 BlocksPruning, DatabaseSource, ExecutorConfiguration, KeystoreConfig, NetworkConfiguration,
12 OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, RpcConfiguration,
13 WasmExecutionMethod, WasmtimeInstantiationStrategy,
14};
15use sc_service::error::Error as ServiceError;
16use sc_service::{BasePath, ChainSpec, Configuration, Role};
17use sp_consensus::BlockOrigin;
18use sp_keyring::sr25519::Keyring as Sr25519Keyring;
19use std::sync::Arc;
20use subcoin_service::{FullClient, NodeComponents, SubcoinConfiguration};
21
22fn decode_raw_block(hex_str: &str) -> Block {
23 let data = Vec::<u8>::from_hex(hex_str).expect("Failed to convert hex str");
24 Block::consensus_decode(&mut data.as_slice()).expect("Failed to convert hex data to Block")
25}
26
27pub fn block_data() -> Vec<Block> {
28 let block0 = decode_raw_block(
30 "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",
31 );
32 let block1 = decode_raw_block(
35 "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e362990101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000",
36 );
37 let block2 = decode_raw_block(
40 "010000004860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36ef744ee42c316022c90f9bb0bc6649ffff001d08d2bd610101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000",
41 );
42 let block3 = decode_raw_block(
45 "01000000bddd99ccfda39da1b108ce1a5d70038d0a967bacb68b6b63065f626a0000000044f672226090d85db9a9f2fbfe5f0f9609b387af7be5b7fbb7a1767c831c9e995dbe6649ffff001d05e0ed6d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010effffffff0100f2052a0100000043410494b9d3e76c5b1629ecf97fff95d7a4bbdac87cc26099ada28066c6ff1eb9191223cd897194a08d0c2726c5747f1db49e8cf90e75dc3e3550ae9b30086f3cd5aaac00000000",
46 );
47 vec![block0, block1, block2, block3]
48}
49
50pub fn full_test_configuration(
51 tokio_handle: tokio::runtime::Handle,
52 chain_spec: Box<dyn ChainSpec>,
53) -> Configuration {
54 let tmp = tempfile::tempdir().unwrap();
55 let base_path = BasePath::new(tmp.path());
56 let root = base_path.path().to_path_buf();
57
58 let network_config = NetworkConfiguration::new(
59 Sr25519Keyring::Alice.to_seed(),
60 "network/test/0.1",
61 Default::default(),
62 None,
63 );
64
65 Configuration {
66 impl_name: "subcoin-test-node".to_string(),
67 impl_version: "1.0".to_string(),
68 role: Role::Full,
69 tokio_handle,
70 transaction_pool: Default::default(),
71 network: network_config,
72 keystore: KeystoreConfig::InMemory,
73 database: DatabaseSource::ParityDb {
74 path: root.join("db"),
75 },
76 trie_cache_maximum_size: Some(64 * 1024 * 1024),
77 state_pruning: Some(PruningMode::ArchiveAll),
78 blocks_pruning: BlocksPruning::KeepAll,
79 chain_spec,
80 executor: ExecutorConfiguration {
81 wasm_method: WasmExecutionMethod::Compiled {
82 instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
83 },
84 max_runtime_instances: 8,
85 runtime_cache_size: 2,
86 default_heap_pages: None,
87 },
88 rpc: RpcConfiguration {
89 addr: None,
90 max_connections: Default::default(),
91 cors: None,
92 methods: Default::default(),
93 max_request_size: Default::default(),
94 max_response_size: Default::default(),
95 id_provider: Default::default(),
96 max_subs_per_conn: Default::default(),
97 port: 9944,
98 message_buffer_capacity: Default::default(),
99 batch_config: RpcBatchRequestConfig::Unlimited,
100 rate_limit: None,
101 rate_limit_whitelisted_ips: Default::default(),
102 rate_limit_trust_proxy_headers: Default::default(),
103 },
104 prometheus_config: None,
105 telemetry_endpoints: None,
106 offchain_worker: OffchainWorkerConfig {
107 enabled: true,
108 indexing_enabled: false,
109 },
110 force_authoring: false,
111 disable_grandpa: false,
112 dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()),
113 tracing_targets: None,
114 tracing_receiver: Default::default(),
115 announce_block: true,
116 data_path: base_path.path().into(),
117 base_path,
118 wasm_runtime_overrides: None,
119 warm_up_trie_cache: None,
120 }
121}
122
123pub fn test_configuration(tokio_handle: tokio::runtime::Handle) -> Configuration {
124 let spec = subcoin_service::chain_spec::config(bitcoin::Network::Bitcoin)
125 .expect("Failed to create chain spec");
126
127 full_test_configuration(tokio_handle, Box::new(spec))
128}
129
130pub fn new_test_node(tokio_handle: tokio::runtime::Handle) -> Result<NodeComponents, ServiceError> {
131 let config = test_configuration(tokio_handle);
132 subcoin_service::new_node(SubcoinConfiguration {
133 network: bitcoin::Network::Bitcoin,
134 config: &config,
135 no_hardware_benchmarks: true,
136 storage_monitor: Default::default(),
137 })
138}
139
140pub async fn new_test_node_and_produce_blocks(
141 config: &Configuration,
142 up_to: u32,
143) -> Arc<FullClient> {
144 let NodeComponents { client, .. } =
145 subcoin_service::new_node(SubcoinConfiguration::test_config(config))
146 .expect("Failed to create node");
147
148 let mut bitcoin_block_import =
149 BitcoinBlockImporter::<_, _, _, _, subcoin_service::TransactionAdapter>::new(
150 client.clone(),
151 client.clone(),
152 ImportConfig {
153 network: bitcoin::Network::Bitcoin,
154 block_verification: BlockVerification::None,
155 execute_block: true,
156 script_engine: ScriptEngine::Core,
157 },
158 Arc::new(subcoin_service::CoinStorageKey),
159 None,
160 );
161
162 let test_blocks = block_data();
163
164 if up_to as usize >= test_blocks.len() {
165 panic!(
166 "Can not produce too many blocks (maximum: {}) in test env",
167 test_blocks.len()
168 );
169 }
170
171 for block_number in 1..=up_to {
172 let block = test_blocks[block_number as usize].clone();
173 let import_status = bitcoin_block_import
174 .import_block(block, BlockOrigin::Own)
175 .await
176 .unwrap();
177 assert!(matches!(import_status, ImportStatus::Imported { .. }));
178 }
179
180 client
181}