Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 90bedd7

Browse files
authored
Split signature throughput tracking out of FeeCalculator (#8447)
* SDK: Split new `FeeRateGovernor` out of `FeeCalculator` Leaving `FeeCalculator` to *only* calculate transaction fees * Replace `FeeCalculator` with `FeeRateGovernor` as appropriate * Expose recent `FeeRateGovernor` to clients * Move `burn()` back into `FeeCalculator` Appease BPF tests * Revert "Move `burn()` back into `FeeCalculator`" This reverts commit f303562. * Adjust BPF `Fee` sysvar test to reflect removal of `burn()` from `FeeCalculator` * Make `FeeRateGovernor`'s `lamports_per_signature` private * rebase artifacts * fmt * Drop 'Recent' * Drop _with_commitment variant * Use a more portable integer for `target_signatures_per_slot` * Add docs for `getReeRateCalculator` JSON RPC method * Don't return `lamports_per_signature` in `getFeeRateGovernor` JSONRPC reply
1 parent 7d27be2 commit 90bedd7

File tree

22 files changed

+298
-118
lines changed

22 files changed

+298
-118
lines changed

bench-tps/src/bench.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,8 +1059,8 @@ pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
10591059
// pay for the transaction fees in a new run.
10601060
let enough_lamports = 8 * lamports_per_account / 10;
10611061
if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
1062-
let (_blockhash, fee_calculator) = get_recent_blockhash(client.as_ref());
1063-
let max_fee = fee_calculator.max_lamports_per_signature;
1062+
let fee_rate_governor = client.get_fee_rate_governor().unwrap();
1063+
let max_fee = fee_rate_governor.max_lamports_per_signature;
10641064
let extra_fees = extra * max_fee;
10651065
let total_keypairs = keypairs.len() as u64 + 1; // Add one for funding keypair
10661066
let mut total = lamports_per_account * total_keypairs + extra_fees;
@@ -1134,7 +1134,7 @@ mod tests {
11341134
use solana_runtime::bank::Bank;
11351135
use solana_runtime::bank_client::BankClient;
11361136
use solana_sdk::client::SyncClient;
1137-
use solana_sdk::fee_calculator::FeeCalculator;
1137+
use solana_sdk::fee_calculator::FeeRateGovernor;
11381138
use solana_sdk::genesis_config::create_genesis_config;
11391139

11401140
#[test]
@@ -1181,8 +1181,8 @@ mod tests {
11811181
#[test]
11821182
fn test_bench_tps_fund_keys_with_fees() {
11831183
let (mut genesis_config, id) = create_genesis_config(10_000);
1184-
let fee_calculator = FeeCalculator::new(11, 0);
1185-
genesis_config.fee_calculator = fee_calculator;
1184+
let fee_rate_governor = FeeRateGovernor::new(11, 0);
1185+
genesis_config.fee_rate_governor = fee_rate_governor;
11861186
let bank = Bank::new(&genesis_config);
11871187
let client = Arc::new(BankClient::new(bank));
11881188
let keypair_count = 20;

bench-tps/src/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clap::{crate_description, crate_name, App, Arg, ArgMatches};
22
use solana_faucet::faucet::FAUCET_PORT;
3-
use solana_sdk::fee_calculator::FeeCalculator;
3+
use solana_sdk::fee_calculator::FeeRateGovernor;
44
use solana_sdk::signature::{read_keypair_file, Keypair};
55
use std::{net::SocketAddr, process::exit, time::Duration};
66

@@ -43,7 +43,7 @@ impl Default for Config {
4343
client_ids_and_stake_file: String::new(),
4444
write_to_client_file: false,
4545
read_from_client_file: false,
46-
target_lamports_per_signature: FeeCalculator::default().target_lamports_per_signature,
46+
target_lamports_per_signature: FeeRateGovernor::default().target_lamports_per_signature,
4747
multi_client: true,
4848
use_move: false,
4949
num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,

bench-tps/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate
33
use solana_bench_tps::cli;
44
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
55
use solana_genesis::Base64Account;
6-
use solana_sdk::fee_calculator::FeeCalculator;
6+
use solana_sdk::fee_calculator::FeeRateGovernor;
77
use solana_sdk::signature::{Keypair, Signer};
88
use solana_sdk::system_program;
99
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};
@@ -41,7 +41,7 @@ fn main() {
4141
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
4242
let num_accounts = keypairs.len() as u64;
4343
let max_fee =
44-
FeeCalculator::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
44+
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
4545
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
4646
/ num_accounts
4747
+ num_lamports_per_account;

cli/src/offline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ mod tests {
201201
fn test_blockhashspec_get_blockhash_fee_calc() {
202202
let test_blockhash = hash(&[0u8]);
203203
let rpc_blockhash = hash(&[1u8]);
204-
let rpc_fee_calc = FeeCalculator::new(42, 42);
204+
let rpc_fee_calc = FeeCalculator::new(42);
205205
let get_recent_blockhash_response = json!(Response {
206206
context: RpcResponseContext { slot: 1 },
207207
value: json!((

client/src/mock_rpc_client_request.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77
use serde_json::{Number, Value};
88
use solana_sdk::{
9-
fee_calculator::FeeCalculator,
9+
fee_calculator::{FeeCalculator, FeeRateGovernor},
1010
instruction::InstructionError,
1111
transaction::{self, TransactionError},
1212
};
@@ -71,6 +71,10 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
7171
serde_json::to_value(FeeCalculator::default()).unwrap(),
7272
),
7373
})?,
74+
RpcRequest::GetFeeRateGovernor => serde_json::to_value(Response {
75+
context: RpcResponseContext { slot: 1 },
76+
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
77+
})?,
7478
RpcRequest::GetSignatureStatus => {
7579
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
7680
Some(Err(TransactionError::AccountInUse))

client/src/rpc_client.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use crate::{
66
rpc_request::RpcRequest,
77
rpc_response::{
88
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
9-
RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse, RpcVersionInfo,
10-
RpcVoteAccountStatus,
9+
RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse,
10+
RpcVersionInfo, RpcVoteAccountStatus,
1111
},
1212
};
1313
use bincode::serialize;
@@ -18,7 +18,7 @@ use solana_sdk::{
1818
clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
1919
commitment_config::CommitmentConfig,
2020
epoch_schedule::EpochSchedule,
21-
fee_calculator::FeeCalculator,
21+
fee_calculator::{FeeCalculator, FeeRateGovernor},
2222
hash::Hash,
2323
inflation::Inflation,
2424
pubkey::Pubkey,
@@ -804,6 +804,31 @@ impl RpcClient {
804804
})
805805
}
806806

807+
pub fn get_fee_rate_governor(&self) -> RpcResponse<FeeRateGovernor> {
808+
let response = self
809+
.client
810+
.send(&RpcRequest::GetFeeRateGovernor, Value::Null, 0)
811+
.map_err(|e| {
812+
io::Error::new(
813+
io::ErrorKind::Other,
814+
format!("GetFeeRateGovernor request failure: {:?}", e),
815+
)
816+
})?;
817+
let Response {
818+
context,
819+
value: RpcFeeRateGovernor { fee_rate_governor },
820+
} = serde_json::from_value::<Response<RpcFeeRateGovernor>>(response).map_err(|e| {
821+
io::Error::new(
822+
io::ErrorKind::Other,
823+
format!("GetFeeRateGovernor parse failure: {:?}", e),
824+
)
825+
})?;
826+
Ok(Response {
827+
context,
828+
value: fee_rate_governor,
829+
})
830+
}
831+
807832
pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> {
808833
let mut num_retries = 0;
809834
let start = Instant::now();

client/src/rpc_request.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub enum RpcRequest {
2020
GetNumBlocksSinceSignatureConfirmation,
2121
GetProgramAccounts,
2222
GetRecentBlockhash,
23+
GetFeeRateGovernor,
2324
GetSignatureStatus,
2425
GetSlot,
2526
GetSlotLeader,
@@ -61,6 +62,7 @@ impl RpcRequest {
6162
}
6263
RpcRequest::GetProgramAccounts => "getProgramAccounts",
6364
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
65+
RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
6466
RpcRequest::GetSignatureStatus => "getSignatureStatus",
6567
RpcRequest::GetSlot => "getSlot",
6668
RpcRequest::GetSlotLeader => "getSlotLeader",
@@ -138,6 +140,10 @@ mod tests {
138140
let request = test_request.build_request_json(1, Value::Null);
139141
assert_eq!(request["method"], "getRecentBlockhash");
140142

143+
let test_request = RpcRequest::GetFeeRateGovernor;
144+
let request = test_request.build_request_json(1, Value::Null);
145+
assert_eq!(request["method"], "getFeeRateGovernor");
146+
141147
let test_request = RpcRequest::GetSlot;
142148
let request = test_request.build_request_json(1, Value::Null);
143149
assert_eq!(request["method"], "getSlot");

client/src/rpc_response.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use jsonrpc_core::Result as JsonResult;
44
use solana_sdk::{
55
account::Account,
66
clock::{Epoch, Slot},
7-
fee_calculator::FeeCalculator,
7+
fee_calculator::{FeeCalculator, FeeRateGovernor},
88
message::MessageHeader,
99
pubkey::Pubkey,
1010
transaction::{Result, Transaction},
@@ -152,6 +152,12 @@ pub struct RpcBlockhashFeeCalculator {
152152
pub fee_calculator: FeeCalculator,
153153
}
154154

155+
#[derive(Serialize, Deserialize, Clone, Debug)]
156+
#[serde(rename_all = "camelCase")]
157+
pub struct RpcFeeRateGovernor {
158+
pub fee_rate_governor: FeeRateGovernor,
159+
}
160+
155161
#[derive(Serialize, Deserialize, Clone, Debug)]
156162
#[serde(rename_all = "camelCase")]
157163
pub struct RpcKeyedAccount {

client/src/thin_client.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use solana_sdk::{
1111
client::{AsyncClient, Client, SyncClient},
1212
clock::MAX_PROCESSING_AGE,
1313
commitment_config::CommitmentConfig,
14-
fee_calculator::FeeCalculator,
14+
fee_calculator::{FeeCalculator, FeeRateGovernor},
1515
hash::Hash,
1616
instruction::Instruction,
1717
message::Message,
@@ -445,6 +445,11 @@ impl SyncClient for ThinClient {
445445
}
446446
}
447447

448+
fn get_fee_rate_governor(&self) -> TransportResult<FeeRateGovernor> {
449+
let fee_rate_governor = self.rpc_client().get_fee_rate_governor()?;
450+
Ok(fee_rate_governor.value)
451+
}
452+
448453
fn get_signature_status(
449454
&self,
450455
signature: &Signature,

core/src/rpc.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use jsonrpc_core::{Error, Metadata, Result};
99
use jsonrpc_derive::rpc;
1010
use solana_client::rpc_response::{
1111
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
12-
RpcContactInfo, RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponseContext,
13-
RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding, RpcVersionInfo,
14-
RpcVoteAccountInfo, RpcVoteAccountStatus,
12+
RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule,
13+
RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding,
14+
RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
1515
};
1616
use solana_faucet::faucet::request_airdrop_transaction;
1717
use solana_ledger::{
@@ -164,6 +164,17 @@ impl JsonRpcRequestProcessor {
164164
)
165165
}
166166

167+
fn get_fee_rate_governor(&self) -> RpcResponse<RpcFeeRateGovernor> {
168+
let bank = &*self.bank(None);
169+
let fee_rate_governor = bank.get_fee_rate_governor();
170+
new_response(
171+
bank,
172+
RpcFeeRateGovernor {
173+
fee_rate_governor: fee_rate_governor.clone(),
174+
},
175+
)
176+
}
177+
167178
pub fn confirm_transaction(
168179
&self,
169180
signature: Result<Signature>,
@@ -491,6 +502,9 @@ pub trait RpcSol {
491502
commitment: Option<CommitmentConfig>,
492503
) -> RpcResponse<RpcBlockhashFeeCalculator>;
493504

505+
#[rpc(meta, name = "getFeeRateGovernor")]
506+
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor>;
507+
494508
#[rpc(meta, name = "getSignatureStatus")]
495509
fn get_signature_status(
496510
&self,
@@ -813,6 +827,14 @@ impl RpcSol for RpcSolImpl {
813827
.get_recent_blockhash(commitment)
814828
}
815829

830+
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor> {
831+
debug!("get_fee_rate_governor rpc request received");
832+
meta.request_processor
833+
.read()
834+
.unwrap()
835+
.get_fee_rate_governor()
836+
}
837+
816838
fn get_signature_status(
817839
&self,
818840
meta: Self::Metadata,
@@ -1770,8 +1792,32 @@ pub mod tests {
17701792
"value":{
17711793
"blockhash": blockhash.to_string(),
17721794
"feeCalculator": {
1773-
"burnPercent": DEFAULT_BURN_PERCENT,
17741795
"lamportsPerSignature": 0,
1796+
}
1797+
}},
1798+
"id": 1
1799+
});
1800+
let expected: Response =
1801+
serde_json::from_value(expected).expect("expected response deserialization");
1802+
let result: Response = serde_json::from_str(&res.expect("actual response"))
1803+
.expect("actual response deserialization");
1804+
assert_eq!(expected, result);
1805+
}
1806+
1807+
#[test]
1808+
fn test_rpc_get_fee_rate_governor() {
1809+
let bob_pubkey = Pubkey::new_rand();
1810+
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
1811+
1812+
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getFeeRateGovernor"}}"#);
1813+
let res = io.handle_request_sync(&req, meta);
1814+
let expected = json!({
1815+
"jsonrpc": "2.0",
1816+
"result": {
1817+
"context":{"slot":0},
1818+
"value":{
1819+
"feeRateGovernor": {
1820+
"burnPercent": DEFAULT_BURN_PERCENT,
17751821
"maxLamportsPerSignature": 0,
17761822
"minLamportsPerSignature": 0,
17771823
"targetLamportsPerSignature": 0,

core/src/validator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ impl TestValidator {
680680

681681
pub fn run_with_options(options: TestValidatorOptions) -> Self {
682682
use crate::genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo};
683-
use solana_sdk::fee_calculator::FeeCalculator;
683+
use solana_sdk::fee_calculator::FeeRateGovernor;
684684

685685
let TestValidatorOptions {
686686
fees,
@@ -706,7 +706,7 @@ impl TestValidator {
706706

707707
genesis_config.rent.lamports_per_byte_year = 1;
708708
genesis_config.rent.exemption_threshold = 1.0;
709-
genesis_config.fee_calculator = FeeCalculator::new(fees, 0);
709+
genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0);
710710

711711
let (ledger_path, blockhash) = create_new_tmp_ledger!(&genesis_config);
712712

docs/src/apps/jsonrpc-api.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
2424
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
2525
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
2626
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
27+
* [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor)
2728
* [getGenesisHash](jsonrpc-api.md#getgenesishash)
2829
* [getInflation](jsonrpc-api.md#getinflation)
2930
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
@@ -403,6 +404,34 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
403404
{"jsonrpc":"2.0","result":{"firstNormalEpoch":8,"firstNormalSlot":8160,"leaderScheduleSlotOffset":8192,"slotsPerEpoch":8192,"warmup":true},"id":1}
404405
```
405406

407+
### getFeeRateGovernor
408+
409+
Returns the fee rate governor information from the root bank
410+
411+
#### Parameters:
412+
413+
None
414+
415+
#### Results:
416+
417+
The `result` field will be an `object` with the following fields:
418+
419+
* `burnPercent: <u8>`, Percentage of fees collected to be destroyed
420+
* `maxLamportsPerSignature: <u64>`, Largest value `lamportsPerSignature` can attain for the next slot
421+
* `minLamportsPerSignature: <u64>`, Smallest value `lamportsPerSignature` can attain for the next slot
422+
* `targetLamportsPerSignature: <u64>`, Desired fee rate for the cluster
423+
* `targetSignaturesPerSlot: <u64>`, Desired signature rate for the cluster
424+
425+
#### Example:
426+
427+
```bash
428+
// Request
429+
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getFeeRateGovernor"}' http://localhost:8899
430+
431+
// Result
432+
{"jsonrpc":"2.0","result":{"context":{"slot":54},"value":{"feeRateGovernor":{"burnPercent":50,"maxLamportsPerSignature":100000,"minLamportsPerSignature":5000,"targetLamportsPerSignature":10000,"targetSignaturesPerSlot":20000}}},"id":1}
433+
```
434+
406435
### getGenesisHash
407436

408437
Returns the genesis hash

0 commit comments

Comments
 (0)