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

Commit 1ffd6b4

Browse files
authored
Add program and runtime support for Durable Transaction Nonces (#6845)
* Rework transaction processing result forwarding Durable nonce prereq * Add Durable Nonce program API * Add runtime changes for Durable Nonce program * Register Durable Nonce program * Concise comments and bad math * Fix c/p error * Add rent sysvar to withdraw ix * Remove rent exempt required balance from Meta struct * Use the helper
1 parent 6469606 commit 1ffd6b4

18 files changed

Lines changed: 1833 additions & 144 deletions

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/banking_stage.rs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ use solana_ledger::{
2020
use solana_measure::measure::Measure;
2121
use solana_metrics::{inc_new_counter_debug, inc_new_counter_info, inc_new_counter_warn};
2222
use solana_perf::{cuda_runtime::PinnedVec, perf_libs};
23-
use solana_runtime::{accounts_db::ErrorCounters, bank::Bank, transaction_batch::TransactionBatch};
23+
use solana_runtime::{
24+
accounts_db::ErrorCounters,
25+
bank::{Bank, TransactionProcessResult},
26+
transaction_batch::TransactionBatch,
27+
};
2428
use solana_sdk::{
2529
clock::{
2630
Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE,
@@ -443,15 +447,15 @@ impl BankingStage {
443447
fn record_transactions(
444448
bank_slot: Slot,
445449
txs: &[Transaction],
446-
results: &[transaction::Result<()>],
450+
results: &[TransactionProcessResult],
447451
poh: &Arc<Mutex<PohRecorder>>,
448452
) -> (Result<usize>, Vec<usize>) {
449453
let mut processed_generation = Measure::start("record::process_generation");
450454
let (processed_transactions, processed_transactions_indexes): (Vec<_>, Vec<_>) = results
451455
.iter()
452456
.zip(txs.iter())
453457
.enumerate()
454-
.filter_map(|(i, (r, x))| {
458+
.filter_map(|(i, ((r, _h), x))| {
455459
if Bank::can_commit(r) {
456460
Some((x.clone(), i))
457461
} else {
@@ -678,13 +682,13 @@ impl BankingStage {
678682
// This function returns a vector containing index of all valid transactions. A valid
679683
// transaction has result Ok() as the value
680684
fn filter_valid_transaction_indexes(
681-
valid_txs: &[transaction::Result<()>],
685+
valid_txs: &[TransactionProcessResult],
682686
transaction_indexes: &[usize],
683687
) -> Vec<usize> {
684688
let valid_transactions = valid_txs
685689
.iter()
686690
.enumerate()
687-
.filter_map(|(index, x)| if x.is_ok() { Some(index) } else { None })
691+
.filter_map(|(index, (x, _h))| if x.is_ok() { Some(index) } else { None })
688692
.collect_vec();
689693

690694
valid_transactions
@@ -1022,6 +1026,7 @@ mod tests {
10221026
entry::{next_entry, Entry, EntrySlice},
10231027
get_tmp_ledger_path,
10241028
};
1029+
use solana_runtime::bank::HashAgeKind;
10251030
use solana_sdk::{
10261031
instruction::InstructionError,
10271032
signature::{Keypair, KeypairUtil},
@@ -1369,7 +1374,10 @@ mod tests {
13691374
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()),
13701375
];
13711376

1372-
let mut results = vec![Ok(()), Ok(())];
1377+
let mut results = vec![
1378+
(Ok(()), Some(HashAgeKind::Extant)),
1379+
(Ok(()), Some(HashAgeKind::Extant)),
1380+
];
13731381
let _ = BankingStage::record_transactions(
13741382
bank.slot(),
13751383
&transactions,
@@ -1380,10 +1388,13 @@ mod tests {
13801388
assert_eq!(entry.transactions.len(), transactions.len());
13811389

13821390
// InstructionErrors should still be recorded
1383-
results[0] = Err(TransactionError::InstructionError(
1384-
1,
1385-
InstructionError::new_result_with_negative_lamports(),
1386-
));
1391+
results[0] = (
1392+
Err(TransactionError::InstructionError(
1393+
1,
1394+
InstructionError::new_result_with_negative_lamports(),
1395+
)),
1396+
Some(HashAgeKind::Extant),
1397+
);
13871398
let (res, retryable) = BankingStage::record_transactions(
13881399
bank.slot(),
13891400
&transactions,
@@ -1396,7 +1407,7 @@ mod tests {
13961407
assert_eq!(entry.transactions.len(), transactions.len());
13971408

13981409
// Other TransactionErrors should not be recorded
1399-
results[0] = Err(TransactionError::AccountNotFound);
1410+
results[0] = (Err(TransactionError::AccountNotFound), None);
14001411
let (res, retryable) = BankingStage::record_transactions(
14011412
bank.slot(),
14021413
&transactions,
@@ -1559,12 +1570,12 @@ mod tests {
15591570
assert_eq!(
15601571
BankingStage::filter_valid_transaction_indexes(
15611572
&vec![
1562-
Err(TransactionError::BlockhashNotFound),
1563-
Err(TransactionError::BlockhashNotFound),
1564-
Ok(()),
1565-
Err(TransactionError::BlockhashNotFound),
1566-
Ok(()),
1567-
Ok(())
1573+
(Err(TransactionError::BlockhashNotFound), None),
1574+
(Err(TransactionError::BlockhashNotFound), None),
1575+
(Ok(()), Some(HashAgeKind::Extant)),
1576+
(Err(TransactionError::BlockhashNotFound), None),
1577+
(Ok(()), Some(HashAgeKind::Extant)),
1578+
(Ok(()), Some(HashAgeKind::Extant)),
15681579
],
15691580
&vec![2, 4, 5, 9, 11, 13]
15701581
),
@@ -1574,12 +1585,12 @@ mod tests {
15741585
assert_eq!(
15751586
BankingStage::filter_valid_transaction_indexes(
15761587
&vec![
1577-
Ok(()),
1578-
Err(TransactionError::BlockhashNotFound),
1579-
Err(TransactionError::BlockhashNotFound),
1580-
Ok(()),
1581-
Ok(()),
1582-
Ok(())
1588+
(Ok(()), Some(HashAgeKind::Extant)),
1589+
(Err(TransactionError::BlockhashNotFound), None),
1590+
(Err(TransactionError::BlockhashNotFound), None),
1591+
(Ok(()), Some(HashAgeKind::Extant)),
1592+
(Ok(()), Some(HashAgeKind::Extant)),
1593+
(Ok(()), Some(HashAgeKind::Extant)),
15831594
],
15841595
&vec![1, 6, 7, 9, 31, 43]
15851596
),

core/src/transaction_status_service.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::result::{Error, Result};
22
use crossbeam_channel::{Receiver, RecvTimeoutError};
33
use solana_client::rpc_request::RpcTransactionStatus;
44
use solana_ledger::{blocktree::Blocktree, blocktree_processor::TransactionStatusBatch};
5-
use solana_runtime::bank::Bank;
5+
use solana_runtime::bank::{Bank, HashAgeKind};
66
use std::{
77
sync::{
88
atomic::{AtomicBool, Ordering},
@@ -56,10 +56,15 @@ impl TransactionStatusService {
5656
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
5757

5858
let slot = bank.slot();
59-
for (transaction, status) in transactions.iter().zip(statuses) {
59+
for (transaction, (status, hash_age_kind)) in transactions.iter().zip(statuses) {
6060
if Bank::can_commit(&status) && !transaction.signatures.is_empty() {
61+
let fee_hash = if let Some(HashAgeKind::DurableNonce) = hash_age_kind {
62+
bank.last_blockhash()
63+
} else {
64+
transaction.message().recent_blockhash
65+
};
6166
let fee_calculator = bank
62-
.get_fee_calculator(&transaction.message().recent_blockhash)
67+
.get_fee_calculator(&fee_hash)
6368
.expect("FeeCalculator must exist");
6469
let fee = fee_calculator.calculate_fee(transaction.message());
6570
blocktree

genesis-programs/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use solana_sdk::{
22
clock::Epoch, genesis_config::OperatingMode, inflation::Inflation,
3-
move_loader::solana_move_loader_program, pubkey::Pubkey, system_program::solana_system_program,
3+
move_loader::solana_move_loader_program, nonce_program::solana_nonce_program, pubkey::Pubkey,
4+
system_program::solana_system_program,
45
};
56

67
#[macro_use]
@@ -58,6 +59,7 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
5859
solana_system_program(),
5960
solana_bpf_loader_program!(),
6061
solana_config_program!(),
62+
solana_nonce_program(),
6163
solana_stake_program!(),
6264
solana_storage_program!(),
6365
solana_vest_program!(),
@@ -73,8 +75,9 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
7375
}
7476
OperatingMode::SoftLaunch => {
7577
if epoch == 0 {
76-
// Voting, Staking and System Program only at epoch 0
78+
// Nonce, Voting, Staking and System Program only at epoch 0
7779
Some(vec![
80+
solana_nonce_program(),
7881
solana_stake_program!(),
7982
solana_system_program(),
8083
solana_vote_program!(),
@@ -124,6 +127,7 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch
124127
#[cfg(test)]
125128
mod tests {
126129
use super::*;
130+
use solana_sdk::nonce_program::solana_nonce_program;
127131
use std::collections::HashSet;
128132

129133
#[test]
@@ -146,7 +150,7 @@ mod tests {
146150
fn test_development_programs() {
147151
assert_eq!(
148152
get_programs(OperatingMode::Development, 0).unwrap().len(),
149-
10
153+
11
150154
);
151155
assert_eq!(get_programs(OperatingMode::Development, 1), None);
152156
}
@@ -169,6 +173,7 @@ mod tests {
169173
assert_eq!(
170174
get_programs(OperatingMode::SoftLaunch, 0),
171175
Some(vec![
176+
solana_nonce_program(),
172177
solana_stake_program!(),
173178
solana_system_program(),
174179
solana_vote_program!(),

ledger/src/blocktree_processor.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rayon::{prelude::*, ThreadPool};
1414
use solana_metrics::{datapoint, datapoint_error, inc_new_counter_debug};
1515
use solana_rayon_threadlimit::get_thread_count;
1616
use solana_runtime::{
17-
bank::{Bank, TransactionResults},
17+
bank::{Bank, TransactionProcessResult, TransactionResults},
1818
transaction_batch::TransactionBatch,
1919
};
2020
use solana_sdk::{
@@ -550,14 +550,14 @@ fn process_pending_slots(
550550
pub struct TransactionStatusBatch {
551551
pub bank: Arc<Bank>,
552552
pub transactions: Vec<Transaction>,
553-
pub statuses: Vec<Result<()>>,
553+
pub statuses: Vec<TransactionProcessResult>,
554554
}
555555
pub type TransactionStatusSender = Sender<TransactionStatusBatch>;
556556

557557
pub fn send_transaction_status_batch(
558558
bank: Arc<Bank>,
559559
transactions: &[Transaction],
560-
statuses: Vec<Result<()>>,
560+
statuses: Vec<TransactionProcessResult>,
561561
transaction_status_sender: TransactionStatusSender,
562562
) {
563563
let slot = bank.slot();

0 commit comments

Comments
 (0)