sui_single_node_benchmark/
single_node.rs1use crate::command::Component;
5use crate::mock_storage::InMemoryObjectStore;
6use std::collections::{BTreeMap, HashMap};
7use std::sync::Arc;
8use sui_core::authority::authority_per_epoch_store::AuthorityPerEpochStore;
9use sui_core::authority::authority_store_tables::LiveObject;
10use sui_core::authority::shared_object_version_manager::{
11 AssignedTxAndVersions, AssignedVersions, Schedulable,
12};
13use sui_core::authority::test_authority_builder::TestAuthorityBuilder;
14use sui_core::authority::{AuthorityState, ExecutionEnv};
15use sui_core::authority_server::{ValidatorService, ValidatorServiceMetrics};
16use sui_core::checkpoints::checkpoint_executor::CheckpointExecutor;
17use sui_core::consensus_adapter::{ConsensusAdapter, ConsensusAdapterMetrics};
18use sui_core::global_state_hasher::GlobalStateHasher;
19use sui_core::mock_checkpoint_builder::{MockCheckpointBuilder, ValidatorKeypairProvider};
20use sui_core::mock_consensus::{ConsensusMode, MockConsensusClient};
21use sui_test_transaction_builder::{PublishData, TestTransactionBuilder};
22use sui_types::base_types::{AuthorityName, ObjectRef, SuiAddress, TransactionDigest};
23use sui_types::committee::Committee;
24use sui_types::crypto::{AccountKeyPair, AuthoritySignature, Signer};
25use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
26use sui_types::executable_transaction::VerifiedExecutableTransaction;
27use sui_types::execution_params::ExecutionOrEarlyError;
28use sui_types::messages_checkpoint::{VerifiedCheckpoint, VerifiedCheckpointContents};
29use sui_types::object::Object;
30use sui_types::transaction::{
31 DEFAULT_VALIDATOR_GAS_PRICE, Transaction, TransactionDataAPI, VerifiedTransaction,
32};
33
34#[derive(Clone)]
35pub struct SingleValidator {
36 validator_service: Arc<ValidatorService>,
37 epoch_store: Arc<AuthorityPerEpochStore>,
38}
39
40impl SingleValidator {
41 pub(crate) async fn new(genesis_objects: &[Object], component: Component) -> Self {
42 let validator = TestAuthorityBuilder::new()
43 .disable_indexer()
44 .with_starting_objects(genesis_objects)
45 .insert_genesis_checkpoint()
47 .build()
48 .await;
49 let epoch_store = validator.epoch_store_for_testing().clone();
50 let consensus_mode = match component {
51 Component::ValidatorWithFakeConsensus => ConsensusMode::DirectSequencing,
52 _ => ConsensusMode::Noop,
53 };
54 let consensus_adapter = Arc::new(ConsensusAdapter::new(
55 Arc::new(MockConsensusClient::new(
56 Arc::downgrade(&validator),
57 consensus_mode,
58 )),
59 validator.checkpoint_store.clone(),
60 validator.name,
61 100_000,
62 100_000,
63 ConsensusAdapterMetrics::new_test(),
64 Arc::new(tokio::sync::Notify::new()),
65 ));
66 let validator_service = Arc::new(ValidatorService::new_for_tests(
70 validator,
71 consensus_adapter,
72 Arc::new(ValidatorServiceMetrics::new_for_tests()),
73 ));
74 Self {
75 validator_service,
76 epoch_store,
77 }
78 }
79
80 pub fn get_validator(&self) -> &Arc<AuthorityState> {
81 self.validator_service.validator_state()
82 }
83
84 pub fn get_epoch(&self) -> u64 {
85 self.epoch_store.epoch()
86 }
87
88 pub async fn publish_package(
90 &self,
91 publish_data: PublishData,
92 sender: SuiAddress,
93 keypair: &AccountKeyPair,
94 gas: ObjectRef,
95 ) -> (ObjectRef, ObjectRef) {
96 let tx_builder = TestTransactionBuilder::new(sender, gas, DEFAULT_VALIDATOR_GAS_PRICE)
97 .publish_with_data_async(publish_data)
98 .await;
99 let transaction = tx_builder.build_and_sign(keypair);
100 let effects = self.execute_raw_transaction(transaction).await;
101 let package = effects
102 .all_changed_objects()
103 .into_iter()
104 .filter_map(|(oref, owner, _)| owner.is_immutable().then_some(oref))
105 .next()
106 .unwrap();
107 let updated_gas = effects.gas_object().unwrap().0;
108 (package, updated_gas)
109 }
110
111 pub async fn execute_raw_transaction(&self, transaction: Transaction) -> TransactionEffects {
112 let executable = VerifiedExecutableTransaction::new_from_consensus(
113 VerifiedTransaction::new_unchecked(transaction),
114 0,
115 );
116 let effects = self
117 .get_validator()
118 .try_execute_immediately(&executable, ExecutionEnv::new(), &self.epoch_store)
119 .await
120 .unwrap()
121 .0;
122 assert!(effects.status().is_ok());
123 effects
124 }
125
126 pub async fn execute_dry_run(&self, transaction: Transaction) -> TransactionEffects {
127 let effects = self
128 .get_validator()
129 .dry_exec_transaction_for_benchmark(
130 transaction.data().intent_message().value.clone(),
131 *transaction.digest(),
132 )
133 .unwrap()
134 .2;
135 assert!(effects.status().is_ok());
136 effects
137 }
138
139 fn create_executable(&self, transaction: Transaction) -> VerifiedExecutableTransaction {
141 VerifiedExecutableTransaction::new_from_consensus(
142 VerifiedTransaction::new_unchecked(transaction),
143 self.epoch_store.epoch(),
144 )
145 }
146
147 pub async fn execute_transaction(
148 &self,
149 transaction: Transaction,
150 assigned_versions: &AssignedVersions,
151 component: Component,
152 ) -> (TransactionEffects, std::time::Duration) {
153 let executable = self.create_executable(transaction);
154 let start = std::time::Instant::now();
155 let effects = match component {
156 Component::Baseline => {
157 self.get_validator()
158 .try_execute_immediately(
159 &executable,
160 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
161 &self.epoch_store,
162 )
163 .await
164 .unwrap()
165 .0
166 }
167 Component::WithTxManager => {
168 self.get_validator().execution_scheduler().enqueue(
170 vec![(
171 executable.clone().into(),
172 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
173 )],
174 &self.epoch_store,
175 );
176 self.get_validator()
177 .wait_for_transaction_execution_for_testing(&executable)
178 .await
179 }
180 Component::ValidatorWithoutConsensus | Component::ValidatorWithFakeConsensus => {
181 let (signed_effects, _) = self
183 .get_validator()
184 .try_execute_executable_for_test(
185 &executable,
186 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
187 )
188 .await;
189 signed_effects.into_inner().into_data()
190 }
191 Component::CheckpointExecutor | Component::ExecutionOnly => {
192 unreachable!()
193 }
194 };
195 let elapsed = start.elapsed();
196 assert!(effects.status().is_ok());
197 (effects, elapsed)
198 }
199
200 pub(crate) async fn execute_transaction_in_memory(
201 &self,
202 store: InMemoryObjectStore,
203 transaction: Transaction,
204 assigned_versions: &AssignedVersions,
205 ) -> TransactionEffects {
206 let input_objects = transaction
207 .data()
208 .intent_message()
209 .value
210 .input_objects()
211 .unwrap();
212 let executable = self.create_executable(transaction);
213 let objects = store
214 .read_objects_for_execution(&executable.key(), assigned_versions, &input_objects)
215 .unwrap();
216
217 let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input(
218 &executable,
219 objects,
220 self.epoch_store.protocol_config(),
221 self.epoch_store.reference_gas_price(),
222 )
223 .unwrap();
224 let (kind, signer, gas_data) = executable.transaction_data().execution_parts();
225 let (inner_temp_store, _, effects, _timings, _) =
226 self.epoch_store.executor().execute_transaction_to_effects(
227 &store,
228 self.epoch_store.protocol_config(),
229 self.get_validator().metrics.execution_metrics.clone(),
230 false,
231 ExecutionOrEarlyError::Ok(()),
232 &self.epoch_store.epoch(),
233 0,
234 input_objects,
235 gas_data,
236 gas_status,
237 kind,
238 None, signer,
240 *executable.digest(),
241 &mut None,
242 );
243 assert!(effects.status().is_ok());
244 store.commit_objects(inner_temp_store);
245 effects
246 }
247
248 pub(crate) async fn build_checkpoints(
249 &self,
250 transactions: Vec<Transaction>,
251 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
252 checkpoint_size: usize,
253 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
254 let mut builder = MockCheckpointBuilder::new(
255 self.get_validator()
256 .get_checkpoint_store()
257 .get_latest_certified_checkpoint()
258 .unwrap()
259 .unwrap(),
260 );
261 let mut checkpoints = vec![];
262 for transaction in transactions {
263 let effects = all_effects.remove(transaction.digest()).unwrap();
264 builder.push_transaction(VerifiedTransaction::new_unchecked(transaction), effects);
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(GlobalStateHasher::new_for_tests(
284 validator.get_global_state_hash_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_global_state_hash_store()
293 .iter_cached_live_object_set_for_testing(false)
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: &[Transaction],
305 ) -> AssignedTxAndVersions {
306 let executables: Vec<_> = transactions
307 .iter()
308 .map(|tx| self.create_executable(tx.clone()))
309 .collect();
310 let assignables: Vec<_> = executables.iter().map(Schedulable::Transaction).collect();
311 self.epoch_store
312 .assign_shared_object_versions_idempotent(
313 self.get_validator().get_object_cache_reader().as_ref(),
314 assignables.iter(),
315 )
316 .unwrap()
317 }
318}
319
320impl ValidatorKeypairProvider for SingleValidator {
321 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
322 assert_eq!(name, &self.get_validator().name);
323 &*self.get_validator().secret
324 }
325
326 fn get_committee(&self) -> &Committee {
327 self.epoch_store.committee().as_ref()
328 }
329}