Demote write locks on transaction program ids (#19593)

* Add feature

* Demote write lock on program ids

* Fixup bpf tests

* Update MappedMessage::is_writable

* Comma nit

* Review comments
This commit is contained in:
Tyera Eulberg
2021-09-03 21:05:30 -06:00
committed by GitHub
parent 7578db7ee3
commit decec3cd8b
20 changed files with 297 additions and 177 deletions

View File

@ -1049,6 +1049,7 @@ impl BankingStage {
libsecp256k1_fail_on_bad_count: bool,
cost_tracker: &Arc<RwLock<CostTracker>>,
banking_stage_stats: &BankingStageStats,
demote_program_write_locks: bool,
) -> (Vec<SanitizedTransaction>, Vec<usize>, Vec<usize>) {
let mut retryable_transaction_packet_indexes: Vec<usize> = vec![];
@ -1082,7 +1083,8 @@ impl BankingStage {
verified_transactions_with_packet_indexes
.into_iter()
.filter_map(|(tx, tx_index)| {
let result = cost_tracker_readonly.would_transaction_fit(&tx);
let result = cost_tracker_readonly
.would_transaction_fit(&tx, demote_program_write_locks);
if result.is_err() {
debug!("transaction {:?} would exceed limit: {:?}", tx, result);
retryable_transaction_packet_indexes.push(tx_index);
@ -1165,6 +1167,7 @@ impl BankingStage {
bank.libsecp256k1_fail_on_bad_count(),
cost_tracker,
banking_stage_stats,
bank.demote_program_write_locks(),
);
packet_conversion_time.stop();
inc_new_counter_info!("banking_stage-packet_conversion", 1);
@ -1201,7 +1204,10 @@ impl BankingStage {
let mut cost_tracking_time = Measure::start("cost_tracking_time");
transactions.iter().enumerate().for_each(|(index, tx)| {
if unprocessed_tx_indexes.iter().all(|&i| i != index) {
cost_tracker.write().unwrap().add_transaction_cost(tx);
cost_tracker
.write()
.unwrap()
.add_transaction_cost(tx, bank.demote_program_write_locks());
}
});
cost_tracking_time.stop();
@ -1268,6 +1274,7 @@ impl BankingStage {
bank.libsecp256k1_fail_on_bad_count(),
cost_tracker,
banking_stage_stats,
bank.demote_program_write_locks(),
);
unprocessed_packet_conversion_time.stop();

View File

@ -113,7 +113,11 @@ impl CostModel {
);
}
pub fn calculate_cost(&mut self, transaction: &SanitizedTransaction) -> &TransactionCost {
pub fn calculate_cost(
&mut self,
transaction: &SanitizedTransaction,
demote_program_write_locks: bool,
) -> &TransactionCost {
self.transaction_cost.reset();
// calculate transaction exeution cost
@ -122,7 +126,7 @@ impl CostModel {
// calculate account access cost
let message = transaction.message();
message.account_keys_iter().enumerate().for_each(|(i, k)| {
let is_writable = message.is_writable(i);
let is_writable = message.is_writable(i, demote_program_write_locks);
if is_writable {
self.transaction_cost.writable_accounts.push(*k);
@ -353,7 +357,7 @@ mod tests {
.unwrap();
let mut cost_model = CostModel::default();
let tx_cost = cost_model.calculate_cost(&tx);
let tx_cost = cost_model.calculate_cost(&tx, /*demote_program_write_locks=*/ true);
assert_eq!(2 + 2, tx_cost.writable_accounts.len());
assert_eq!(signer1.pubkey(), tx_cost.writable_accounts[0]);
assert_eq!(signer2.pubkey(), tx_cost.writable_accounts[1]);
@ -395,7 +399,7 @@ mod tests {
cost_model
.upsert_instruction_cost(&system_program::id(), expected_execution_cost)
.unwrap();
let tx_cost = cost_model.calculate_cost(&tx);
let tx_cost = cost_model.calculate_cost(&tx, /*demote_program_write_locks=*/ true);
assert_eq!(expected_account_cost, tx_cost.account_access_cost);
assert_eq!(expected_execution_cost, tx_cost.execution_cost);
assert_eq!(2, tx_cost.writable_accounts.len());
@ -465,7 +469,8 @@ mod tests {
} else {
thread::spawn(move || {
let mut cost_model = cost_model.write().unwrap();
let tx_cost = cost_model.calculate_cost(&tx);
let tx_cost = cost_model
.calculate_cost(&tx, /*demote_program_write_locks=*/ true);
assert_eq!(3, tx_cost.writable_accounts.len());
assert_eq!(expected_account_cost, tx_cost.account_access_cost);
})

View File

@ -46,18 +46,23 @@ impl CostTracker {
pub fn would_transaction_fit(
&self,
transaction: &SanitizedTransaction,
demote_program_write_locks: bool,
) -> Result<(), CostModelError> {
let mut cost_model = self.cost_model.write().unwrap();
let tx_cost = cost_model.calculate_cost(transaction);
let tx_cost = cost_model.calculate_cost(transaction, demote_program_write_locks);
self.would_fit(
&tx_cost.writable_accounts,
&(tx_cost.account_access_cost + tx_cost.execution_cost),
)
}
pub fn add_transaction_cost(&mut self, transaction: &SanitizedTransaction) {
pub fn add_transaction_cost(
&mut self,
transaction: &SanitizedTransaction,
demote_program_write_locks: bool,
) {
let mut cost_model = self.cost_model.write().unwrap();
let tx_cost = cost_model.calculate_cost(transaction);
let tx_cost = cost_model.calculate_cost(transaction, demote_program_write_locks);
let cost = tx_cost.account_access_cost + tx_cost.execution_cost;
for account_key in tx_cost.writable_accounts.iter() {
*self