iota_single_node_benchmark/
single_node.rs1use std::{
6 collections::{BTreeMap, HashMap, HashSet},
7 sync::Arc,
8};
9
10use iota_core::{
11 authority::{
12 AuthorityState, authority_per_epoch_store::AuthorityPerEpochStore,
13 authority_store_tables::LiveObject, test_authority_builder::TestAuthorityBuilder,
14 },
15 authority_server::{ValidatorService, ValidatorServiceMetrics},
16 checkpoints::checkpoint_executor::CheckpointExecutor,
17 consensus_adapter::{
18 ConnectionMonitorStatusForTests, ConsensusAdapter, ConsensusAdapterMetrics,
19 },
20 mock_consensus::{ConsensusMode, MockConsensusClient},
21 state_accumulator::StateAccumulator,
22};
23use iota_test_transaction_builder::{PublishData, TestTransactionBuilder};
24use iota_types::{
25 base_types::{AuthorityName, IotaAddress, ObjectRef, TransactionDigest},
26 committee::Committee,
27 crypto::{AccountKeyPair, AuthoritySignature, Signer},
28 effects::{TransactionEffects, TransactionEffectsAPI},
29 executable_transaction::VerifiedExecutableTransaction,
30 messages_checkpoint::{VerifiedCheckpoint, VerifiedCheckpointContents},
31 messages_grpc::HandleTransactionResponse,
32 mock_checkpoint_builder::{MockCheckpointBuilder, ValidatorKeypairProvider},
33 object::Object,
34 transaction::{
35 CertifiedTransaction, DEFAULT_VALIDATOR_GAS_PRICE, Transaction, TransactionDataAPI,
36 VerifiedCertificate, VerifiedTransaction,
37 },
38};
39
40use crate::{command::Component, mock_storage::InMemoryObjectStore};
41
42#[derive(Clone)]
43pub struct SingleValidator {
44 validator_service: Arc<ValidatorService>,
45 epoch_store: Arc<AuthorityPerEpochStore>,
46}
47
48impl SingleValidator {
49 pub(crate) async fn new(genesis_objects: &[Object], component: Component) -> Self {
50 let validator = TestAuthorityBuilder::new()
51 .disable_indexer()
52 .with_starting_objects(genesis_objects)
53 .insert_genesis_checkpoint()
55 .build()
56 .await;
57 let epoch_store = validator.epoch_store_for_testing().clone();
58 let consensus_mode = match component {
59 Component::ValidatorWithFakeConsensus => ConsensusMode::DirectSequencing,
60 _ => ConsensusMode::Noop,
61 };
62 let consensus_adapter = Arc::new(ConsensusAdapter::new(
63 Arc::new(MockConsensusClient::new(
64 Arc::downgrade(&validator),
65 consensus_mode,
66 )),
67 validator.checkpoint_store.clone(),
68 validator.name,
69 Arc::new(ConnectionMonitorStatusForTests {}),
70 100_000,
71 100_000,
72 None,
73 None,
74 ConsensusAdapterMetrics::new_test(),
75 ));
76 let validator_service = Arc::new(ValidatorService::new_for_tests(
80 validator,
81 consensus_adapter,
82 Arc::new(ValidatorServiceMetrics::new_for_tests()),
83 ));
84 Self {
85 validator_service,
86 epoch_store,
87 }
88 }
89
90 pub fn get_validator(&self) -> &Arc<AuthorityState> {
91 self.validator_service.validator_state()
92 }
93
94 pub fn get_epoch_store(&self) -> &Arc<AuthorityPerEpochStore> {
95 &self.epoch_store
96 }
97
98 pub async fn publish_package(
101 &self,
102 publish_data: PublishData,
103 sender: IotaAddress,
104 keypair: &AccountKeyPair,
105 gas: ObjectRef,
106 ) -> (ObjectRef, ObjectRef) {
107 let tx_builder = TestTransactionBuilder::new(sender, gas, DEFAULT_VALIDATOR_GAS_PRICE)
108 .publish_with_data(publish_data);
109 let transaction = tx_builder.build_and_sign(keypair);
110 let effects = self.execute_raw_transaction(transaction).await;
111 let package = effects
112 .all_changed_objects()
113 .into_iter()
114 .filter_map(|(oref, owner, _)| owner.is_immutable().then_some(oref))
115 .next()
116 .unwrap();
117 let updated_gas = effects.gas_object().0;
118 (package, updated_gas)
119 }
120
121 pub async fn execute_raw_transaction(&self, transaction: Transaction) -> TransactionEffects {
122 let executable = VerifiedExecutableTransaction::new_from_quorum_execution(
123 VerifiedTransaction::new_unchecked(transaction),
124 0,
125 );
126 let effects = self
127 .get_validator()
128 .try_execute_immediately(&executable, None, &self.epoch_store)
129 .unwrap()
130 .0;
131 assert!(effects.status().is_ok());
132 effects
133 }
134
135 pub async fn execute_dry_run(&self, transaction: Transaction) -> TransactionEffects {
136 let effects = self
137 .get_validator()
138 .dry_exec_transaction_for_benchmark(
139 transaction.data().intent_message().value.clone(),
140 *transaction.digest(),
141 )
142 .unwrap()
143 .2;
144 assert!(effects.status().is_ok());
145 effects
146 }
147
148 pub async fn execute_certificate(
149 &self,
150 cert: CertifiedTransaction,
151 component: Component,
152 ) -> TransactionEffects {
153 let effects = match component {
154 Component::Baseline => {
155 let cert = VerifiedExecutableTransaction::new_from_certificate(
156 VerifiedCertificate::new_unchecked(cert),
157 );
158 self.get_validator()
159 .try_execute_immediately(&cert, None, &self.epoch_store)
160 .unwrap()
161 .0
162 }
163 Component::WithTxManager => {
164 let cert = VerifiedCertificate::new_unchecked(cert);
165 if cert.contains_shared_object() {
166 self.get_validator()
170 .enqueue_certificates_for_execution(vec![cert.clone()], &self.epoch_store);
171 }
172 self.get_validator()
173 .execute_certificate(&cert, &self.epoch_store)
174 .await
175 .unwrap()
176 }
177 Component::ValidatorWithoutConsensus | Component::ValidatorWithFakeConsensus => {
178 let response = self
179 .validator_service
180 .execute_certificate_for_testing(cert)
181 .await
182 .unwrap()
183 .into_inner();
184 response.signed_effects.into_data()
185 }
186 Component::TxnSigning | Component::CheckpointExecutor | Component::ExecutionOnly => {
187 unreachable!()
188 }
189 };
190 assert!(effects.status().is_ok());
191 effects
192 }
193
194 pub(crate) async fn execute_transaction_in_memory(
195 &self,
196 store: InMemoryObjectStore,
197 transaction: CertifiedTransaction,
198 ) -> TransactionEffects {
199 let input_objects = transaction.transaction_data().input_objects().unwrap();
200 let objects = store
201 .read_objects_for_execution(&self.epoch_store, &transaction.key(), &input_objects)
202 .unwrap();
203
204 let executable = VerifiedExecutableTransaction::new_from_certificate(
205 VerifiedCertificate::new_unchecked(transaction),
206 );
207 let (gas_status, input_objects) = iota_transaction_checks::check_certificate_input(
208 &executable,
209 objects,
210 self.epoch_store.protocol_config(),
211 self.epoch_store.reference_gas_price(),
212 )
213 .unwrap();
214 let (kind, signer, gas) = executable.transaction_data().execution_parts();
215 let (inner_temp_store, _, effects, _) =
216 self.epoch_store.executor().execute_transaction_to_effects(
217 &store,
218 self.epoch_store.protocol_config(),
219 self.get_validator().metrics.limits_metrics.clone(),
220 false,
221 &HashSet::new(),
222 &self.epoch_store.epoch(),
223 0,
224 input_objects,
225 gas,
226 gas_status,
227 kind,
228 signer,
229 *executable.digest(),
230 &mut None,
231 );
232 assert!(effects.status().is_ok());
233 store.commit_objects(inner_temp_store);
234 effects
235 }
236
237 pub async fn sign_transaction(&self, transaction: Transaction) -> HandleTransactionResponse {
238 self.validator_service
239 .handle_transaction_for_benchmarking(transaction)
240 .await
241 .unwrap()
242 .into_inner()
243 }
244
245 pub(crate) async fn build_checkpoints(
246 &self,
247 transactions: Vec<CertifiedTransaction>,
248 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
249 checkpoint_size: usize,
250 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
251 let mut builder = MockCheckpointBuilder::new(
252 self.get_validator()
253 .get_checkpoint_store()
254 .get_latest_certified_checkpoint()
255 .unwrap()
256 .unwrap(),
257 );
258 let mut checkpoints = vec![];
259 for transaction in transactions {
260 let effects = all_effects.remove(transaction.digest()).unwrap();
261 builder.push_transaction(
262 VerifiedTransaction::new_unchecked(transaction.into_unsigned()),
263 effects,
264 );
265 if builder.size() == checkpoint_size {
266 let (checkpoint, _, full_contents) = builder.build(self, 0);
267 checkpoints.push((checkpoint, full_contents));
268 }
269 }
270 if builder.size() > 0 {
271 let (checkpoint, _, full_contents) = builder.build(self, 0);
272 checkpoints.push((checkpoint, full_contents));
273 }
274 checkpoints
275 }
276
277 pub fn create_checkpoint_executor(&self) -> CheckpointExecutor {
278 let validator = self.get_validator();
279 CheckpointExecutor::new_for_tests(
280 self.epoch_store.clone(),
281 validator.get_checkpoint_store().clone(),
282 validator.clone(),
283 Arc::new(StateAccumulator::new_for_tests(
284 validator.get_accumulator_store().clone(),
285 )),
286 )
287 }
288
289 pub(crate) fn create_in_memory_store(&self) -> InMemoryObjectStore {
290 let objects: HashMap<_, _> = self
291 .get_validator()
292 .get_accumulator_store()
293 .iter_cached_live_object_set_for_testing()
294 .map(|o| match o {
295 LiveObject::Normal(object) => (object.id(), object),
296 LiveObject::Wrapped(_) => unreachable!(),
297 })
298 .collect();
299 InMemoryObjectStore::new(objects)
300 }
301
302 pub(crate) async fn assigned_shared_object_versions(
303 &self,
304 transactions: &[CertifiedTransaction],
305 ) {
306 let transactions: Vec<_> = transactions
307 .iter()
308 .map(|tx| {
309 VerifiedExecutableTransaction::new_from_certificate(
310 VerifiedCertificate::new_unchecked(tx.clone()),
311 )
312 })
313 .collect();
314 self.epoch_store
315 .assign_shared_object_versions_idempotent(
316 self.get_validator().get_object_cache_reader().as_ref(),
317 &transactions,
318 )
319 .unwrap();
320 }
321}
322
323impl ValidatorKeypairProvider for SingleValidator {
324 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
325 assert_eq!(name, &self.get_validator().name);
326 &*self.get_validator().secret
327 }
328
329 fn get_committee(&self) -> &Committee {
330 self.epoch_store.committee().as_ref()
331 }
332}