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::{
18 ConnectionMonitorStatusForTests, ConsensusAdapter, ConsensusAdapterMetrics,
19};
20use sui_core::global_state_hasher::GlobalStateHasher;
21use sui_core::mock_checkpoint_builder::{MockCheckpointBuilder, ValidatorKeypairProvider};
22use sui_core::mock_consensus::{ConsensusMode, MockConsensusClient};
23use sui_test_transaction_builder::{PublishData, TestTransactionBuilder};
24use sui_types::base_types::{AuthorityName, ObjectRef, SuiAddress, TransactionDigest};
25use sui_types::committee::Committee;
26use sui_types::crypto::{AccountKeyPair, AuthoritySignature, Signer};
27use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
28use sui_types::executable_transaction::VerifiedExecutableTransaction;
29use sui_types::execution_params::ExecutionOrEarlyError;
30use sui_types::messages_checkpoint::{VerifiedCheckpoint, VerifiedCheckpointContents};
31use sui_types::object::Object;
32use sui_types::transaction::{
33 DEFAULT_VALIDATOR_GAS_PRICE, Transaction, TransactionDataAPI, VerifiedTransaction,
34};
35
36#[derive(Clone)]
37pub struct SingleValidator {
38 validator_service: Arc<ValidatorService>,
39 epoch_store: Arc<AuthorityPerEpochStore>,
40}
41
42impl SingleValidator {
43 pub(crate) async fn new(genesis_objects: &[Object], component: Component) -> Self {
44 let validator = TestAuthorityBuilder::new()
45 .disable_indexer()
46 .with_starting_objects(genesis_objects)
47 .insert_genesis_checkpoint()
49 .build()
50 .await;
51 let epoch_store = validator.epoch_store_for_testing().clone();
52 let consensus_mode = match component {
53 Component::ValidatorWithFakeConsensus => ConsensusMode::DirectSequencing,
54 _ => ConsensusMode::Noop,
55 };
56 let consensus_adapter = Arc::new(ConsensusAdapter::new(
57 Arc::new(MockConsensusClient::new(
58 Arc::downgrade(&validator),
59 consensus_mode,
60 )),
61 validator.checkpoint_store.clone(),
62 validator.name,
63 Arc::new(ConnectionMonitorStatusForTests {}),
64 100_000,
65 100_000,
66 None,
67 None,
68 ConsensusAdapterMetrics::new_test(),
69 epoch_store.protocol_config().clone(),
70 ));
71 let validator_service = Arc::new(ValidatorService::new_for_tests(
75 validator,
76 consensus_adapter,
77 Arc::new(ValidatorServiceMetrics::new_for_tests()),
78 ));
79 Self {
80 validator_service,
81 epoch_store,
82 }
83 }
84
85 pub fn get_validator(&self) -> &Arc<AuthorityState> {
86 self.validator_service.validator_state()
87 }
88
89 pub async fn publish_package(
91 &self,
92 publish_data: PublishData,
93 sender: SuiAddress,
94 keypair: &AccountKeyPair,
95 gas: ObjectRef,
96 ) -> (ObjectRef, ObjectRef) {
97 let tx_builder = TestTransactionBuilder::new(sender, gas, DEFAULT_VALIDATOR_GAS_PRICE)
98 .publish_with_data_async(publish_data)
99 .await;
100 let transaction = tx_builder.build_and_sign(keypair);
101 let effects = self.execute_raw_transaction(transaction).await;
102 let package = effects
103 .all_changed_objects()
104 .into_iter()
105 .filter_map(|(oref, owner, _)| owner.is_immutable().then_some(oref))
106 .next()
107 .unwrap();
108 let updated_gas = effects.gas_object().0;
109 (package, updated_gas)
110 }
111
112 pub async fn execute_raw_transaction(&self, transaction: Transaction) -> TransactionEffects {
113 let executable = VerifiedExecutableTransaction::new_from_consensus(
114 VerifiedTransaction::new_unchecked(transaction),
115 0,
116 );
117 let effects = self
118 .get_validator()
119 .try_execute_immediately(&executable, ExecutionEnv::new(), &self.epoch_store)
120 .await
121 .unwrap()
122 .0;
123 assert!(effects.status().is_ok());
124 effects
125 }
126
127 pub async fn execute_dry_run(&self, transaction: Transaction) -> TransactionEffects {
128 let effects = self
129 .get_validator()
130 .dry_exec_transaction_for_benchmark(
131 transaction.data().intent_message().value.clone(),
132 *transaction.digest(),
133 )
134 .unwrap()
135 .2;
136 assert!(effects.status().is_ok());
137 effects
138 }
139
140 fn create_executable(&self, transaction: Transaction) -> VerifiedExecutableTransaction {
142 VerifiedExecutableTransaction::new_from_consensus(
143 VerifiedTransaction::new_unchecked(transaction),
144 self.epoch_store.epoch(),
145 )
146 }
147
148 pub async fn execute_transaction(
149 &self,
150 transaction: Transaction,
151 assigned_versions: &AssignedVersions,
152 component: Component,
153 ) -> TransactionEffects {
154 let executable = self.create_executable(transaction);
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, &self.epoch_store)
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 assert!(effects.status().is_ok());
196 effects
197 }
198
199 pub(crate) async fn execute_transaction_in_memory(
200 &self,
201 store: InMemoryObjectStore,
202 transaction: Transaction,
203 assigned_versions: &AssignedVersions,
204 ) -> TransactionEffects {
205 let input_objects = transaction
206 .data()
207 .intent_message()
208 .value
209 .input_objects()
210 .unwrap();
211 let executable = self.create_executable(transaction);
212 let objects = store
213 .read_objects_for_execution(&executable.key(), assigned_versions, &input_objects)
214 .unwrap();
215
216 let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input(
217 &executable,
218 objects,
219 self.epoch_store.protocol_config(),
220 self.epoch_store.reference_gas_price(),
221 )
222 .unwrap();
223 let (kind, signer, gas_data) = executable.transaction_data().execution_parts();
224 let (inner_temp_store, _, effects, _timings, _) =
225 self.epoch_store.executor().execute_transaction_to_effects(
226 &store,
227 self.epoch_store.protocol_config(),
228 self.get_validator().metrics.limits_metrics.clone(),
229 false,
230 ExecutionOrEarlyError::Ok(()),
231 &self.epoch_store.epoch(),
232 0,
233 input_objects,
234 gas_data,
235 gas_status,
236 kind,
237 signer,
238 *executable.digest(),
239 &mut None,
240 );
241 assert!(effects.status().is_ok());
242 store.commit_objects(inner_temp_store);
243 effects
244 }
245
246 pub(crate) async fn build_checkpoints(
247 &self,
248 transactions: Vec<Transaction>,
249 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
250 checkpoint_size: usize,
251 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
252 let mut builder = MockCheckpointBuilder::new(
253 self.get_validator()
254 .get_checkpoint_store()
255 .get_latest_certified_checkpoint()
256 .unwrap()
257 .unwrap(),
258 );
259 let mut checkpoints = vec![];
260 for transaction in transactions {
261 let effects = all_effects.remove(transaction.digest()).unwrap();
262 builder.push_transaction(VerifiedTransaction::new_unchecked(transaction), effects);
263 if builder.size() == checkpoint_size {
264 let (checkpoint, _, full_contents) = builder.build(self, 0);
265 checkpoints.push((checkpoint, full_contents));
266 }
267 }
268 if builder.size() > 0 {
269 let (checkpoint, _, full_contents) = builder.build(self, 0);
270 checkpoints.push((checkpoint, full_contents));
271 }
272 checkpoints
273 }
274
275 pub fn create_checkpoint_executor(&self) -> CheckpointExecutor {
276 let validator = self.get_validator();
277 CheckpointExecutor::new_for_tests(
278 self.epoch_store.clone(),
279 validator.get_checkpoint_store().clone(),
280 validator.clone(),
281 Arc::new(GlobalStateHasher::new_for_tests(
282 validator.get_global_state_hash_store().clone(),
283 )),
284 )
285 }
286
287 pub(crate) fn create_in_memory_store(&self) -> InMemoryObjectStore {
288 let objects: HashMap<_, _> = self
289 .get_validator()
290 .get_global_state_hash_store()
291 .iter_cached_live_object_set_for_testing(false)
292 .map(|o| match o {
293 LiveObject::Normal(object) => (object.id(), object),
294 LiveObject::Wrapped(_) => unreachable!(),
295 })
296 .collect();
297 InMemoryObjectStore::new(objects)
298 }
299
300 pub(crate) async fn assigned_shared_object_versions(
301 &self,
302 transactions: &[Transaction],
303 ) -> AssignedTxAndVersions {
304 let executables: Vec<_> = transactions
305 .iter()
306 .map(|tx| self.create_executable(tx.clone()))
307 .collect();
308 let assignables: Vec<_> = executables.iter().map(Schedulable::Transaction).collect();
309 self.epoch_store
310 .assign_shared_object_versions_idempotent(
311 self.get_validator().get_object_cache_reader().as_ref(),
312 assignables.iter(),
313 )
314 .unwrap()
315 }
316}
317
318impl ValidatorKeypairProvider for SingleValidator {
319 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
320 assert_eq!(name, &self.get_validator().name);
321 &*self.get_validator().secret
322 }
323
324 fn get_committee(&self) -> &Committee {
325 self.epoch_store.committee().as_ref()
326 }
327}