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 .with_starting_objects(genesis_objects)
44 .insert_genesis_checkpoint()
46 .build()
47 .await;
48 let epoch_store = validator.epoch_store_for_testing().clone();
49 let consensus_mode = match component {
50 Component::ValidatorWithFakeConsensus => ConsensusMode::DirectSequencing,
51 _ => ConsensusMode::Noop,
52 };
53 let consensus_adapter = Arc::new(ConsensusAdapter::new(
54 Arc::new(MockConsensusClient::new(
55 Arc::downgrade(&validator),
56 consensus_mode,
57 )),
58 validator.checkpoint_store.clone(),
59 validator.name,
60 100_000,
61 100_000,
62 ConsensusAdapterMetrics::new_test(),
63 Arc::new(tokio::sync::Notify::new()),
64 ));
65 let validator_service = Arc::new(ValidatorService::new_for_tests(
69 validator,
70 consensus_adapter,
71 Arc::new(ValidatorServiceMetrics::new_for_tests()),
72 ));
73 Self {
74 validator_service,
75 epoch_store,
76 }
77 }
78
79 pub fn get_validator(&self) -> &Arc<AuthorityState> {
80 self.validator_service.validator_state()
81 }
82
83 pub fn get_epoch(&self) -> u64 {
84 self.epoch_store.epoch()
85 }
86
87 pub async fn publish_package(
89 &self,
90 publish_data: PublishData,
91 sender: SuiAddress,
92 keypair: &AccountKeyPair,
93 gas: ObjectRef,
94 ) -> (ObjectRef, ObjectRef) {
95 let tx_builder = TestTransactionBuilder::new(sender, gas, DEFAULT_VALIDATOR_GAS_PRICE)
96 .publish_with_data_async(publish_data)
97 .await;
98 let transaction = tx_builder.build_and_sign(keypair);
99 let effects = self.execute_raw_transaction(transaction).await;
100 let package = effects
101 .all_changed_objects()
102 .into_iter()
103 .filter_map(|(oref, owner, _)| owner.is_immutable().then_some(oref))
104 .next()
105 .unwrap();
106 let updated_gas = effects.gas_object().unwrap().0;
107 (package, updated_gas)
108 }
109
110 pub async fn execute_raw_transaction(&self, transaction: Transaction) -> TransactionEffects {
111 let executable = VerifiedExecutableTransaction::new_from_consensus(
112 VerifiedTransaction::new_unchecked(transaction),
113 0,
114 );
115 let effects = self
116 .get_validator()
117 .try_execute_immediately(&executable, ExecutionEnv::new(), &self.epoch_store)
118 .unwrap()
119 .0;
120 assert!(effects.status().is_ok());
121 effects
122 }
123
124 fn create_executable(&self, transaction: Transaction) -> VerifiedExecutableTransaction {
126 VerifiedExecutableTransaction::new_from_consensus(
127 VerifiedTransaction::new_unchecked(transaction),
128 self.epoch_store.epoch(),
129 )
130 }
131
132 pub async fn execute_transaction(
133 &self,
134 transaction: Transaction,
135 assigned_versions: &AssignedVersions,
136 component: Component,
137 ) -> (TransactionEffects, std::time::Duration) {
138 let executable = self.create_executable(transaction);
139 let start = std::time::Instant::now();
140 let effects = match component {
141 Component::Baseline => {
142 self.get_validator()
143 .try_execute_immediately(
144 &executable,
145 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
146 &self.epoch_store,
147 )
148 .unwrap()
149 .0
150 }
151 Component::WithTxManager => {
152 self.get_validator().execution_scheduler().enqueue(
154 vec![(
155 executable.clone().into(),
156 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
157 )],
158 &self.epoch_store,
159 );
160 self.get_validator()
161 .wait_for_transaction_execution_for_testing(&executable)
162 .await
163 }
164 Component::ValidatorWithoutConsensus | Component::ValidatorWithFakeConsensus => {
165 let (signed_effects, _) = self
167 .get_validator()
168 .try_execute_executable_for_test(
169 &executable,
170 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
171 )
172 .await;
173 signed_effects.into_inner().into_data()
174 }
175 Component::CheckpointExecutor | Component::ExecutionOnly => {
176 unreachable!()
177 }
178 };
179 let elapsed = start.elapsed();
180 assert!(effects.status().is_ok());
181 (effects, elapsed)
182 }
183
184 pub(crate) async fn execute_transaction_in_memory(
185 &self,
186 store: InMemoryObjectStore,
187 transaction: Transaction,
188 assigned_versions: &AssignedVersions,
189 ) -> TransactionEffects {
190 let input_objects = transaction
191 .data()
192 .intent_message()
193 .value
194 .input_objects()
195 .unwrap();
196 let executable = self.create_executable(transaction);
197 let objects = store
198 .read_objects_for_execution(&executable.key(), assigned_versions, &input_objects)
199 .unwrap();
200
201 let (gas_status, input_objects) = sui_transaction_checks::check_certificate_input(
202 &executable,
203 objects,
204 self.epoch_store.protocol_config(),
205 self.epoch_store.reference_gas_price(),
206 )
207 .unwrap();
208 let (kind, signer, gas_data) = executable.transaction_data().execution_parts();
209 let (inner_temp_store, _, effects, _timings, _) =
210 self.epoch_store.executor().execute_transaction_to_effects(
211 &store,
212 self.epoch_store.protocol_config(),
213 self.get_validator().metrics.execution_metrics.clone(),
214 false,
215 ExecutionOrEarlyError::ok(None),
216 &self.epoch_store.epoch(),
217 0,
218 input_objects,
219 sui_types::base_types::SystemObjectVersions::empty(),
220 &sui_types::accumulator_root::EmptyUnsettledObjectFunds,
223 gas_data,
224 gas_status,
225 kind,
226 None, signer,
228 *executable.digest(),
229 &mut None,
230 );
231 assert!(effects.status().is_ok());
232 store.commit_objects(inner_temp_store);
233 effects
234 }
235
236 pub(crate) async fn build_checkpoints(
237 &self,
238 transactions: Vec<Transaction>,
239 mut all_effects: BTreeMap<TransactionDigest, TransactionEffects>,
240 checkpoint_size: usize,
241 ) -> Vec<(VerifiedCheckpoint, VerifiedCheckpointContents)> {
242 let mut builder = MockCheckpointBuilder::new(
243 self.get_validator()
244 .get_checkpoint_store()
245 .get_latest_certified_checkpoint()
246 .unwrap()
247 .unwrap(),
248 );
249 let mut checkpoints = vec![];
250 for transaction in transactions {
251 let effects = all_effects.remove(transaction.digest()).unwrap();
252 builder.push_transaction(VerifiedTransaction::new_unchecked(transaction), effects);
253 if builder.size() == checkpoint_size {
254 let (checkpoint, _, full_contents) = builder.build(self, 0);
255 checkpoints.push((checkpoint, full_contents));
256 }
257 }
258 if builder.size() > 0 {
259 let (checkpoint, _, full_contents) = builder.build(self, 0);
260 checkpoints.push((checkpoint, full_contents));
261 }
262 checkpoints
263 }
264
265 pub fn create_checkpoint_executor(&self) -> CheckpointExecutor {
266 let validator = self.get_validator();
267 CheckpointExecutor::new_for_tests(
268 self.epoch_store.clone(),
269 validator.get_checkpoint_store().clone(),
270 validator.clone(),
271 Arc::new(GlobalStateHasher::new_for_tests(
272 validator.get_global_state_hash_store().clone(),
273 )),
274 )
275 }
276
277 pub(crate) fn create_in_memory_store(&self) -> InMemoryObjectStore {
278 let objects: HashMap<_, _> = self
279 .get_validator()
280 .get_global_state_hash_store()
281 .iter_cached_live_object_set_for_testing(false)
282 .map(|o| match o {
283 LiveObject::Normal(object) => (object.id(), object),
284 LiveObject::Wrapped(_) => unreachable!(),
285 })
286 .collect();
287 InMemoryObjectStore::new(objects)
288 }
289
290 pub(crate) async fn assigned_shared_object_versions(
291 &self,
292 transactions: &[Transaction],
293 ) -> AssignedTxAndVersions {
294 let executables: Vec<_> = transactions
295 .iter()
296 .map(|tx| self.create_executable(tx.clone()))
297 .collect();
298 let assignables: Vec<_> = executables.iter().map(Schedulable::Transaction).collect();
299 self.epoch_store
300 .assign_shared_object_versions_idempotent(
301 self.get_validator().get_object_cache_reader().as_ref(),
302 assignables.iter(),
303 )
304 .unwrap()
305 }
306}
307
308impl ValidatorKeypairProvider for SingleValidator {
309 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
310 assert_eq!(name, &self.get_validator().name);
311 &*self.get_validator().secret
312 }
313
314 fn get_committee(&self) -> &Committee {
315 self.epoch_store.committee().as_ref()
316 }
317}