From fe2bd7fb7db1d1d47d73989b17b2c139afb25b1d Mon Sep 17 00:00:00 2001 From: Zhe Wu Date: Tue, 10 Oct 2023 19:30:12 -0700 Subject: [PATCH] Adding a benchmark for transaction signing (#14174) ## Description Adding a benchmark to measure validator signing transaction performace in the single node benchmark suite. Sample output: ``` cargo run --release --bin sui-single-node-benchmark -- move --component txn-signing 2023-10-10T16:08:05.023632Z INFO sui_single_node_benchmark::benchmark_context: Creating 500001 accounts and 1000002 gas objects 2023-10-10T16:08:06.430838Z INFO sui_single_node_benchmark::benchmark_context: Initializing validator 2023-10-10T16:08:10.306098Z INFO sui_single_node_benchmark::benchmark_context: Programmable Move Transaction Generator: Creating 500001 transactions 2023-10-10T16:08:11.236391Z INFO sui_single_node_benchmark::execution: Sample transaction: SenderSignedData([SenderSignedTransaction { intent_message: IntentMessage { intent: Intent { scope: TransactionData, version: V0, app_id: Sui }, value: V1(TransactionDataV1 { kind: ProgrammableTransaction(ProgrammableTransaction { inputs: [Object(ImmOrOwnedObject((0xff01000000000000000000000000000000000000000000000000000000000000, SequenceNumber(1), o#3Wy9EiapZQKhT8rAyQMyrNNYY16hUSJdqhwetB92C4pu))), Pure([184, 159, 82, 182, 144, 220, 83, 194, 8, 51, 15, 138, 44, 214, 190, 240, 85, 19, 16, 201, 173, 213, 246, 216, 58, 70, 65, 252, 110, 209, 66, 161]), Pure([0, 0, 0, 0, 0, 0, 0, 0])], commands: [MakeMoveVec(None, [Input(0)]), MoveCall(ProgrammableMoveCall { package: 0x22b99c7c24f1fe4e0ba3a3b65b120f85fc3923fcf9111ddc75caa54150604920, module: Identifier("benchmark"), function: Identifier("merge_input_coins"), type_arguments: [], arguments: [Result(0)] }), TransferObjects([Result(1)], Input(1)), MoveCall(ProgrammableMoveCall { package: 0x22b99c7c24f1fe4e0ba3a3b65b120f85fc3923fcf9111ddc75caa54150604920, module: Identifier("benchmark"), function: Identifier("run_computation"), type_arguments: [], arguments: [Input(2)] })] }), sender: 0xb89f52b690dc53c208330f8a2cd6bef0551310c9add5f6d83a4641fc6ed142a1, gas_data: GasData { payment: [(0xff00000000000000000000000000000000000000000000000000000000000000, SequenceNumber(1), o#9tCQKCfifCQzaicSPdBpWyPKVD6fJFcKatKoHn9TyBEn)], owner: 0xb89f52b690dc53c208330f8a2cd6bef0551310c9add5f6d83a4641fc6ed142a1, price: 1000, budget: 5000000000 }, expiration: None }) }, tx_signatures: [Signature(Ed25519SuiSignature(Ed25519SuiSignature([0, 124, 197, 41, 122, 155, 114, 67, 77, 13, 124, 161, 104, 88, 199, 110, 40, 181, 128, 92, 5, 144, 52, 28, 230, 159, 225, 27, 88, 94, 74, 10, 49, 189, 110, 178, 7, 46, 169, 154, 72, 167, 128, 132, 104, 166, 96, 142, 46, 92, 11, 217, 238, 201, 121, 206, 109, 215, 229, 219, 52, 157, 237, 154, 4, 98, 34, 97, 21, 172, 104, 110, 152, 8, 19, 17, 185, 26, 203, 149, 57, 52, 64, 167, 160, 214, 216, 121, 224, 126, 86, 237, 26, 8, 57, 116, 90])))] }]) 2023-10-10T16:08:11.236431Z INFO sui_single_node_benchmark::benchmark_context: Started signing 500001 transactions. You can now attach a profiler 2023-10-10T16:08:23.669227Z INFO sui_single_node_benchmark::execution: Transaction signing finished in 12.432s, TPS=40218.87065637066 ``` ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --------- Co-authored-by: Zhe Wu --- crates/sui-core/src/authority_server.rs | 10 +++++ .../src/benchmark_context.rs | 20 ++++++++++ .../sui-single-node-benchmark/src/command.rs | 2 + .../src/execution.rs | 37 +++++++++++++++++-- .../src/single_node.rs | 9 +++++ 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/crates/sui-core/src/authority_server.rs b/crates/sui-core/src/authority_server.rs index 82657614bc0ef..cac6ec29236c0 100644 --- a/crates/sui-core/src/authority_server.rs +++ b/crates/sui-core/src/authority_server.rs @@ -248,6 +248,16 @@ impl ValidatorService { .into_inner() } + pub async fn handle_transaction_for_testing( + &self, + transaction: Transaction, + ) -> HandleTransactionResponse { + self.transaction(tonic::Request::new(transaction)) + .await + .unwrap() + .into_inner() + } + async fn handle_transaction( self, request: tonic::Request, diff --git a/crates/sui-single-node-benchmark/src/benchmark_context.rs b/crates/sui-single-node-benchmark/src/benchmark_context.rs index 54489cf7fcbc9..5f5e1f584f6ca 100644 --- a/crates/sui-single-node-benchmark/src/benchmark_context.rs +++ b/crates/sui-single-node-benchmark/src/benchmark_context.rs @@ -13,6 +13,7 @@ use std::sync::Arc; use sui_types::base_types::{ObjectID, ObjectRef, SuiAddress, SUI_ADDRESS_LENGTH}; use sui_types::crypto::{get_account_key_pair, AccountKeyPair}; use sui_types::effects::TransactionEffects; +use sui_types::messages_grpc::HandleTransactionResponse; use sui_types::object::Object; use sui_types::transaction::{CertifiedTransaction, SignedTransaction, Transaction}; use tracing::info; @@ -232,4 +233,23 @@ impl BenchmarkContext { *gas_objects = Arc::new(refreshed_gas_objects); } } + + pub(crate) async fn validator_sign_transactions( + &self, + transactions: Vec, + ) -> Vec { + info!( + "Started signing {} transactions. You can now attach a profiler", + transactions.len(), + ); + let tasks: FuturesUnordered<_> = transactions + .into_iter() + .map(|tx| { + let validator = self.validator(); + tokio::spawn(async move { validator.sign_transaction(tx).await }) + }) + .collect(); + let results: Vec<_> = tasks.collect().await; + results.into_iter().map(|r| r.unwrap()).collect() + } } diff --git a/crates/sui-single-node-benchmark/src/command.rs b/crates/sui-single-node-benchmark/src/command.rs index 32a90007fd129..6d64ff21fe88e 100644 --- a/crates/sui-single-node-benchmark/src/command.rs +++ b/crates/sui-single-node-benchmark/src/command.rs @@ -84,4 +84,6 @@ pub enum Component { /// and store the sequenced transactions into the store. It covers the consensus-independent /// portion of the code in consensus handler. ValidatorWithFakeConsensus, + /// Benchmark only validator signing compoment: `handle_transaction`. + TxnSigning, } diff --git a/crates/sui-single-node-benchmark/src/execution.rs b/crates/sui-single-node-benchmark/src/execution.rs index 0eeec8bcd37d9..654ea53046838 100644 --- a/crates/sui-single-node-benchmark/src/execution.rs +++ b/crates/sui-single-node-benchmark/src/execution.rs @@ -22,7 +22,7 @@ pub async fn benchmark_simple_transfer(tx_count: u64, component: Component) { let transactions = ctx .generate_transactions(Arc::new(NonMoveTxGenerator::new())) .await; - benchmark_transactions(&ctx, transactions).await; + benchmark_transactions(&ctx, transactions, component).await; } /// Benchmark Move transactions. @@ -57,7 +57,7 @@ pub async fn benchmark_move_transactions( root_objects, ))) .await; - benchmark_transactions(&ctx, transactions).await; + benchmark_transactions(&ctx, transactions, component).await; } /// In order to benchmark transactions that can read dynamic fields, we must first create @@ -104,8 +104,23 @@ async fn preparing_dynamic_fields( root_objects } +async fn benchmark_transactions( + ctx: &BenchmarkContext, + transactions: Vec, + component: Component, +) { + match component { + Component::TxnSigning => { + benchmark_transaction_signing(ctx, transactions).await; + } + _ => { + benchmark_transaction_execution(ctx, transactions).await; + } + } +} + /// Benchmark parallel execution of a vector of transactions and measure the TPS. -async fn benchmark_transactions(ctx: &BenchmarkContext, transactions: Vec) { +async fn benchmark_transaction_execution(ctx: &BenchmarkContext, transactions: Vec) { let mut transactions = ctx.certify_transactions(transactions).await; // Print out a sample transaction and its effects so that we can get a rough idea @@ -129,3 +144,19 @@ async fn benchmark_transactions(ctx: &BenchmarkContext, transactions: Vec) { + let sample_transaction = &transactions[0]; + info!("Sample transaction: {:?}", sample_transaction.data()); + + let tx_count = transactions.len(); + let start_time = std::time::Instant::now(); + ctx.validator_sign_transactions(transactions).await; + let elapsed = start_time.elapsed().as_millis() as f64 / 1000f64; + info!( + "Transaction signing finished in {}s, TPS={}.", + elapsed, + tx_count as f64 / elapsed, + ); +} diff --git a/crates/sui-single-node-benchmark/src/single_node.rs b/crates/sui-single-node-benchmark/src/single_node.rs index cf64f6a86fb1e..06b3f306d7282 100644 --- a/crates/sui-single-node-benchmark/src/single_node.rs +++ b/crates/sui-single-node-benchmark/src/single_node.rs @@ -18,6 +18,7 @@ use sui_types::committee::Committee; use sui_types::crypto::AccountKeyPair; use sui_types::effects::{TransactionEffects, TransactionEffectsAPI}; use sui_types::executable_transaction::VerifiedExecutableTransaction; +use sui_types::messages_grpc::HandleTransactionResponse; use sui_types::object::Object; use sui_types::transaction::{ CertifiedTransaction, Transaction, VerifiedCertificate, VerifiedTransaction, @@ -115,6 +116,7 @@ impl SingleValidator { cert: CertifiedTransaction, component: Component, ) -> TransactionEffects { + assert!(!matches!(component, Component::TxnSigning)); let effects = match component { Component::Baseline => { let cert = VerifiedExecutableTransaction::new_from_certificate( @@ -142,8 +144,15 @@ impl SingleValidator { .await; response.signed_effects.into_data() } + Component::TxnSigning => unreachable!(), }; assert!(effects.status().is_ok()); effects } + + pub async fn sign_transaction(&self, transaction: Transaction) -> HandleTransactionResponse { + self.validator_service + .handle_transaction_for_testing(transaction) + .await + } }