1use std::{collections::BTreeSet, 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, authority_per_epoch_store::AuthorityPerEpochStore,
33 authority_store_tables::AuthorityPerpetualTables,
34 epoch_start_configuration::EpochStartConfiguration,
35 },
36 checkpoints::CheckpointStore,
37 epoch::{
38 committee_store::CommitteeStore, epoch_metrics::EpochMetrics, randomness::RandomnessManager,
39 },
40 execution_cache::build_execution_cache,
41 mock_consensus::{ConsensusMode, MockConsensusClient},
42 module_cache_metrics::ResolverMetrics,
43 rpc_indexes::{
44 RpcIndexesStore,
45 schema::{IndexGroup, RPC_INDEXES_DIR},
46 },
47 signature_verifier::SignatureVerifierMetrics,
48};
49
50#[derive(Default, Clone)]
51pub struct TestAuthorityBuilder<'a> {
52 store_base_path: Option<PathBuf>,
53 store: Option<Arc<AuthorityStore>>,
54 transaction_deny_config: Option<TransactionDenyConfig>,
55 certificate_deny_config: Option<CertificateDenyConfig>,
56 verifier_signing_config: Option<VerifierSigningConfig>,
57 protocol_config: Option<ProtocolConfig>,
58 reference_gas_price: Option<u64>,
59 node_keypair: Option<&'a AuthorityKeyPair>,
60 genesis: Option<&'a Genesis>,
61 starting_objects: Option<&'a [Object]>,
62 expensive_safety_checks: Option<ExpensiveSafetyCheckConfig>,
63 disable_indexer: bool,
64 accounts: Vec<AccountConfig>,
65 insert_genesis_checkpoint: bool,
68 authority_overload_config: Option<AuthorityOverloadConfig>,
69 cache_config: Option<ExecutionCacheConfig>,
70 disable_execute_genesis_transactions: bool,
71 chain_override: Option<Chain>,
72 num_epochs_to_retain: Option<u64>,
73 num_epochs_to_retain_for_checkpoints: Option<u64>,
74 num_epochs_to_retain_for_indexes: Option<u64>,
75}
76
77impl<'a> TestAuthorityBuilder<'a> {
78 pub fn new() -> Self {
79 Self::default()
80 }
81
82 pub fn with_store_base_path(mut self, path: PathBuf) -> Self {
83 assert!(self.store_base_path.replace(path).is_none());
84 self
85 }
86
87 pub fn with_starting_objects(mut self, objects: &'a [Object]) -> Self {
88 assert!(self.starting_objects.replace(objects).is_none());
89 self
90 }
91
92 pub fn with_store(mut self, store: Arc<AuthorityStore>) -> Self {
93 assert!(self.store.replace(store).is_none());
94 self
95 }
96
97 pub fn with_transaction_deny_config(mut self, config: TransactionDenyConfig) -> Self {
98 assert!(self.transaction_deny_config.replace(config).is_none());
99 self
100 }
101
102 pub fn with_certificate_deny_config(mut self, config: CertificateDenyConfig) -> Self {
103 assert!(self.certificate_deny_config.replace(config).is_none());
104 self
105 }
106
107 pub fn with_verifier_signing_config(mut self, config: VerifierSigningConfig) -> Self {
108 assert!(self.verifier_signing_config.replace(config).is_none());
109 self
110 }
111
112 pub fn with_protocol_config(mut self, config: ProtocolConfig) -> Self {
113 assert!(self.protocol_config.replace(config).is_none());
114 self
115 }
116
117 pub fn with_reference_gas_price(mut self, reference_gas_price: u64) -> Self {
118 assert!(self.genesis.is_none());
121 assert!(
122 self.reference_gas_price
123 .replace(reference_gas_price)
124 .is_none()
125 );
126 self
127 }
128
129 pub fn with_genesis_and_keypair(
130 mut self,
131 genesis: &'a Genesis,
132 keypair: &'a AuthorityKeyPair,
133 ) -> Self {
134 assert!(self.genesis.replace(genesis).is_none());
135 assert!(self.node_keypair.replace(keypair).is_none());
136 self
137 }
138
139 pub fn with_keypair(mut self, keypair: &'a AuthorityKeyPair) -> Self {
140 assert!(self.node_keypair.replace(keypair).is_none());
141 self
142 }
143
144 pub fn with_network_config(self, config: &'a NetworkConfig, node_idx: usize) -> Self {
147 self.with_genesis_and_keypair(
148 &config.genesis,
149 config.validator_configs()[node_idx].authority_key_pair(),
150 )
151 }
152
153 pub fn disable_indexer(mut self) -> Self {
154 self.disable_indexer = true;
155 self
156 }
157
158 pub fn insert_genesis_checkpoint(mut self) -> Self {
159 self.insert_genesis_checkpoint = true;
160 self
161 }
162
163 pub fn with_expensive_safety_checks(mut self, config: ExpensiveSafetyCheckConfig) -> Self {
164 assert!(self.expensive_safety_checks.replace(config).is_none());
165 self
166 }
167
168 pub fn with_accounts(mut self, accounts: Vec<AccountConfig>) -> Self {
169 self.accounts = accounts;
170 self
171 }
172
173 pub fn with_authority_overload_config(mut self, config: AuthorityOverloadConfig) -> Self {
174 assert!(self.authority_overload_config.replace(config).is_none());
175 self
176 }
177
178 pub fn with_cache_config(mut self, config: ExecutionCacheConfig) -> Self {
179 self.cache_config = Some(config);
180 self
181 }
182
183 pub fn disable_execute_genesis_transactions(mut self) -> Self {
184 self.disable_execute_genesis_transactions = true;
185 self
186 }
187
188 pub fn with_num_epochs_to_retain(mut self, num_epochs_to_retain: u64) -> Self {
191 assert!(
192 self.num_epochs_to_retain
193 .replace(num_epochs_to_retain)
194 .is_none()
195 );
196 self
197 }
198
199 pub fn with_num_epochs_to_retain_for_checkpoints(mut self, num_epochs_to_retain: u64) -> Self {
203 assert!(
204 self.num_epochs_to_retain_for_checkpoints
205 .replace(num_epochs_to_retain)
206 .is_none()
207 );
208 self
209 }
210
211 pub fn with_num_epochs_to_retain_for_indexes(mut self, num_epochs_to_retain: u64) -> Self {
214 assert!(
215 self.num_epochs_to_retain_for_indexes
216 .replace(num_epochs_to_retain)
217 .is_none()
218 );
219 self
220 }
221
222 pub fn with_chain_override(mut self, chain: Chain) -> Self {
223 self.chain_override = Some(chain);
224 self
225 }
226
227 pub async fn build(self) -> Arc<AuthorityState> {
228 let protocol_config = self.protocol_config.clone();
229
230 let local_network_config = {
237 let _genesis_guard = protocol_config.clone().map(|mut config| {
238 let framework_binary_format_version =
239 ProtocolConfig::get_for_version(config.version, Chain::Unknown)
240 .move_binary_format_version();
241 config.set_move_binary_format_version_for_testing(framework_binary_format_version);
242 ProtocolConfig::apply_overrides_for_testing(move |_, _| config.clone())
243 });
244
245 let mut local_network_config_builder =
246 iota_swarm_config::network_config_builder::ConfigBuilder::new_with_temp_dir()
247 .with_accounts(self.accounts)
248 .with_reference_gas_price(self.reference_gas_price.unwrap_or(500));
249 if let Some(protocol_config) = &self.protocol_config {
250 local_network_config_builder =
251 local_network_config_builder.with_protocol_version(protocol_config.version);
252 }
253 local_network_config_builder.build()
254 };
255
256 let _guard = protocol_config
259 .map(|config| ProtocolConfig::apply_overrides_for_testing(move |_, _| config.clone()));
260
261 let genesis = &self.genesis.unwrap_or(&local_network_config.genesis);
262 let genesis_committee = genesis.committee().unwrap();
263 let storage_dir = self
264 .store_base_path
265 .unwrap_or_else(|| iota_common::tempdir().keep());
266 let mut config = local_network_config.validator_configs()[0].clone();
267 let registry = Registry::new();
268
269 let authority_store = match self.store {
270 Some(store) => store,
271 None => {
272 let (perpetual_tables, historic_objects, historic_ledger, epoch_markers) =
274 AuthorityPerpetualTables::open_with_historic_objects(
275 &storage_dir.join("store"),
276 None,
277 )
278 .unwrap();
279 AuthorityStore::open_with_committee_for_testing(
280 Arc::new(perpetual_tables),
281 Arc::new(historic_objects),
282 Arc::new(historic_ledger),
283 Arc::new(epoch_markers),
284 &genesis_committee,
285 genesis,
286 )
287 .await
288 .unwrap()
289 }
290 };
291 if let Some(cache_config) = self.cache_config {
292 config.execution_cache_config = cache_config;
293 }
294
295 let keypair = if let Some(keypair) = self.node_keypair {
296 keypair.copy()
297 } else {
298 config.authority_key_pair().copy()
299 };
300
301 let secret = Arc::pin(keypair.copy());
302 let name: AuthorityName = secret.public().into();
303 let cache_metrics = Arc::new(ResolverMetrics::new(®istry));
304 let signature_verifier_metrics = SignatureVerifierMetrics::new(®istry);
305 let epoch_flags = EpochFlag::default_flags_for_new_epoch(&config);
306 let epoch_start_configuration = EpochStartConfiguration::new(
307 genesis.iota_system_object().into_epoch_start_state(),
308 *genesis.checkpoint().digest(),
309 &genesis.objects(),
310 epoch_flags,
311 )
312 .unwrap();
313 let expensive_safety_checks = self.expensive_safety_checks.unwrap_or_default();
314
315 let checkpoint_store = CheckpointStore::new(&storage_dir.join("checkpoints"));
316 let backpressure_manager =
317 BackpressureManager::new_from_checkpoint_store(&checkpoint_store);
318
319 let cache_traits = build_execution_cache(
320 &config.execution_cache_config,
321 ®istry,
322 &authority_store,
323 backpressure_manager.clone(),
324 );
325
326 let chain_id = ChainIdentifier::from(*genesis.checkpoint().digest());
327 let chain = match self.chain_override {
328 Some(chain) => chain,
329 None => chain_id.chain(),
330 };
331
332 let epoch_store = AuthorityPerEpochStore::new(
333 name,
334 Arc::new(genesis_committee.clone()),
335 &storage_dir.join("store"),
336 None,
337 EpochMetrics::new(®istry),
338 epoch_start_configuration,
339 cache_traits.backing_package_store.clone(),
340 cache_metrics,
341 signature_verifier_metrics,
342 &expensive_safety_checks,
343 (chain_id, chain),
344 checkpoint_store
345 .get_highest_executed_checkpoint_seq_number()
346 .unwrap()
347 .unwrap_or(0),
348 )
349 .expect("failed to create authority per epoch store");
350 let committee_store = Arc::new(CommitteeStore::new(
351 storage_dir.join("epochs"),
352 &genesis_committee,
353 None,
354 ));
355
356 if self.insert_genesis_checkpoint {
357 checkpoint_store.insert_genesis_checkpoint(
358 genesis.checkpoint(),
359 genesis.checkpoint_contents().clone(),
360 &epoch_store,
361 );
362 }
363 let rpc_indexes_store = if self.disable_indexer {
364 None
365 } else {
366 Some(
367 RpcIndexesStore::new(
368 storage_dir.join(RPC_INDEXES_DIR),
369 None,
370 ®istry,
371 BTreeSet::from([IndexGroup::JsonRpc, IndexGroup::Grpc]),
372 epoch_store
373 .protocol_config()
374 .max_move_identifier_len_as_option(),
375 self.num_epochs_to_retain_for_indexes,
376 &authority_store,
377 &checkpoint_store,
378 Arc::default(),
379 )
380 .await
381 .expect("failed to open the RPC index store"),
382 )
383 };
384
385 let transaction_deny_config = self.transaction_deny_config.unwrap_or_default();
386 let certificate_deny_config = self.certificate_deny_config.unwrap_or_default();
387 let verifier_signing_config = self.verifier_signing_config.unwrap_or_default();
388 let authority_overload_config = self.authority_overload_config.unwrap_or_default();
389 let mut pruning_config = AuthorityStorePruningConfig::default();
390 if let Some(num_epochs_to_retain) = self.num_epochs_to_retain {
391 pruning_config.set_num_epochs_to_retain(num_epochs_to_retain);
392 }
393 if let Some(num_epochs_to_retain) = self.num_epochs_to_retain_for_checkpoints {
394 pruning_config.set_num_epochs_to_retain_for_checkpoints(Some(num_epochs_to_retain));
395 }
396
397 config.transaction_deny_config = transaction_deny_config;
398 config.certificate_deny_config = certificate_deny_config;
399 config.verifier_signing_config = verifier_signing_config;
400 config.authority_overload_config = authority_overload_config;
401 config.authority_store_pruning_config = pruning_config;
402
403 let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest());
404 let policy_config = config.policy_config.clone();
405
406 let state = AuthorityState::new(
407 name,
408 secret,
409 SupportedProtocolVersions::SYSTEM_DEFAULT,
410 authority_store,
411 cache_traits,
412 epoch_store.clone(),
413 committee_store,
414 rpc_indexes_store,
415 checkpoint_store,
416 ®istry,
417 config.clone(),
418 None,
419 chain_identifier,
420 policy_config,
421 None,
422 )
423 .await;
424
425 let consensus_client = Box::new(MockConsensusClient::new(
427 Arc::downgrade(&state),
428 ConsensusMode::Noop,
429 ));
430 let randomness_manager = RandomnessManager::try_new(
431 Arc::downgrade(&epoch_store),
432 consensus_client,
433 randomness::Handle::new_stub(),
434 &keypair,
435 )
436 .await;
437 if let Ok(randomness_manager) = randomness_manager {
438 epoch_store
441 .set_randomness_manager(randomness_manager)
442 .await
443 .unwrap();
444 }
445
446 if !self.disable_execute_genesis_transactions {
447 state
453 .try_execute_immediately(
454 &VerifiedExecutableTransaction::new_from_checkpoint(
455 VerifiedTransaction::new_unchecked(genesis.transaction().clone()),
456 genesis.epoch(),
457 genesis.checkpoint().sequence_number,
458 ),
459 ExecutionEnv::new(),
460 &state.epoch_store_for_testing(),
461 )
462 .unwrap();
463
464 let batch = state.get_cache_commit().build_db_batch(
465 epoch_store.epoch(),
466 genesis.checkpoint().sequence_number,
467 &[*genesis.transaction().digest()],
468 );
469
470 state.get_cache_commit().commit_transaction_outputs(
471 epoch_store.epoch(),
472 batch,
473 &[*genesis.transaction().digest()],
474 );
475 }
476
477 if let Some(starting_objects) = self.starting_objects {
483 state
484 .insert_objects_unsafe_for_testing_only(starting_objects)
485 .await;
486 };
487 state
488 }
489}