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 sui_types::base_types::SystemObjectVersions::empty(),
221 &sui_types::accumulator_root::EmptyUnsettledObjectFunds,
224 gas_data,
225 gas_status,
226 kind,
227 None, 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(crate) async fn build_checkpoints(
238 &self,
239 transactions: Vec<Transaction>,
240 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
241 checkpoint_size: usize,
242 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
243 let mut builder = MockCheckpointBuilder::new(
244 self.get_validator()
245 .get_checkpoint_store()
246 .get_latest_certified_checkpoint()
247 .unwrap()
248 .unwrap(),
249 );
250 let mut checkpoints = vec![];
251 for transaction in transactions {
252 let effects = all_effects.remove(transaction.digest()).unwrap();
253 builder.push_transaction(VerifiedTransaction::new_unchecked(transaction), effects);
254 if builder.size() == checkpoint_size {
255 let (checkpoint, _, full_contents) = builder.build(self, 0);
256 checkpoints.push((checkpoint, full_contents));
257 }
258 }
259 if builder.size() > 0 {
260 let (checkpoint, _, full_contents) = builder.build(self, 0);
261 checkpoints.push((checkpoint, full_contents));
262 }
263 checkpoints
264 }
265
266 pub fn create_checkpoint_executor(&self) -> CheckpointExecutor {
267 let validator = self.get_validator();
268 CheckpointExecutor::new_for_tests(
269 self.epoch_store.clone(),
270 validator.get_checkpoint_store().clone(),
271 validator.clone(),
272 Arc::new(GlobalStateHasher::new_for_tests(
273 validator.get_global_state_hash_store().clone(),
274 )),
275 )
276 }
277
278 pub(crate) fn create_in_memory_store(&self) -> InMemoryObjectStore {
279 let objects: HashMap<_, _> = self
280 .get_validator()
281 .get_global_state_hash_store()
282 .iter_cached_live_object_set_for_testing(false)
283 .map(|o| match o {
284 LiveObject::Normal(object) => (object.id(), object),
285 LiveObject::Wrapped(_) => unreachable!(),
286 })
287 .collect();
288 InMemoryObjectStore::new(objects)
289 }
290
291 pub(crate) async fn assigned_shared_object_versions(
292 &self,
293 transactions: &[Transaction],
294 ) -> AssignedTxAndVersions {
295 let executables: Vec<_> = transactions
296 .iter()
297 .map(|tx| self.create_executable(tx.clone()))
298 .collect();
299 let assignables: Vec<_> = executables.iter().map(Schedulable::Transaction).collect();
300 self.epoch_store
301 .assign_shared_object_versions_idempotent(
302 self.get_validator().get_object_cache_reader().as_ref(),
303 assignables.iter(),
304 )
305 .unwrap()
306 }
307}
308
309impl ValidatorKeypairProvider for SingleValidator {
310 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
311 assert_eq!(name, &self.get_validator().name);
312 &*self.get_validator().secret
313 }
314
315 fn get_committee(&self) -> &Committee {
316 self.epoch_store.committee().as_ref()
317 }
318}