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 .unwrap()
120 .0;
121 assert!(effects.status().is_ok());
122 effects
123 }
124
125 fn create_executable(&self, transaction: Transaction) -> VerifiedExecutableTransaction {
127 VerifiedExecutableTransaction::new_from_consensus(
128 VerifiedTransaction::new_unchecked(transaction),
129 self.epoch_store.epoch(),
130 )
131 }
132
133 pub async fn execute_transaction(
134 &self,
135 transaction: Transaction,
136 assigned_versions: &AssignedVersions,
137 component: Component,
138 ) -> (TransactionEffects, std::time::Duration) {
139 let executable = self.create_executable(transaction);
140 let start = std::time::Instant::now();
141 let effects = match component {
142 Component::Baseline => {
143 self.get_validator()
144 .try_execute_immediately(
145 &executable,
146 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
147 &self.epoch_store,
148 )
149 .unwrap()
150 .0
151 }
152 Component::WithTxManager => {
153 self.get_validator().execution_scheduler().enqueue(
155 vec![(
156 executable.clone().into(),
157 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
158 )],
159 &self.epoch_store,
160 );
161 self.get_validator()
162 .wait_for_transaction_execution_for_testing(&executable)
163 .await
164 }
165 Component::ValidatorWithoutConsensus | Component::ValidatorWithFakeConsensus => {
166 let (signed_effects, _) = self
168 .get_validator()
169 .try_execute_executable_for_test(
170 &executable,
171 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
172 )
173 .await;
174 signed_effects.into_inner().into_data()
175 }
176 Component::CheckpointExecutor | Component::ExecutionOnly => {
177 unreachable!()
178 }
179 };
180 let elapsed = start.elapsed();
181 assert!(effects.status().is_ok());
182 (effects, elapsed)
183 }
184
185 pub(crate) async fn execute_transaction_in_memory(
186 &self,
187 store: InMemoryObjectStore,
188 transaction: Transaction,
189 assigned_versions: &AssignedVersions,
190 ) -> TransactionEffects {
191 let input_objects = transaction
192 .data()
193 .intent_message()
194 .value
195 .input_objects()
196 .unwrap();
197 let executable = self.create_executable(transaction);
198 let objects = store
199 .read_objects_for_execution(&executable.key(), assigned_versions, &input_objects)
200 .unwrap();
201
202 let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input(
203 &executable,
204 objects,
205 self.epoch_store.protocol_config(),
206 self.epoch_store.reference_gas_price(),
207 )
208 .unwrap();
209 let (kind, signer, gas_data) = executable.transaction_data().execution_parts();
210 let (inner_temp_store, _, effects, _timings, _) =
211 self.epoch_store.executor().execute_transaction_to_effects(
212 &store,
213 self.epoch_store.protocol_config(),
214 self.get_validator().metrics.execution_metrics.clone(),
215 false,
216 ExecutionOrEarlyError::ok(None),
217 &self.epoch_store.epoch(),
218 0,
219 input_objects,
220 gas_data,
221 gas_status,
222 kind,
223 None, signer,
225 *executable.digest(),
226 &mut None,
227 );
228 assert!(effects.status().is_ok());
229 store.commit_objects(inner_temp_store);
230 effects
231 }
232
233 pub(crate) async fn build_checkpoints(
234 &self,
235 transactions: Vec<Transaction>,
236 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
237 checkpoint_size: usize,
238 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
239 let mut builder = MockCheckpointBuilder::new(
240 self.get_validator()
241 .get_checkpoint_store()
242 .get_latest_certified_checkpoint()
243 .unwrap()
244 .unwrap(),
245 );
246 let mut checkpoints = vec![];
247 for transaction in transactions {
248 let effects = all_effects.remove(transaction.digest()).unwrap();
249 builder.push_transaction(VerifiedTransaction::new_unchecked(transaction), effects);
250 if builder.size() == checkpoint_size {
251 let (checkpoint, _, full_contents) = builder.build(self, 0);
252 checkpoints.push((checkpoint, full_contents));
253 }
254 }
255 if builder.size() > 0 {
256 let (checkpoint, _, full_contents) = builder.build(self, 0);
257 checkpoints.push((checkpoint, full_contents));
258 }
259 checkpoints
260 }
261
262 pub fn create_checkpoint_executor(&self) -> CheckpointExecutor {
263 let validator = self.get_validator();
264 CheckpointExecutor::new_for_tests(
265 self.epoch_store.clone(),
266 validator.get_checkpoint_store().clone(),
267 validator.clone(),
268 Arc::new(GlobalStateHasher::new_for_tests(
269 validator.get_global_state_hash_store().clone(),
270 )),
271 )
272 }
273
274 pub(crate) fn create_in_memory_store(&self) -> InMemoryObjectStore {
275 let objects: HashMap<_, _> = self
276 .get_validator()
277 .get_global_state_hash_store()
278 .iter_cached_live_object_set_for_testing(false)
279 .map(|o| match o {
280 LiveObject::Normal(object) => (object.id(), object),
281 LiveObject::Wrapped(_) => unreachable!(),
282 })
283 .collect();
284 InMemoryObjectStore::new(objects)
285 }
286
287 pub(crate) async fn assigned_shared_object_versions(
288 &self,
289 transactions: &[Transaction],
290 ) -> AssignedTxAndVersions {
291 let executables: Vec<_> = transactions
292 .iter()
293 .map(|tx| self.create_executable(tx.clone()))
294 .collect();
295 let assignables: Vec<_> = executables.iter().map(Schedulable::Transaction).collect();
296 self.epoch_store
297 .assign_shared_object_versions_idempotent(
298 self.get_validator().get_object_cache_reader().as_ref(),
299 assignables.iter(),
300 )
301 .unwrap()
302 }
303}
304
305impl ValidatorKeypairProvider for SingleValidator {
306 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
307 assert_eq!(name, &self.get_validator().name);
308 &*self.get_validator().secret
309 }
310
311 fn get_committee(&self) -> &Committee {
312 self.epoch_store.committee().as_ref()
313 }
314}