1use std::{path::PathBuf, sync::Arc};
6
7use fastcrypto::traits::KeyPair;
8use iota_config::{
9 ExecutionCacheConfig,
10 certificate_deny_config::CertificateDenyConfig,
11 genesis::Genesis,
12 node::{AuthorityOverloadConfig, AuthorityStorePruningConfig, ExpensiveSafetyCheckConfig},
13 transaction_deny_config::TransactionDenyConfig,
14 verifier_signing_config::VerifierSigningConfig,
15};
16use iota_network::randomness;
17use iota_protocol_config::{Chain, ProtocolConfig};
18use iota_swarm_config::{genesis_config::AccountConfig, network_config::NetworkConfig};
19use iota_types::{
20 base_types::AuthorityName, crypto::AuthorityKeyPair, digests::ChainIdentifier,
21 executable_transaction::VerifiedExecutableTransaction, iota_system_state::IotaSystemStateTrait,
22 object::Object, supported_protocol_versions::SupportedProtocolVersions,
23 transaction::VerifiedTransaction,
24};
25use prometheus_filtered::Registry;
26
27use super::{
28 ExecutionEnv, backpressure::BackpressureManager, epoch_start_configuration::EpochFlag,
29};
30use crate::{
31 authority::{
32 AuthorityState, AuthorityStore,
33 authority_per_epoch_store::AuthorityPerEpochStore,
34 authority_store_tables::{AuthorityPerpetualTables, AuthorityPerpetualTablesOptions},
35 epoch_start_configuration::EpochStartConfiguration,
36 },
37 checkpoints::CheckpointStore,
38 epoch::{
39 committee_store::CommitteeStore, epoch_metrics::EpochMetrics, randomness::RandomnessManager,
40 },
41 execution_cache::build_execution_cache,
42 grpc_indexes::{GRPC_INDEXES_DIR, GrpcIndexesStore},
43 jsonrpc_index::IndexStore,
44 mock_consensus::{ConsensusMode, MockConsensusClient},
45 module_cache_metrics::ResolverMetrics,
46 signature_verifier::SignatureVerifierMetrics,
47};
48
49#[derive(Default, Clone)]
50pub struct TestAuthorityBuilder<'a> {
51 store_base_path: Option<PathBuf>,
52 store: Option<Arc<AuthorityStore>>,
53 transaction_deny_config: Option<TransactionDenyConfig>,
54 certificate_deny_config: Option<CertificateDenyConfig>,
55 verifier_signing_config: Option<VerifierSigningConfig>,
56 protocol_config: Option<ProtocolConfig>,
57 reference_gas_price: Option<u64>,
58 node_keypair: Option<&'a AuthorityKeyPair>,
59 genesis: Option<&'a Genesis>,
60 starting_objects: Option<&'a [Object]>,
61 expensive_safety_checks: Option<ExpensiveSafetyCheckConfig>,
62 disable_indexer: bool,
63 accounts: Vec<AccountConfig>,
64 insert_genesis_checkpoint: bool,
67 authority_overload_config: Option<AuthorityOverloadConfig>,
68 cache_config: Option<ExecutionCacheConfig>,
69 disable_execute_genesis_transactions: bool,
70 chain_override: Option<Chain>,
71}
72
73impl<'a> TestAuthorityBuilder<'a> {
74 pub fn new() -> Self {
75 Self::default()
76 }
77
78 pub fn with_store_base_path(mut self, path: PathBuf) -> Self {
79 assert!(self.store_base_path.replace(path).is_none());
80 self
81 }
82
83 pub fn with_starting_objects(mut self, objects: &'a [Object]) -> Self {
84 assert!(self.starting_objects.replace(objects).is_none());
85 self
86 }
87
88 pub fn with_store(mut self, store: Arc<AuthorityStore>) -> Self {
89 assert!(self.store.replace(store).is_none());
90 self
91 }
92
93 pub fn with_transaction_deny_config(mut self, config: TransactionDenyConfig) -> Self {
94 assert!(self.transaction_deny_config.replace(config).is_none());
95 self
96 }
97
98 pub fn with_certificate_deny_config(mut self, config: CertificateDenyConfig) -> Self {
99 assert!(self.certificate_deny_config.replace(config).is_none());
100 self
101 }
102
103 pub fn with_verifier_signing_config(mut self, config: VerifierSigningConfig) -> Self {
104 assert!(self.verifier_signing_config.replace(config).is_none());
105 self
106 }
107
108 pub fn with_protocol_config(mut self, config: ProtocolConfig) -> Self {
109 assert!(self.protocol_config.replace(config).is_none());
110 self
111 }
112
113 pub fn with_reference_gas_price(mut self, reference_gas_price: u64) -> Self {
114 assert!(self.genesis.is_none());
117 assert!(
118 self.reference_gas_price
119 .replace(reference_gas_price)
120 .is_none()
121 );
122 self
123 }
124
125 pub fn with_genesis_and_keypair(
126 mut self,
127 genesis: &'a Genesis,
128 keypair: &'a AuthorityKeyPair,
129 ) -> Self {
130 assert!(self.genesis.replace(genesis).is_none());
131 assert!(self.node_keypair.replace(keypair).is_none());
132 self
133 }
134
135 pub fn with_keypair(mut self, keypair: &'a AuthorityKeyPair) -> Self {
136 assert!(self.node_keypair.replace(keypair).is_none());
137 self
138 }
139
140 pub fn with_network_config(self, config: &'a NetworkConfig, node_idx: usize) -> Self {
143 self.with_genesis_and_keypair(
144 &config.genesis,
145 config.validator_configs()[node_idx].authority_key_pair(),
146 )
147 }
148
149 pub fn disable_indexer(mut self) -> Self {
150 self.disable_indexer = true;
151 self
152 }
153
154 pub fn insert_genesis_checkpoint(mut self) -> Self {
155 self.insert_genesis_checkpoint = true;
156 self
157 }
158
159 pub fn with_expensive_safety_checks(mut self, config: ExpensiveSafetyCheckConfig) -> Self {
160 assert!(self.expensive_safety_checks.replace(config).is_none());
161 self
162 }
163
164 pub fn with_accounts(mut self, accounts: Vec<AccountConfig>) -> Self {
165 self.accounts = accounts;
166 self
167 }
168
169 pub fn with_authority_overload_config(mut self, config: AuthorityOverloadConfig) -> Self {
170 assert!(self.authority_overload_config.replace(config).is_none());
171 self
172 }
173
174 pub fn with_cache_config(mut self, config: ExecutionCacheConfig) -> Self {
175 self.cache_config = Some(config);
176 self
177 }
178
179 pub fn disable_execute_genesis_transactions(mut self) -> Self {
180 self.disable_execute_genesis_transactions = true;
181 self
182 }
183
184 pub fn with_chain_override(mut self, chain: Chain) -> Self {
185 self.chain_override = Some(chain);
186 self
187 }
188
189 pub async fn build(self) -> Arc<AuthorityState> {
190 let protocol_config = self.protocol_config.clone();
191
192 let local_network_config = {
199 let _genesis_guard = protocol_config.clone().map(|mut config| {
200 let framework_binary_format_version =
201 ProtocolConfig::get_for_version(config.version, Chain::Unknown)
202 .move_binary_format_version();
203 config.set_move_binary_format_version_for_testing(framework_binary_format_version);
204 ProtocolConfig::apply_overrides_for_testing(move |_, _| config.clone())
205 });
206
207 let mut local_network_config_builder =
208 iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir()
209 .with_accounts(self.accounts)
210 .with_reference_gas_price(self.reference_gas_price.unwrap_or(500));
211 if let Some(protocol_config) = &self.protocol_config {
212 local_network_config_builder =
213 local_network_config_builder.with_protocol_version(protocol_config.version);
214 }
215 local_network_config_builder.build()
216 };
217
218 let _guard = protocol_config
221 .map(|config| ProtocolConfig::apply_overrides_for_testing(move |_, _| config.clone()));
222
223 let genesis = &self.genesis.unwrap_or(&local_network_config.genesis);
224 let genesis_committee = genesis.committee().unwrap();
225 let storage_dir = self
226 .store_base_path
227 .unwrap_or_else(|| iota_common::tempdir().keep());
228 let mut config = local_network_config.validator_configs()[0].clone();
229 let registry = Registry::new();
230 let authority_store = match self.store {
231 Some(store) => store,
232 None => {
233 let perpetual_tables_options = AuthorityPerpetualTablesOptions::default();
234 let perpetual_tables = Arc::new(AuthorityPerpetualTables::open(
235 &storage_dir.join("store"),
236 Some(perpetual_tables_options),
237 ));
238 AuthorityStore::open_with_committee_for_testing(
240 perpetual_tables,
241 &genesis_committee,
242 genesis,
243 )
244 .await
245 .unwrap()
246 }
247 };
248 if let Some(cache_config) = self.cache_config {
249 config.execution_cache_config = cache_config;
250 }
251
252 let keypair = if let Some(keypair) = self.node_keypair {
253 keypair.copy()
254 } else {
255 config.authority_key_pair().copy()
256 };
257
258 let secret = Arc::pin(keypair.copy());
259 let name: AuthorityName = secret.public().into();
260 let cache_metrics = Arc::new(ResolverMetrics::new(®istry));
261 let signature_verifier_metrics = SignatureVerifierMetrics::new(®istry);
262 let epoch_flags = EpochFlag::default_flags_for_new_epoch(&config);
263 let epoch_start_configuration = EpochStartConfiguration::new(
264 genesis.iota_system_object().into_epoch_start_state(),
265 *genesis.checkpoint().digest(),
266 &genesis.objects(),
267 epoch_flags,
268 )
269 .unwrap();
270 let expensive_safety_checks = self.expensive_safety_checks.unwrap_or_default();
271
272 let checkpoint_store = CheckpointStore::new(&storage_dir.join("checkpoints"));
273 let backpressure_manager =
274 BackpressureManager::new_from_checkpoint_store(&checkpoint_store);
275
276 let cache_traits = build_execution_cache(
277 &config.execution_cache_config,
278 ®istry,
279 &authority_store,
280 backpressure_manager.clone(),
281 );
282
283 let chain_id = ChainIdentifier::from(*genesis.checkpoint().digest());
284 let chain = match self.chain_override {
285 Some(chain) => chain,
286 None => chain_id.chain(),
287 };
288
289 let epoch_store = AuthorityPerEpochStore::new(
290 name,
291 Arc::new(genesis_committee.clone()),
292 &storage_dir.join("store"),
293 None,
294 EpochMetrics::new(®istry),
295 epoch_start_configuration,
296 cache_traits.backing_package_store.clone(),
297 cache_metrics,
298 signature_verifier_metrics,
299 &expensive_safety_checks,
300 (chain_id, chain),
301 checkpoint_store
302 .get_highest_executed_checkpoint_seq_number()
303 .unwrap()
304 .unwrap_or(0),
305 )
306 .expect("failed to create authority per epoch store");
307 let committee_store = Arc::new(CommitteeStore::new(
308 storage_dir.join("epochs"),
309 &genesis_committee,
310 None,
311 ));
312
313 if self.insert_genesis_checkpoint {
314 checkpoint_store.insert_genesis_checkpoint(
315 genesis.checkpoint(),
316 genesis.checkpoint_contents().clone(),
317 &epoch_store,
318 );
319 }
320 let index_store = if self.disable_indexer {
321 None
322 } else {
323 Some(Arc::new(IndexStore::new(
324 storage_dir.join("indexes"),
325 ®istry,
326 epoch_store
327 .protocol_config()
328 .max_move_identifier_len_as_option(),
329 )))
330 };
331 let grpc_indexes_store = if self.disable_indexer {
332 None
333 } else {
334 Some(Arc::new(
335 GrpcIndexesStore::new(
336 storage_dir.join(GRPC_INDEXES_DIR),
337 Arc::clone(&authority_store),
338 &checkpoint_store,
339 )
340 .await,
341 ))
342 };
343
344 let transaction_deny_config = self.transaction_deny_config.unwrap_or_default();
345 let certificate_deny_config = self.certificate_deny_config.unwrap_or_default();
346 let verifier_signing_config = self.verifier_signing_config.unwrap_or_default();
347 let authority_overload_config = self.authority_overload_config.unwrap_or_default();
348 let pruning_config = AuthorityStorePruningConfig::default();
349
350 config.transaction_deny_config = transaction_deny_config;
351 config.certificate_deny_config = certificate_deny_config;
352 config.verifier_signing_config = verifier_signing_config;
353 config.authority_overload_config = authority_overload_config;
354 config.authority_store_pruning_config = pruning_config;
355
356 let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest());
357 let policy_config = config.policy_config.clone();
358 let firewall_config = config.firewall_config.clone();
359
360 let state = AuthorityState::new(
361 name,
362 secret,
363 SupportedProtocolVersions::SYSTEM_DEFAULT,
364 authority_store,
365 cache_traits,
366 epoch_store.clone(),
367 committee_store,
368 index_store,
369 grpc_indexes_store,
370 checkpoint_store,
371 ®istry,
372 genesis.objects(),
373 config.clone(),
374 None,
375 chain_identifier,
376 None,
377 policy_config,
378 firewall_config,
379 )
380 .await;
381
382 let consensus_client = Box::new(MockConsensusClient::new(
384 Arc::downgrade(&state),
385 ConsensusMode::Noop,
386 ));
387 let randomness_manager = RandomnessManager::try_new(
388 Arc::downgrade(&epoch_store),
389 consensus_client,
390 randomness::Handle::new_stub(),
391 &keypair,
392 )
393 .await;
394 if let Ok(randomness_manager) = randomness_manager {
395 epoch_store
398 .set_randomness_manager(randomness_manager)
399 .await
400 .unwrap();
401 }
402
403 if !self.disable_execute_genesis_transactions {
404 state
410 .try_execute_immediately(
411 &VerifiedExecutableTransaction::new_from_checkpoint(
412 VerifiedTransaction::new_unchecked(genesis.transaction().clone()),
413 genesis.epoch(),
414 genesis.checkpoint().sequence_number,
415 ),
416 ExecutionEnv::new(),
417 &state.epoch_store_for_testing(),
418 )
419 .unwrap();
420
421 let batch = state.get_cache_commit().build_db_batch(
422 epoch_store.epoch(),
423 genesis.checkpoint().sequence_number,
424 &[*genesis.transaction().digest()],
425 );
426
427 state.get_cache_commit().commit_transaction_outputs(
428 epoch_store.epoch(),
429 batch,
430 &[*genesis.transaction().digest()],
431 );
432 }
433
434 if let Some(starting_objects) = self.starting_objects {
440 state
441 .insert_objects_unsafe_for_testing_only(starting_objects)
442 .await;
443 };
444 state
445 }
446}