From 8a64e1ddc3050add32311499cdb5a1c06c4c6501 Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Wed, 26 Jun 2019 10:13:21 -0700 Subject: [PATCH] add fee burning (#4818) --- core/src/rpc.rs | 1 + genesis/src/main.rs | 4 +- runtime/append_vec_serialize | Bin 0 -> 1048576 bytes runtime/src/bank.rs | 60 ++++++++++++---- runtime/src/genesis_utils.rs | 16 +++-- sdk/src/fee_calculator.rs | 128 +++++++++++++++++++++++++++-------- sdk/src/genesis_block.rs | 12 ++-- 7 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 runtime/append_vec_serialize diff --git a/core/src/rpc.rs b/core/src/rpc.rs index d4f60b54b8..a5504be051 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -806,6 +806,7 @@ mod tests { let expected = json!({ "jsonrpc": "2.0", "result": [ blockhash.to_string(), { + "burnPercent": 50, "lamportsPerSignature": 0, "maxLamportsPerSignature": 0, "minLamportsPerSignature": 0, diff --git a/genesis/src/main.rs b/genesis/src/main.rs index b07070d133..9435b1b375 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -316,7 +316,7 @@ fn main() -> Result<(), Box> { value_t_or_exit!(matches, "target_lamports_per_signature", u64); fee_calculator.target_signatures_per_slot = value_t_or_exit!(matches, "target_signatures_per_slot", usize); - builder = builder.fee_calculator(&FeeCalculator::new_derived(&fee_calculator, 0)); + builder = builder.fee_calculator(FeeCalculator::new_derived(&fee_calculator, 0)); let mut poh_config = PohConfig::default(); poh_config.target_tick_duration = @@ -345,7 +345,7 @@ fn main() -> Result<(), Box> { poh_config.hashes_per_tick = Some(value_t_or_exit!(matches, "hashes_per_tick", u64)); } } - builder = builder.poh_config(&poh_config); + builder = builder.poh_config(poh_config); if let Some(file) = matches.value_of("primordial_accounts_file") { builder = append_primordial_accounts(file, AccountFileFormat::Pubkey, builder)?; diff --git a/runtime/append_vec_serialize b/runtime/append_vec_serialize new file mode 100644 index 0000000000000000000000000000000000000000..9e0f96a2a253b173cb45b41868209a5d043e1437 GIT binary patch literal 1048576 zcmeIuF#!Mo0K%a4Pi+Wah(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ T0|pEjFkrxd0RsjM82APT0Pp|- literal 0 HcmV?d00001 diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 7363432452..5f1b4d720f 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -487,8 +487,10 @@ impl Bank { let mut hash = self.hash.write().unwrap(); if *hash == Hash::default() { let collector_fees = self.collector_fees.load(Ordering::Relaxed) as u64; + if collector_fees != 0 { - self.deposit(&self.collector_id, collector_fees); + // burn a portion of fees + self.deposit(&self.collector_id, self.fee_calculator.burn(collector_fees)); } // freeze is a one-way trip, idempotent *hash = self.hash_internal_state(); @@ -1723,28 +1725,44 @@ mod tests { #[test] fn test_bank_tx_fee() { + let arbitrary_transfer_amount = 42; + let mint = arbitrary_transfer_amount * 100; let leader = Pubkey::new_rand(); let GenesisBlockInfo { mut genesis_block, mint_keypair, .. - } = create_genesis_block_with_leader(100, &leader, 3); - genesis_block.fee_calculator.lamports_per_signature = 3; + } = create_genesis_block_with_leader(mint, &leader, 3); + genesis_block.fee_calculator.lamports_per_signature = 4; // something divisible by 2 + + let expected_fee_paid = genesis_block.fee_calculator.lamports_per_signature; + let expected_fee_collected = genesis_block.fee_calculator.burn(expected_fee_paid); + let mut bank = Bank::new(&genesis_block); let key = Keypair::new(); - let tx = - system_transaction::transfer(&mint_keypair, &key.pubkey(), 2, bank.last_blockhash()); + let tx = system_transaction::transfer( + &mint_keypair, + &key.pubkey(), + arbitrary_transfer_amount, + bank.last_blockhash(), + ); let initial_balance = bank.get_balance(&leader); assert_eq!(bank.process_transaction(&tx), Ok(())); - assert_eq!(bank.get_balance(&key.pubkey()), 2); - assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 5); + assert_eq!(bank.get_balance(&key.pubkey()), arbitrary_transfer_amount); + assert_eq!( + bank.get_balance(&mint_keypair.pubkey()), + mint - arbitrary_transfer_amount - expected_fee_paid + ); assert_eq!(bank.get_balance(&leader), initial_balance); goto_end_of_slot(&mut bank); assert_eq!(bank.signature_count(), 1); - assert_eq!(bank.get_balance(&leader), initial_balance + 3); // Leader collects fee after the bank is frozen + assert_eq!( + bank.get_balance(&leader), + initial_balance + expected_fee_collected + ); // Leader collects fee after the bank is frozen // Verify that an InstructionError collects fees, too let mut bank = Bank::new_from_parent(&Arc::new(bank), &leader, 1); @@ -1755,13 +1773,19 @@ mod tests { bank.process_transaction(&tx) .expect_err("instruction error"); - assert_eq!(bank.get_balance(&key.pubkey()), 2); // no change - assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 5 - 3); // mint_keypair still pays a fee + assert_eq!(bank.get_balance(&key.pubkey()), arbitrary_transfer_amount); // no change + assert_eq!( + bank.get_balance(&mint_keypair.pubkey()), + mint - arbitrary_transfer_amount - 2 * expected_fee_paid + ); // mint_keypair still pays a fee goto_end_of_slot(&mut bank); assert_eq!(bank.signature_count(), 1); // Profit! 2 transaction signatures processed at 3 lamports each - assert_eq!(bank.get_balance(&leader), initial_balance + 6); + assert_eq!( + bank.get_balance(&leader), + initial_balance + 2 * expected_fee_collected + ); } #[test] @@ -1840,11 +1864,17 @@ mod tests { InstructionError::new_result_with_negative_lamports(), )), ]; - let initial_balance = bank.get_balance(&leader); + let results = bank.filter_program_errors_and_collect_fee(&vec![tx1, tx2], &results); bank.freeze(); - assert_eq!(bank.get_balance(&leader), initial_balance + 2 + 2); + assert_eq!( + bank.get_balance(&leader), + initial_balance + + bank + .fee_calculator + .burn(bank.fee_calculator.lamports_per_signature * 2) + ); assert_eq!(results[0], Ok(())); assert_eq!(results[1], Ok(())); } @@ -2436,11 +2466,11 @@ mod tests { fn test_bank_inherit_fee_calculator() { let (mut genesis_block, _mint_keypair) = create_genesis_block(500); genesis_block.fee_calculator.target_lamports_per_signature = 123; - assert_eq!(genesis_block.fee_calculator.target_signatures_per_slot, 0); + let bank0 = Arc::new(Bank::new(&genesis_block)); let bank1 = Arc::new(new_from_parent(&bank0)); assert_eq!( - bank0.fee_calculator.target_lamports_per_signature, + bank0.fee_calculator.target_lamports_per_signature / 2, bank1.fee_calculator.lamports_per_signature ); } diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 5b9e67f71a..8af381ca5d 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -1,8 +1,11 @@ -use solana_sdk::account::Account; -use solana_sdk::genesis_block::{Builder, GenesisBlock}; -use solana_sdk::pubkey::Pubkey; -use solana_sdk::signature::{Keypair, KeypairUtil}; -use solana_sdk::system_program; +use solana_sdk::{ + account::Account, + fee_calculator::FeeCalculator, + genesis_block::{Builder, GenesisBlock}, + pubkey::Pubkey, + signature::{Keypair, KeypairUtil}, + system_program, +}; use solana_stake_api; use solana_vote_api::vote_state; @@ -67,7 +70,8 @@ pub fn create_genesis_block_with_leader( solana_bpf_loader_program!(), solana_vote_program!(), solana_stake_program!(), - ]); + ]) + .fee_calculator(FeeCalculator::new(0)); // most tests don't want fees builder = solana_stake_api::rewards_pools::genesis(builder); builder = solana_storage_api::rewards_pools::genesis(builder); diff --git a/sdk/src/fee_calculator.rs b/sdk/src/fee_calculator.rs index fd551fa02f..fc0d8635b8 100644 --- a/sdk/src/fee_calculator.rs +++ b/sdk/src/fee_calculator.rs @@ -1,7 +1,8 @@ use crate::message::Message; +use crate::timing::{DEFAULT_NUM_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}; use log::*; -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Default)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct FeeCalculator { // The current cost of a signature This amount may increase/decrease over time based on @@ -19,6 +20,28 @@ pub struct FeeCalculator { pub min_lamports_per_signature: u64, pub max_lamports_per_signature: u64, + + // What portion of collected fees are to be destroyed, percentage-wise + pub burn_percent: u8, +} + +/// TODO: determine good values for these +pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 42; +pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: usize = + 710_000 * DEFAULT_TICKS_PER_SLOT as usize / DEFAULT_NUM_TICKS_PER_SECOND as usize; +pub const DEFAULT_BURN_PERCENT: u8 = 50; + +impl Default for FeeCalculator { + fn default() -> Self { + FeeCalculator { + lamports_per_signature: 0, + target_lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, + target_signatures_per_slot: DEFAULT_TARGET_SIGNATURES_PER_SLOT, + min_lamports_per_signature: 0, + max_lamports_per_signature: 0, + burn_percent: DEFAULT_BURN_PERCENT, + } + } } impl FeeCalculator { @@ -26,6 +49,7 @@ impl FeeCalculator { let base_fee_calculator = Self { target_lamports_per_signature, lamports_per_signature: target_lamports_per_signature, + target_signatures_per_slot: 0, ..FeeCalculator::default() }; @@ -48,15 +72,14 @@ impl FeeCalculator { me.max_lamports_per_signature = me.target_lamports_per_signature * 10; // What the cluster should charge at `latest_signatures_per_slot` - let desired_lamports_per_signature = std::cmp::min( - me.max_lamports_per_signature, - std::cmp::max( - me.min_lamports_per_signature, - me.target_lamports_per_signature - * std::cmp::min(latest_signatures_per_slot, std::u32::MAX as usize) as u64 - / me.target_signatures_per_slot as u64, - ), - ); + let desired_lamports_per_signature = + me.max_lamports_per_signature + .min(me.min_lamports_per_signature.max( + me.target_lamports_per_signature + * std::cmp::min(latest_signatures_per_slot, std::u32::MAX as usize) + as u64 + / me.target_signatures_per_slot as u64, + )); trace!( "desired_lamports_per_signature: {}", @@ -82,13 +105,11 @@ impl FeeCalculator { gap_adjust ); - me.lamports_per_signature = std::cmp::min( - me.max_lamports_per_signature, - std::cmp::max( - me.min_lamports_per_signature, - (base_fee_calculator.lamports_per_signature as i64 + gap_adjust) as u64, - ), - ); + me.lamports_per_signature = + me.max_lamports_per_signature + .min(me.min_lamports_per_signature.max( + (base_fee_calculator.lamports_per_signature as i64 + gap_adjust) as u64, + )); } } else { me.lamports_per_signature = base_fee_calculator.target_lamports_per_signature; @@ -105,6 +126,11 @@ impl FeeCalculator { 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 + pub fn burn(&self, fees: u64) -> u64 { + fees * u64::from(100 - self.burn_percent) / 100 + } } #[cfg(test)] @@ -113,6 +139,19 @@ mod tests { use crate::pubkey::Pubkey; use crate::system_instruction; + #[test] + fn test_fee_calculator_burn() { + let mut fee_calculator = FeeCalculator::default(); + + assert_eq!(fee_calculator.burn(2), 1); + + fee_calculator.burn_percent = 0; + + assert_eq!(fee_calculator.burn(2), 2); + fee_calculator.burn_percent = 100; + assert_eq!(fee_calculator.burn(2), 0); + } + #[test] fn test_fee_calculator_calculate_fee() { // Default: no fee. @@ -140,18 +179,24 @@ mod tests { fn test_fee_calculator_derived_default() { solana_logger::setup(); - let mut f0 = FeeCalculator::default(); - assert_eq!(f0.target_signatures_per_slot, 0); - assert_eq!(f0.target_lamports_per_signature, 0); + let f0 = FeeCalculator::default(); + assert_eq!( + f0.target_signatures_per_slot, + DEFAULT_TARGET_SIGNATURES_PER_SLOT + ); + assert_eq!( + f0.target_lamports_per_signature, + DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE + ); assert_eq!(f0.lamports_per_signature, 0); - f0.target_lamports_per_signature = 42; - let f1 = FeeCalculator::new_derived(&f0, 4242); - assert_eq!(f1.target_signatures_per_slot, 0); + let f1 = FeeCalculator::new_derived(&f0, DEFAULT_TARGET_SIGNATURES_PER_SLOT); + assert_eq!( + f1.target_signatures_per_slot, + DEFAULT_TARGET_SIGNATURES_PER_SLOT + ); assert_eq!(f1.target_lamports_per_signature, 42); - assert_eq!(f1.lamports_per_signature, 42); - assert_eq!(f1.min_lamports_per_signature, 42); - assert_eq!(f1.max_lamports_per_signature, 42); + assert_eq!(f1.lamports_per_signature, 21); // min } #[test] @@ -164,27 +209,54 @@ mod tests { f = FeeCalculator::new_derived(&f, 0); // Ramp fees up - while f.lamports_per_signature < f.max_lamports_per_signature { + let mut count = 0; + loop { + let last_lamports_per_signature = f.lamports_per_signature; + f = FeeCalculator::new_derived(&f, std::usize::MAX); info!("[up] f.lamports_per_signature={}", f.lamports_per_signature); + + // some maximum target reached + if f.lamports_per_signature == last_lamports_per_signature { + break; + } + // shouldn't take more than 1000 steps to get to minimum + assert!(count < 1000); + count += 1; } // Ramp fees down - while f.lamports_per_signature > f.min_lamports_per_signature { + let mut count = 0; + loop { + let last_lamports_per_signature = f.lamports_per_signature; f = FeeCalculator::new_derived(&f, 0); + info!( "[down] f.lamports_per_signature={}", f.lamports_per_signature ); + + // some minimum target reached + if f.lamports_per_signature == last_lamports_per_signature { + break; + } + + // shouldn't take more than 1000 steps to get to minimum + assert!(count < 1000); + count += 1; } // Arrive at target rate + let mut count = 0; while f.lamports_per_signature != f.target_lamports_per_signature { f = FeeCalculator::new_derived(&f, f.target_signatures_per_slot); info!( "[target] f.lamports_per_signature={}", f.lamports_per_signature ); + // shouldn't take more than 100 steps to get to target + assert!(count < 100); + count += 1; } } } diff --git a/sdk/src/genesis_block.rs b/sdk/src/genesis_block.rs index 115c719ec8..783aafe826 100644 --- a/sdk/src/genesis_block.rs +++ b/sdk/src/genesis_block.rs @@ -130,16 +130,16 @@ impl Builder { self.genesis_block.ticks_per_slot = ticks_per_slot; self } - pub fn poh_config(mut self, poh_config: &PohConfig) -> Self { - self.genesis_block.poh_config = poh_config.clone(); + pub fn poh_config(mut self, poh_config: PohConfig) -> Self { + self.genesis_block.poh_config = poh_config; self } - pub fn fee_calculator(mut self, fee_calculator: &FeeCalculator) -> Self { - self.genesis_block.fee_calculator = fee_calculator.clone(); + pub fn fee_calculator(mut self, fee_calculator: FeeCalculator) -> Self { + self.genesis_block.fee_calculator = fee_calculator; self } - pub fn inflation(mut self, inflation: &Inflation) -> Self { - self.genesis_block.inflation = inflation.clone(); + pub fn inflation(mut self, inflation: Inflation) -> Self { + self.genesis_block.inflation = inflation; self } }