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 f3035624307196722b62ff8b74c12cfcc13b1941.

* 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
This commit is contained in:
Trent Nelson
2020-02-28 13:27:01 -07:00
committed by GitHub
parent 7d27be2a73
commit 90bedd7e06
22 changed files with 298 additions and 118 deletions

View File

@ -1059,8 +1059,8 @@ pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
// pay for the transaction fees in a new run. // pay for the transaction fees in a new run.
let enough_lamports = 8 * lamports_per_account / 10; let enough_lamports = 8 * lamports_per_account / 10;
if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports { if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
let (_blockhash, fee_calculator) = get_recent_blockhash(client.as_ref()); let fee_rate_governor = client.get_fee_rate_governor().unwrap();
let max_fee = fee_calculator.max_lamports_per_signature; let max_fee = fee_rate_governor.max_lamports_per_signature;
let extra_fees = extra * max_fee; let extra_fees = extra * max_fee;
let total_keypairs = keypairs.len() as u64 + 1; // Add one for funding keypair let total_keypairs = keypairs.len() as u64 + 1; // Add one for funding keypair
let mut total = lamports_per_account * total_keypairs + extra_fees; let mut total = lamports_per_account * total_keypairs + extra_fees;
@ -1134,7 +1134,7 @@ mod tests {
use solana_runtime::bank::Bank; use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient; use solana_runtime::bank_client::BankClient;
use solana_sdk::client::SyncClient; use solana_sdk::client::SyncClient;
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::genesis_config::create_genesis_config; use solana_sdk::genesis_config::create_genesis_config;
#[test] #[test]
@ -1181,8 +1181,8 @@ mod tests {
#[test] #[test]
fn test_bench_tps_fund_keys_with_fees() { fn test_bench_tps_fund_keys_with_fees() {
let (mut genesis_config, id) = create_genesis_config(10_000); let (mut genesis_config, id) = create_genesis_config(10_000);
let fee_calculator = FeeCalculator::new(11, 0); let fee_rate_governor = FeeRateGovernor::new(11, 0);
genesis_config.fee_calculator = fee_calculator; genesis_config.fee_rate_governor = fee_rate_governor;
let bank = Bank::new(&genesis_config); let bank = Bank::new(&genesis_config);
let client = Arc::new(BankClient::new(bank)); let client = Arc::new(BankClient::new(bank));
let keypair_count = 20; let keypair_count = 20;

View File

@ -1,6 +1,6 @@
use clap::{crate_description, crate_name, App, Arg, ArgMatches}; use clap::{crate_description, crate_name, App, Arg, ArgMatches};
use solana_faucet::faucet::FAUCET_PORT; use solana_faucet::faucet::FAUCET_PORT;
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{read_keypair_file, Keypair}; use solana_sdk::signature::{read_keypair_file, Keypair};
use std::{net::SocketAddr, process::exit, time::Duration}; use std::{net::SocketAddr, process::exit, time::Duration};
@ -43,7 +43,7 @@ impl Default for Config {
client_ids_and_stake_file: String::new(), client_ids_and_stake_file: String::new(),
write_to_client_file: false, write_to_client_file: false,
read_from_client_file: false, read_from_client_file: false,
target_lamports_per_signature: FeeCalculator::default().target_lamports_per_signature, target_lamports_per_signature: FeeRateGovernor::default().target_lamports_per_signature,
multi_client: true, multi_client: true,
use_move: false, use_move: false,
num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT, num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,

View File

@ -3,7 +3,7 @@ use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate
use solana_bench_tps::cli; use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client}; use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
use solana_genesis::Base64Account; use solana_genesis::Base64Account;
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{Keypair, Signer}; use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_program; use solana_sdk::system_program;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc}; use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};
@ -41,7 +41,7 @@ fn main() {
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64); let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let num_accounts = keypairs.len() as u64; let num_accounts = keypairs.len() as u64;
let max_fee = let max_fee =
FeeCalculator::new(*target_lamports_per_signature, 0).max_lamports_per_signature; FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee) let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
/ num_accounts / num_accounts
+ num_lamports_per_account; + num_lamports_per_account;

View File

@ -201,7 +201,7 @@ mod tests {
fn test_blockhashspec_get_blockhash_fee_calc() { fn test_blockhashspec_get_blockhash_fee_calc() {
let test_blockhash = hash(&[0u8]); let test_blockhash = hash(&[0u8]);
let rpc_blockhash = hash(&[1u8]); let rpc_blockhash = hash(&[1u8]);
let rpc_fee_calc = FeeCalculator::new(42, 42); let rpc_fee_calc = FeeCalculator::new(42);
let get_recent_blockhash_response = json!(Response { let get_recent_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 }, context: RpcResponseContext { slot: 1 },
value: json!(( value: json!((

View File

@ -6,7 +6,7 @@ use crate::{
}; };
use serde_json::{Number, Value}; use serde_json::{Number, Value};
use solana_sdk::{ use solana_sdk::{
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
instruction::InstructionError, instruction::InstructionError,
transaction::{self, TransactionError}, transaction::{self, TransactionError},
}; };
@ -71,6 +71,10 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
serde_json::to_value(FeeCalculator::default()).unwrap(), serde_json::to_value(FeeCalculator::default()).unwrap(),
), ),
})?, })?,
RpcRequest::GetFeeRateGovernor => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
})?,
RpcRequest::GetSignatureStatus => { RpcRequest::GetSignatureStatus => {
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" { let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
Some(Err(TransactionError::AccountInUse)) Some(Err(TransactionError::AccountInUse))

View File

@ -6,8 +6,8 @@ use crate::{
rpc_request::RpcRequest, rpc_request::RpcRequest,
rpc_response::{ rpc_response::{
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo, Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse, RpcVersionInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse,
RpcVoteAccountStatus, RpcVersionInfo, RpcVoteAccountStatus,
}, },
}; };
use bincode::serialize; use bincode::serialize;
@ -18,7 +18,7 @@ use solana_sdk::{
clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}, clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash, hash::Hash,
inflation::Inflation, inflation::Inflation,
pubkey::Pubkey, pubkey::Pubkey,
@ -804,6 +804,31 @@ impl RpcClient {
}) })
} }
pub fn get_fee_rate_governor(&self) -> RpcResponse<FeeRateGovernor> {
let response = self
.client
.send(&RpcRequest::GetFeeRateGovernor, Value::Null, 0)
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("GetFeeRateGovernor request failure: {:?}", e),
)
})?;
let Response {
context,
value: RpcFeeRateGovernor { fee_rate_governor },
} = serde_json::from_value::<Response<RpcFeeRateGovernor>>(response).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("GetFeeRateGovernor parse failure: {:?}", e),
)
})?;
Ok(Response {
context,
value: fee_rate_governor,
})
}
pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> { pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> {
let mut num_retries = 0; let mut num_retries = 0;
let start = Instant::now(); let start = Instant::now();

View File

@ -20,6 +20,7 @@ pub enum RpcRequest {
GetNumBlocksSinceSignatureConfirmation, GetNumBlocksSinceSignatureConfirmation,
GetProgramAccounts, GetProgramAccounts,
GetRecentBlockhash, GetRecentBlockhash,
GetFeeRateGovernor,
GetSignatureStatus, GetSignatureStatus,
GetSlot, GetSlot,
GetSlotLeader, GetSlotLeader,
@ -61,6 +62,7 @@ impl RpcRequest {
} }
RpcRequest::GetProgramAccounts => "getProgramAccounts", RpcRequest::GetProgramAccounts => "getProgramAccounts",
RpcRequest::GetRecentBlockhash => "getRecentBlockhash", RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
RpcRequest::GetSignatureStatus => "getSignatureStatus", RpcRequest::GetSignatureStatus => "getSignatureStatus",
RpcRequest::GetSlot => "getSlot", RpcRequest::GetSlot => "getSlot",
RpcRequest::GetSlotLeader => "getSlotLeader", RpcRequest::GetSlotLeader => "getSlotLeader",
@ -138,6 +140,10 @@ mod tests {
let request = test_request.build_request_json(1, Value::Null); let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getRecentBlockhash"); assert_eq!(request["method"], "getRecentBlockhash");
let test_request = RpcRequest::GetFeeRateGovernor;
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getFeeRateGovernor");
let test_request = RpcRequest::GetSlot; let test_request = RpcRequest::GetSlot;
let request = test_request.build_request_json(1, Value::Null); let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getSlot"); assert_eq!(request["method"], "getSlot");

View File

@ -4,7 +4,7 @@ use jsonrpc_core::Result as JsonResult;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
clock::{Epoch, Slot}, clock::{Epoch, Slot},
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
message::MessageHeader, message::MessageHeader,
pubkey::Pubkey, pubkey::Pubkey,
transaction::{Result, Transaction}, transaction::{Result, Transaction},
@ -152,6 +152,12 @@ pub struct RpcBlockhashFeeCalculator {
pub fee_calculator: FeeCalculator, pub fee_calculator: FeeCalculator,
} }
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcFeeRateGovernor {
pub fee_rate_governor: FeeRateGovernor,
}
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct RpcKeyedAccount { pub struct RpcKeyedAccount {

View File

@ -11,7 +11,7 @@ use solana_sdk::{
client::{AsyncClient, Client, SyncClient}, client::{AsyncClient, Client, SyncClient},
clock::MAX_PROCESSING_AGE, clock::MAX_PROCESSING_AGE,
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash, hash::Hash,
instruction::Instruction, instruction::Instruction,
message::Message, message::Message,
@ -445,6 +445,11 @@ impl SyncClient for ThinClient {
} }
} }
fn get_fee_rate_governor(&self) -> TransportResult<FeeRateGovernor> {
let fee_rate_governor = self.rpc_client().get_fee_rate_governor()?;
Ok(fee_rate_governor.value)
}
fn get_signature_status( fn get_signature_status(
&self, &self,
signature: &Signature, signature: &Signature,

View File

@ -9,9 +9,9 @@ use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc; use jsonrpc_derive::rpc;
use solana_client::rpc_response::{ use solana_client::rpc_response::{
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock, Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
RpcContactInfo, RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponseContext, RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule,
RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding, RpcVersionInfo, RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding,
RpcVoteAccountInfo, RpcVoteAccountStatus, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
}; };
use solana_faucet::faucet::request_airdrop_transaction; use solana_faucet::faucet::request_airdrop_transaction;
use solana_ledger::{ use solana_ledger::{
@ -164,6 +164,17 @@ impl JsonRpcRequestProcessor {
) )
} }
fn get_fee_rate_governor(&self) -> RpcResponse<RpcFeeRateGovernor> {
let bank = &*self.bank(None);
let fee_rate_governor = bank.get_fee_rate_governor();
new_response(
bank,
RpcFeeRateGovernor {
fee_rate_governor: fee_rate_governor.clone(),
},
)
}
pub fn confirm_transaction( pub fn confirm_transaction(
&self, &self,
signature: Result<Signature>, signature: Result<Signature>,
@ -491,6 +502,9 @@ pub trait RpcSol {
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> RpcResponse<RpcBlockhashFeeCalculator>; ) -> RpcResponse<RpcBlockhashFeeCalculator>;
#[rpc(meta, name = "getFeeRateGovernor")]
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor>;
#[rpc(meta, name = "getSignatureStatus")] #[rpc(meta, name = "getSignatureStatus")]
fn get_signature_status( fn get_signature_status(
&self, &self,
@ -813,6 +827,14 @@ impl RpcSol for RpcSolImpl {
.get_recent_blockhash(commitment) .get_recent_blockhash(commitment)
} }
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor> {
debug!("get_fee_rate_governor rpc request received");
meta.request_processor
.read()
.unwrap()
.get_fee_rate_governor()
}
fn get_signature_status( fn get_signature_status(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
@ -1770,8 +1792,32 @@ pub mod tests {
"value":{ "value":{
"blockhash": blockhash.to_string(), "blockhash": blockhash.to_string(),
"feeCalculator": { "feeCalculator": {
"burnPercent": DEFAULT_BURN_PERCENT,
"lamportsPerSignature": 0, "lamportsPerSignature": 0,
}
}},
"id": 1
});
let expected: Response =
serde_json::from_value(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);
}
#[test]
fn test_rpc_get_fee_rate_governor() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getFeeRateGovernor"}}"#);
let res = io.handle_request_sync(&req, meta);
let expected = json!({
"jsonrpc": "2.0",
"result": {
"context":{"slot":0},
"value":{
"feeRateGovernor": {
"burnPercent": DEFAULT_BURN_PERCENT,
"maxLamportsPerSignature": 0, "maxLamportsPerSignature": 0,
"minLamportsPerSignature": 0, "minLamportsPerSignature": 0,
"targetLamportsPerSignature": 0, "targetLamportsPerSignature": 0,

View File

@ -680,7 +680,7 @@ impl TestValidator {
pub fn run_with_options(options: TestValidatorOptions) -> Self { pub fn run_with_options(options: TestValidatorOptions) -> Self {
use crate::genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo}; use crate::genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo};
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeRateGovernor;
let TestValidatorOptions { let TestValidatorOptions {
fees, fees,
@ -706,7 +706,7 @@ impl TestValidator {
genesis_config.rent.lamports_per_byte_year = 1; genesis_config.rent.lamports_per_byte_year = 1;
genesis_config.rent.exemption_threshold = 1.0; genesis_config.rent.exemption_threshold = 1.0;
genesis_config.fee_calculator = FeeCalculator::new(fees, 0); genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0);
let (ledger_path, blockhash) = create_new_tmp_ledger!(&genesis_config); let (ledger_path, blockhash) = create_new_tmp_ledger!(&genesis_config);

View File

@ -24,6 +24,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks) * [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
* [getEpochInfo](jsonrpc-api.md#getepochinfo) * [getEpochInfo](jsonrpc-api.md#getepochinfo)
* [getEpochSchedule](jsonrpc-api.md#getepochschedule) * [getEpochSchedule](jsonrpc-api.md#getepochschedule)
* [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor)
* [getGenesisHash](jsonrpc-api.md#getgenesishash) * [getGenesisHash](jsonrpc-api.md#getgenesishash)
* [getInflation](jsonrpc-api.md#getinflation) * [getInflation](jsonrpc-api.md#getinflation)
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule) * [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
@ -403,6 +404,34 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
{"jsonrpc":"2.0","result":{"firstNormalEpoch":8,"firstNormalSlot":8160,"leaderScheduleSlotOffset":8192,"slotsPerEpoch":8192,"warmup":true},"id":1} {"jsonrpc":"2.0","result":{"firstNormalEpoch":8,"firstNormalSlot":8160,"leaderScheduleSlotOffset":8192,"slotsPerEpoch":8192,"warmup":true},"id":1}
``` ```
### getFeeRateGovernor
Returns the fee rate governor information from the root bank
#### Parameters:
None
#### Results:
The `result` field will be an `object` with the following fields:
* `burnPercent: <u8>`, Percentage of fees collected to be destroyed
* `maxLamportsPerSignature: <u64>`, Largest value `lamportsPerSignature` can attain for the next slot
* `minLamportsPerSignature: <u64>`, Smallest value `lamportsPerSignature` can attain for the next slot
* `targetLamportsPerSignature: <u64>`, Desired fee rate for the cluster
* `targetSignaturesPerSlot: <u64>`, Desired signature rate for the cluster
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getFeeRateGovernor"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"context":{"slot":54},"value":{"feeRateGovernor":{"burnPercent":50,"maxLamportsPerSignature":100000,"minLamportsPerSignature":5000,"targetLamportsPerSignature":10000,"targetSignaturesPerSlot":20000}}},"id":1}
```
### getGenesisHash ### getGenesisHash
Returns the genesis hash Returns the genesis hash

View File

@ -11,7 +11,7 @@ use solana_sdk::{
account::Account, account::Account,
clock, clock,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::FeeRateGovernor,
genesis_config::{GenesisConfig, OperatingMode}, genesis_config::{GenesisConfig, OperatingMode},
native_token::sol_to_lamports, native_token::sol_to_lamports,
poh_config::PohConfig, poh_config::PohConfig,
@ -99,16 +99,16 @@ pub fn load_genesis_accounts(file: &str, genesis_config: &mut GenesisConfig) ->
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn main() -> Result<(), Box<dyn error::Error>> { fn main() -> Result<(), Box<dyn error::Error>> {
let fee_calculator = FeeCalculator::default(); let fee_rate_governor = FeeRateGovernor::default();
let ( let (
default_target_lamports_per_signature, default_target_lamports_per_signature,
default_target_signatures_per_slot, default_target_signatures_per_slot,
default_fee_burn_percentage, default_fee_burn_percentage,
) = { ) = {
( (
&fee_calculator.target_lamports_per_signature.to_string(), &fee_rate_governor.target_lamports_per_signature.to_string(),
&fee_calculator.target_signatures_per_slot.to_string(), &fee_rate_governor.target_signatures_per_slot.to_string(),
&fee_calculator.burn_percent.to_string(), &fee_rate_governor.burn_percent.to_string(),
) )
}; };
@ -449,11 +449,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let ticks_per_slot = value_t_or_exit!(matches, "ticks_per_slot", u64); let ticks_per_slot = value_t_or_exit!(matches, "ticks_per_slot", u64);
let mut fee_calculator = FeeCalculator::new( let mut fee_rate_governor = FeeRateGovernor::new(
value_t_or_exit!(matches, "target_lamports_per_signature", u64), value_t_or_exit!(matches, "target_lamports_per_signature", u64),
value_t_or_exit!(matches, "target_signatures_per_slot", usize), value_t_or_exit!(matches, "target_signatures_per_slot", u64),
); );
fee_calculator.burn_percent = value_t_or_exit!(matches, "fee_burn_percentage", u8); fee_rate_governor.burn_percent = value_t_or_exit!(matches, "fee_burn_percentage", u8);
let mut poh_config = PohConfig::default(); let mut poh_config = PohConfig::default();
poh_config.target_tick_duration = if matches.is_present("target_tick_duration") { poh_config.target_tick_duration = if matches.is_present("target_tick_duration") {
@ -513,7 +513,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
ticks_per_slot, ticks_per_slot,
epoch_schedule, epoch_schedule,
inflation, inflation,
fee_calculator, fee_rate_governor,
rent, rent,
poh_config, poh_config,
operating_mode, operating_mode,

View File

@ -25,7 +25,7 @@ pub struct StakerInfo {
// lamports to cover TX fees (delegation) for one year, // lamports to cover TX fees (delegation) for one year,
// and we support one delegation per epoch // and we support one delegation per epoch
fn calculate_staker_fees(genesis_config: &GenesisConfig, years: f64) -> u64 { fn calculate_staker_fees(genesis_config: &GenesisConfig, years: f64) -> u64 {
genesis_config.fee_calculator.max_lamports_per_signature genesis_config.fee_rate_governor.max_lamports_per_signature
* genesis_config.epoch_schedule.get_epoch(years_as_slots( * genesis_config.epoch_schedule.get_epoch(years_as_slots(
years, years,
&genesis_config.poh_config.target_tick_duration, &genesis_config.poh_config.target_tick_duration,

View File

@ -36,8 +36,8 @@ fn process_instruction(
info!("Fees identifier:"); info!("Fees identifier:");
sysvar::fees::id().log(); sysvar::fees::id().log();
let fees = Fees::from_account_info(&accounts[3]).expect("fees"); let fees = Fees::from_account_info(&accounts[3]).expect("fees");
let burn = fees.fee_calculator.burn(42); let fee_calculator = fees.fee_calculator;
assert_eq!(burn, (21, 21)); assert_eq!(fee_calculator.lamports_per_signature, 0);
// Rewards // Rewards
info!("Rewards identifier:"); info!("Rewards identifier:");

View File

@ -853,7 +853,7 @@ mod tests {
instructions, instructions,
); );
let fee_calculator = FeeCalculator::new(10, 0); let fee_calculator = FeeCalculator::new(10);
assert_eq!(fee_calculator.calculate_fee(tx.message()), 10); assert_eq!(fee_calculator.calculate_fee(tx.message()), 10);
let loaded_accounts = let loaded_accounts =
@ -918,7 +918,7 @@ mod tests {
let min_balance = rent_collector let min_balance = rent_collector
.rent .rent
.minimum_balance(nonce_state::NonceState::size()); .minimum_balance(nonce_state::NonceState::size());
let fee_calculator = FeeCalculator::new(min_balance, 0); let fee_calculator = FeeCalculator::new(min_balance);
let nonce = Keypair::new(); let nonce = Keypair::new();
let mut accounts = vec![( let mut accounts = vec![(
nonce.pubkey(), nonce.pubkey(),

View File

@ -35,7 +35,7 @@ use solana_sdk::{
account::Account, account::Account,
clock::{get_segment_from_slot, Epoch, Slot, UnixTimestamp, MAX_RECENT_BLOCKHASHES}, clock::{get_segment_from_slot, Epoch, Slot, UnixTimestamp, MAX_RECENT_BLOCKHASHES},
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
genesis_config::GenesisConfig, genesis_config::GenesisConfig,
hard_forks::HardForks, hard_forks::HardForks,
hash::{extend_and_hash, hashv, Hash}, hash::{extend_and_hash, hashv, Hash},
@ -302,6 +302,9 @@ pub struct Bank {
/// Latest transaction fees for transactions processed by this bank /// Latest transaction fees for transactions processed by this bank
fee_calculator: FeeCalculator, fee_calculator: FeeCalculator,
/// Track cluster signature throughput and adjust fee rate
fee_rate_governor: FeeRateGovernor,
/// Rent that have been collected /// Rent that have been collected
#[serde(serialize_with = "serialize_atomicu64")] #[serde(serialize_with = "serialize_atomicu64")]
#[serde(deserialize_with = "deserialize_atomicu64")] #[serde(deserialize_with = "deserialize_atomicu64")]
@ -401,6 +404,9 @@ impl Bank {
let epoch_schedule = parent.epoch_schedule; let epoch_schedule = parent.epoch_schedule;
let epoch = epoch_schedule.get_epoch(slot); let epoch = epoch_schedule.get_epoch(slot);
let fee_rate_governor =
FeeRateGovernor::new_derived(&parent.fee_rate_governor, parent.signature_count());
let mut new = Bank { let mut new = Bank {
rc, rc,
src, src,
@ -420,10 +426,8 @@ impl Bank {
rent_collector: parent.rent_collector.clone_with_epoch(epoch), rent_collector: parent.rent_collector.clone_with_epoch(epoch),
max_tick_height: (slot + 1) * parent.ticks_per_slot, max_tick_height: (slot + 1) * parent.ticks_per_slot,
block_height: parent.block_height + 1, block_height: parent.block_height + 1,
fee_calculator: FeeCalculator::new_derived( fee_calculator: fee_rate_governor.create_fee_calculator(),
&parent.fee_calculator, fee_rate_governor,
parent.signature_count() as usize,
),
capitalization: AtomicU64::new(parent.capitalization()), capitalization: AtomicU64::new(parent.capitalization()),
inflation: parent.inflation.clone(), inflation: parent.inflation.clone(),
transaction_count: AtomicU64::new(parent.transaction_count()), transaction_count: AtomicU64::new(parent.transaction_count()),
@ -745,7 +749,7 @@ impl Bank {
let collector_fees = self.collector_fees.load(Ordering::Relaxed) as u64; let collector_fees = self.collector_fees.load(Ordering::Relaxed) as u64;
if collector_fees != 0 { if collector_fees != 0 {
let (unburned, burned) = self.fee_calculator.burn(collector_fees); let (unburned, burned) = self.fee_rate_governor.burn(collector_fees);
// burn a portion of fees // burn a portion of fees
self.deposit(&self.collector_id, unburned); self.deposit(&self.collector_id, unburned);
self.capitalization.fetch_sub(burned, Ordering::Relaxed); self.capitalization.fetch_sub(burned, Ordering::Relaxed);
@ -811,7 +815,8 @@ impl Bank {
fn process_genesis_config(&mut self, genesis_config: &GenesisConfig) { fn process_genesis_config(&mut self, genesis_config: &GenesisConfig) {
// Bootstrap validator collects fees until `new_from_parent` is called. // Bootstrap validator collects fees until `new_from_parent` is called.
self.fee_calculator = genesis_config.fee_calculator.clone(); self.fee_rate_governor = genesis_config.fee_rate_governor.clone();
self.fee_calculator = self.fee_rate_governor.create_fee_calculator();
self.update_fees(); self.update_fees();
for (pubkey, account) in genesis_config.accounts.iter() { for (pubkey, account) in genesis_config.accounts.iter() {
@ -905,6 +910,10 @@ impl Bank {
blockhash_queue.get_fee_calculator(hash).cloned() blockhash_queue.get_fee_calculator(hash).cloned()
} }
pub fn get_fee_rate_governor(&self) -> &FeeRateGovernor {
&self.fee_rate_governor
}
pub fn confirmed_last_blockhash(&self) -> (Hash, FeeCalculator) { pub fn confirmed_last_blockhash(&self) -> (Hash, FeeCalculator) {
const NUM_BLOCKHASH_CONFIRMATIONS: usize = 3; const NUM_BLOCKHASH_CONFIRMATIONS: usize = 3;
@ -3290,7 +3299,7 @@ mod tests {
#[test] #[test]
fn test_detect_failed_duplicate_transactions() { fn test_detect_failed_duplicate_transactions() {
let (mut genesis_config, mint_keypair) = create_genesis_config(2); let (mut genesis_config, mint_keypair) = create_genesis_config(2);
genesis_config.fee_calculator.lamports_per_signature = 1; genesis_config.fee_rate_governor = FeeRateGovernor::new(1, 0);
let bank = Bank::new(&genesis_config); let bank = Bank::new(&genesis_config);
let dest = Keypair::new(); let dest = Keypair::new();
@ -3450,11 +3459,14 @@ mod tests {
mint_keypair, mint_keypair,
.. ..
} = create_genesis_config_with_leader(mint, &leader, 3); } = create_genesis_config_with_leader(mint, &leader, 3);
genesis_config.fee_calculator.lamports_per_signature = 4; // something divisible by 2 genesis_config.fee_rate_governor = FeeRateGovernor::new(4, 0); // something divisible by 2
let expected_fee_paid = genesis_config.fee_calculator.lamports_per_signature; let expected_fee_paid = genesis_config
.fee_rate_governor
.create_fee_calculator()
.lamports_per_signature;
let (expected_fee_collected, expected_fee_burned) = let (expected_fee_collected, expected_fee_burned) =
genesis_config.fee_calculator.burn(expected_fee_paid); genesis_config.fee_rate_governor.burn(expected_fee_paid);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
@ -3521,8 +3533,10 @@ mod tests {
mint_keypair, mint_keypair,
.. ..
} = create_genesis_config_with_leader(1_000_000, &leader, 3); } = create_genesis_config_with_leader(1_000_000, &leader, 3);
genesis_config.fee_calculator.target_lamports_per_signature = 1000; genesis_config
genesis_config.fee_calculator.target_signatures_per_slot = 1; .fee_rate_governor
.target_lamports_per_signature = 1000;
genesis_config.fee_rate_governor.target_signatures_per_slot = 1;
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
goto_end_of_slot(&mut bank); goto_end_of_slot(&mut bank);
@ -3571,7 +3585,7 @@ mod tests {
mint_keypair, mint_keypair,
.. ..
} = create_genesis_config_with_leader(100, &leader, 3); } = create_genesis_config_with_leader(100, &leader, 3);
genesis_config.fee_calculator.lamports_per_signature = 2; genesis_config.fee_rate_governor = FeeRateGovernor::new(2, 0);
let bank = Bank::new(&genesis_config); let bank = Bank::new(&genesis_config);
let key = Keypair::new(); let key = Keypair::new();
@ -3598,7 +3612,7 @@ mod tests {
bank.get_balance(&leader), bank.get_balance(&leader),
initial_balance initial_balance
+ bank + bank
.fee_calculator .fee_rate_governor
.burn(bank.fee_calculator.lamports_per_signature * 2) .burn(bank.fee_calculator.lamports_per_signature * 2)
.0 .0
); );
@ -4548,15 +4562,20 @@ mod tests {
} }
#[test] #[test]
fn test_bank_inherit_fee_calculator() { fn test_bank_inherit_fee_rate_governor() {
let (mut genesis_config, _mint_keypair) = create_genesis_config(500); let (mut genesis_config, _mint_keypair) = create_genesis_config(500);
genesis_config.fee_calculator.target_lamports_per_signature = 123; genesis_config
.fee_rate_governor
.target_lamports_per_signature = 123;
let bank0 = Arc::new(Bank::new(&genesis_config)); let bank0 = Arc::new(Bank::new(&genesis_config));
let bank1 = Arc::new(new_from_parent(&bank0)); let bank1 = Arc::new(new_from_parent(&bank0));
assert_eq!( assert_eq!(
bank0.fee_calculator.target_lamports_per_signature / 2, bank0.fee_rate_governor.target_lamports_per_signature / 2,
bank1.fee_calculator.lamports_per_signature bank1
.fee_rate_governor
.create_fee_calculator()
.lamports_per_signature
); );
} }
@ -4659,7 +4678,7 @@ mod tests {
#[test] #[test]
fn test_bank_fees_account() { fn test_bank_fees_account() {
let (mut genesis_config, _) = create_genesis_config(500); let (mut genesis_config, _) = create_genesis_config(500);
genesis_config.fee_calculator.lamports_per_signature = 12345; genesis_config.fee_rate_governor = FeeRateGovernor::new(12345, 0);
let bank = Arc::new(Bank::new(&genesis_config)); let bank = Arc::new(Bank::new(&genesis_config));
let fees_account = bank.get_account(&sysvar::fees::id()).unwrap(); let fees_account = bank.get_account(&sysvar::fees::id()).unwrap();
@ -5443,8 +5462,8 @@ mod tests {
#[test] #[test]
fn test_pre_post_transaction_balances() { fn test_pre_post_transaction_balances() {
let (mut genesis_config, _mint_keypair) = create_genesis_config(500); let (mut genesis_config, _mint_keypair) = create_genesis_config(500);
let fee_calculator = FeeCalculator::new(1, 0); let fee_rate_governor = FeeRateGovernor::new(1, 0);
genesis_config.fee_calculator = fee_calculator; genesis_config.fee_rate_governor = fee_rate_governor;
let parent = Arc::new(Bank::new(&genesis_config)); let parent = Arc::new(Bank::new(&genesis_config));
let bank0 = Arc::new(new_from_parent(&parent)); let bank0 = Arc::new(new_from_parent(&parent));

View File

@ -3,7 +3,7 @@ use solana_sdk::{
account::Account, account::Account,
client::{AsyncClient, Client, SyncClient}, client::{AsyncClient, Client, SyncClient},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash, hash::Hash,
instruction::Instruction, instruction::Instruction,
message::Message, message::Message,
@ -137,6 +137,10 @@ impl SyncClient for BankClient {
Ok(self.bank.last_blockhash_with_fee_calculator()) Ok(self.bank.last_blockhash_with_fee_calculator())
} }
fn get_fee_rate_governor(&self) -> Result<FeeRateGovernor> {
Ok(self.bank.get_fee_rate_governor().clone())
}
fn get_signature_status( fn get_signature_status(
&self, &self,
signature: &Signature, signature: &Signature,

View File

@ -1,6 +1,6 @@
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
fee_calculator::FeeCalculator, fee_calculator::FeeRateGovernor,
genesis_config::GenesisConfig, genesis_config::GenesisConfig,
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
@ -140,11 +140,11 @@ pub fn create_genesis_config_with_leader_ex(
solana_stake_program!(), solana_stake_program!(),
]; ];
let fee_calculator = FeeCalculator::new(0, 0); // most tests can't handle transaction fees let fee_rate_governor = FeeRateGovernor::new(0, 0); // most tests can't handle transaction fees
let mut genesis_config = GenesisConfig { let mut genesis_config = GenesisConfig {
accounts, accounts,
native_instruction_processors, native_instruction_processors,
fee_calculator, fee_rate_governor,
rent, rent,
..GenesisConfig::default() ..GenesisConfig::default()
}; };

View File

@ -11,7 +11,7 @@ use crate::{
account::Account, account::Account,
clock::Slot, clock::Slot,
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator, fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash, hash::Hash,
instruction::Instruction, instruction::Instruction,
message::Message, message::Message,
@ -72,6 +72,9 @@ pub trait SyncClient {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> Result<(Hash, FeeCalculator)>; ) -> Result<(Hash, FeeCalculator)>;
/// Get recent fee rate governor
fn get_fee_rate_governor(&self) -> Result<FeeRateGovernor>;
/// Get signature status. /// Get signature status.
fn get_signature_status( fn get_signature_status(
&self, &self,

View File

@ -8,6 +8,35 @@ pub struct FeeCalculator {
// The current cost of a signature This amount may increase/decrease over time based on // The current cost of a signature This amount may increase/decrease over time based on
// cluster processing load. // cluster processing load.
pub lamports_per_signature: u64, pub lamports_per_signature: u64,
}
impl Default for FeeCalculator {
fn default() -> Self {
Self {
lamports_per_signature: 0,
}
}
}
impl FeeCalculator {
pub fn new(lamports_per_signature: u64) -> Self {
Self {
lamports_per_signature,
}
}
pub fn calculate_fee(&self, message: &Message) -> u64 {
self.lamports_per_signature * u64::from(message.header.num_required_signatures)
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct FeeRateGovernor {
// The current cost of a signature This amount may increase/decrease over time based on
// cluster processing load.
#[serde(skip)]
lamports_per_signature: u64,
// The target cost of a signature when the cluster is operating around target_signatures_per_slot // The target cost of a signature when the cluster is operating around target_signatures_per_slot
// signatures // signatures
@ -16,7 +45,7 @@ pub struct FeeCalculator {
// Used to estimate the desired processing capacity of the cluster. As the signatures for // Used to estimate the desired processing capacity of the cluster. As the signatures for
// recent slots are fewer/greater than this value, lamports_per_signature will decrease/increase // recent slots are fewer/greater than this value, lamports_per_signature will decrease/increase
// for the next slot. A value of 0 disables lamports_per_signature fee adjustments // for the next slot. A value of 0 disables lamports_per_signature fee adjustments
pub target_signatures_per_slot: usize, pub target_signatures_per_slot: u64,
pub min_lamports_per_signature: u64, pub min_lamports_per_signature: u64,
pub max_lamports_per_signature: u64, pub max_lamports_per_signature: u64,
@ -26,15 +55,15 @@ pub struct FeeCalculator {
} }
pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 10_000; pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 10_000;
pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: usize = pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: u64 =
50_000 * DEFAULT_TICKS_PER_SLOT as usize / DEFAULT_TICKS_PER_SECOND as usize; 50_000 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND;
// Percentage of tx fees to burn // Percentage of tx fees to burn
pub const DEFAULT_BURN_PERCENT: u8 = 50; pub const DEFAULT_BURN_PERCENT: u8 = 50;
impl Default for FeeCalculator { impl Default for FeeRateGovernor {
fn default() -> Self { fn default() -> Self {
FeeCalculator { Self {
lamports_per_signature: 0, lamports_per_signature: 0,
target_lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, target_lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE,
target_signatures_per_slot: DEFAULT_TARGET_SIGNATURES_PER_SLOT, target_signatures_per_slot: DEFAULT_TARGET_SIGNATURES_PER_SLOT,
@ -45,23 +74,23 @@ impl Default for FeeCalculator {
} }
} }
impl FeeCalculator { impl FeeRateGovernor {
pub fn new(target_lamports_per_signature: u64, target_signatures_per_slot: usize) -> Self { pub fn new(target_lamports_per_signature: u64, target_signatures_per_slot: u64) -> Self {
let base_fee_calculator = Self { let base_fee_rate_governor = Self {
target_lamports_per_signature, target_lamports_per_signature,
lamports_per_signature: target_lamports_per_signature, lamports_per_signature: target_lamports_per_signature,
target_signatures_per_slot, target_signatures_per_slot,
..FeeCalculator::default() ..FeeRateGovernor::default()
}; };
Self::new_derived(&base_fee_calculator, 0) Self::new_derived(&base_fee_rate_governor, 0)
} }
pub fn new_derived( pub fn new_derived(
base_fee_calculator: &FeeCalculator, base_fee_rate_governor: &FeeRateGovernor,
latest_signatures_per_slot: usize, latest_signatures_per_slot: u64,
) -> Self { ) -> Self {
let mut me = base_fee_calculator.clone(); let mut me = base_fee_rate_governor.clone();
if me.target_signatures_per_slot > 0 { if me.target_signatures_per_slot > 0 {
// lamports_per_signature can range from 50% to 1000% of // lamports_per_signature can range from 50% to 1000% of
@ -74,7 +103,7 @@ impl FeeCalculator {
me.max_lamports_per_signature me.max_lamports_per_signature
.min(me.min_lamports_per_signature.max( .min(me.min_lamports_per_signature.max(
me.target_lamports_per_signature me.target_lamports_per_signature
* std::cmp::min(latest_signatures_per_slot, std::u32::MAX as usize) * std::cmp::min(latest_signatures_per_slot, std::u32::MAX as u64)
as u64 as u64
/ me.target_signatures_per_slot as u64, / me.target_signatures_per_slot as u64,
)); ));
@ -85,7 +114,7 @@ impl FeeCalculator {
); );
let gap = desired_lamports_per_signature as i64 let gap = desired_lamports_per_signature as i64
- base_fee_calculator.lamports_per_signature as i64; - base_fee_rate_governor.lamports_per_signature as i64;
if gap == 0 { if gap == 0 {
me.lamports_per_signature = desired_lamports_per_signature; me.lamports_per_signature = desired_lamports_per_signature;
@ -104,11 +133,12 @@ impl FeeCalculator {
me.lamports_per_signature = me.lamports_per_signature =
me.max_lamports_per_signature me.max_lamports_per_signature
.min(me.min_lamports_per_signature.max( .min(me.min_lamports_per_signature.max(
(base_fee_calculator.lamports_per_signature as i64 + gap_adjust) as u64, (base_fee_rate_governor.lamports_per_signature as i64 + gap_adjust)
as u64,
)); ));
} }
} else { } else {
me.lamports_per_signature = base_fee_calculator.target_lamports_per_signature; me.lamports_per_signature = base_fee_rate_governor.target_lamports_per_signature;
me.min_lamports_per_signature = me.target_lamports_per_signature; me.min_lamports_per_signature = me.target_lamports_per_signature;
me.max_lamports_per_signature = me.target_lamports_per_signature; me.max_lamports_per_signature = me.target_lamports_per_signature;
} }
@ -119,15 +149,18 @@ impl FeeCalculator {
me me
} }
pub fn calculate_fee(&self, message: &Message) -> u64 {
self.lamports_per_signature * u64::from(message.header.num_required_signatures)
}
/// calculate unburned fee from a fee total, returns (unburned, burned) /// calculate unburned fee from a fee total, returns (unburned, burned)
pub fn burn(&self, fees: u64) -> (u64, u64) { pub fn burn(&self, fees: u64) -> (u64, u64) {
let burned = fees * u64::from(self.burn_percent) / 100; let burned = fees * u64::from(self.burn_percent) / 100;
(fees - burned, burned) (fees - burned, burned)
} }
/// create a FeeCalculator based on current cluster signature throughput
pub fn create_fee_calculator(&self) -> FeeCalculator {
FeeCalculator {
lamports_per_signature: self.lamports_per_signature,
}
}
} }
#[cfg(test)] #[cfg(test)]
@ -136,15 +169,15 @@ mod tests {
use crate::{pubkey::Pubkey, system_instruction}; use crate::{pubkey::Pubkey, system_instruction};
#[test] #[test]
fn test_fee_calculator_burn() { fn test_fee_rate_governor_burn() {
let mut fee_calculator = FeeCalculator::default(); let mut fee_rate_governor = FeeRateGovernor::default();
assert_eq!(fee_calculator.burn(2), (1, 1)); assert_eq!(fee_rate_governor.burn(2), (1, 1));
fee_calculator.burn_percent = 0; fee_rate_governor.burn_percent = 0;
assert_eq!(fee_calculator.burn(2), (2, 0)); assert_eq!(fee_rate_governor.burn(2), (2, 0));
fee_calculator.burn_percent = 100; fee_rate_governor.burn_percent = 100;
assert_eq!(fee_calculator.burn(2), (0, 2)); assert_eq!(fee_rate_governor.burn(2), (0, 2));
} }
#[test] #[test]
@ -154,27 +187,27 @@ mod tests {
assert_eq!(FeeCalculator::default().calculate_fee(&message), 0); assert_eq!(FeeCalculator::default().calculate_fee(&message), 0);
// No signature, no fee. // No signature, no fee.
assert_eq!(FeeCalculator::new(1, 0).calculate_fee(&message), 0); assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 0);
// One signature, a fee. // One signature, a fee.
let pubkey0 = Pubkey::new(&[0; 32]); let pubkey0 = Pubkey::new(&[0; 32]);
let pubkey1 = Pubkey::new(&[1; 32]); let pubkey1 = Pubkey::new(&[1; 32]);
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1); let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
let message = Message::new(vec![ix0]); let message = Message::new(vec![ix0]);
assert_eq!(FeeCalculator::new(2, 0).calculate_fee(&message), 2); assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 2);
// Two signatures, double the fee. // Two signatures, double the fee.
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1); let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
let ix1 = system_instruction::transfer(&pubkey1, &pubkey0, 1); let ix1 = system_instruction::transfer(&pubkey1, &pubkey0, 1);
let message = Message::new(vec![ix0, ix1]); let message = Message::new(vec![ix0, ix1]);
assert_eq!(FeeCalculator::new(2, 0).calculate_fee(&message), 4); assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 4);
} }
#[test] #[test]
fn test_fee_calculator_derived_default() { fn test_fee_rate_governor_derived_default() {
solana_logger::setup(); solana_logger::setup();
let f0 = FeeCalculator::default(); let f0 = FeeRateGovernor::default();
assert_eq!( assert_eq!(
f0.target_signatures_per_slot, f0.target_signatures_per_slot,
DEFAULT_TARGET_SIGNATURES_PER_SLOT DEFAULT_TARGET_SIGNATURES_PER_SLOT
@ -185,7 +218,7 @@ mod tests {
); );
assert_eq!(f0.lamports_per_signature, 0); assert_eq!(f0.lamports_per_signature, 0);
let f1 = FeeCalculator::new_derived(&f0, DEFAULT_TARGET_SIGNATURES_PER_SLOT); let f1 = FeeRateGovernor::new_derived(&f0, DEFAULT_TARGET_SIGNATURES_PER_SLOT);
assert_eq!( assert_eq!(
f1.target_signatures_per_slot, f1.target_signatures_per_slot,
DEFAULT_TARGET_SIGNATURES_PER_SLOT DEFAULT_TARGET_SIGNATURES_PER_SLOT
@ -201,20 +234,20 @@ mod tests {
} }
#[test] #[test]
fn test_fee_calculator_derived_adjust() { fn test_fee_rate_governor_derived_adjust() {
solana_logger::setup(); solana_logger::setup();
let mut f = FeeCalculator::default(); let mut f = FeeRateGovernor::default();
f.target_lamports_per_signature = 100; f.target_lamports_per_signature = 100;
f.target_signatures_per_slot = 100; f.target_signatures_per_slot = 100;
f = FeeCalculator::new_derived(&f, 0); f = FeeRateGovernor::new_derived(&f, 0);
// Ramp fees up // Ramp fees up
let mut count = 0; let mut count = 0;
loop { loop {
let last_lamports_per_signature = f.lamports_per_signature; let last_lamports_per_signature = f.lamports_per_signature;
f = FeeCalculator::new_derived(&f, std::usize::MAX); f = FeeRateGovernor::new_derived(&f, std::u64::MAX);
info!("[up] f.lamports_per_signature={}", f.lamports_per_signature); info!("[up] f.lamports_per_signature={}", f.lamports_per_signature);
// some maximum target reached // some maximum target reached
@ -230,7 +263,7 @@ mod tests {
let mut count = 0; let mut count = 0;
loop { loop {
let last_lamports_per_signature = f.lamports_per_signature; let last_lamports_per_signature = f.lamports_per_signature;
f = FeeCalculator::new_derived(&f, 0); f = FeeRateGovernor::new_derived(&f, 0);
info!( info!(
"[down] f.lamports_per_signature={}", "[down] f.lamports_per_signature={}",
@ -250,7 +283,7 @@ mod tests {
// Arrive at target rate // Arrive at target rate
let mut count = 0; let mut count = 0;
while f.lamports_per_signature != f.target_lamports_per_signature { while f.lamports_per_signature != f.target_lamports_per_signature {
f = FeeCalculator::new_derived(&f, f.target_signatures_per_slot); f = FeeRateGovernor::new_derived(&f, f.target_signatures_per_slot);
info!( info!(
"[target] f.lamports_per_signature={}", "[target] f.lamports_per_signature={}",
f.lamports_per_signature f.lamports_per_signature

View File

@ -4,7 +4,7 @@ use crate::{
account::Account, account::Account,
clock::{UnixTimestamp, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT}, clock::{UnixTimestamp, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::FeeRateGovernor,
hash::{hash, Hash}, hash::{hash, Hash},
inflation::Inflation, inflation::Inflation,
native_token::lamports_to_sol, native_token::lamports_to_sol,
@ -49,7 +49,7 @@ pub struct GenesisConfig {
/// network speed configuration /// network speed configuration
pub poh_config: PohConfig, pub poh_config: PohConfig,
/// transaction fee config /// transaction fee config
pub fee_calculator: FeeCalculator, pub fee_rate_governor: FeeRateGovernor,
/// rent config /// rent config
pub rent: Rent, pub rent: Rent,
/// inflation config /// inflation config
@ -89,7 +89,7 @@ impl Default for GenesisConfig {
slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT, slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT,
poh_config: PohConfig::default(), poh_config: PohConfig::default(),
inflation: Inflation::default(), inflation: Inflation::default(),
fee_calculator: FeeCalculator::default(), fee_rate_governor: FeeRateGovernor::default(),
rent: Rent::default(), rent: Rent::default(),
epoch_schedule: EpochSchedule::default(), epoch_schedule: EpochSchedule::default(),
operating_mode: OperatingMode::Development, operating_mode: OperatingMode::Development,
@ -182,17 +182,17 @@ impl fmt::Display for GenesisConfig {
write!( write!(
f, f,
"\ "\
Creation time: {}\n\ Creation time: {}\n\
Operating mode: {:?}\n\ Operating mode: {:?}\n\
Genesis hash: {}\n\ Genesis hash: {}\n\
Shred version: {}\n\ Shred version: {}\n\
Hashes per tick: {:?}\n\ Hashes per tick: {:?}\n\
Slots per epoch: {}\n\ Slots per epoch: {}\n\
Warmup epochs: {}abled\n\ Warmup epochs: {}abled\n\
{:?}\n\ {:?}\n\
{:?}\n\ {:?}\n\
Capitalization: {} SOL in {} accounts\n\ Capitalization: {} SOL in {} accounts\n\
", ",
Utc.timestamp(self.creation_time, 0).to_rfc3339(), Utc.timestamp(self.creation_time, 0).to_rfc3339(),
self.operating_mode, self.operating_mode,
self.hash(), self.hash(),
@ -205,7 +205,7 @@ impl fmt::Display for GenesisConfig {
"dis" "dis"
}, },
self.rent, self.rent,
self.fee_calculator, self.fee_rate_governor,
lamports_to_sol( lamports_to_sol(
self.accounts self.accounts
.iter() .iter()