Extend getConfirmedBlock rpc to return account pre- and post-balances (#7543)
automerge
This commit is contained in:
parent
dcaf69a5d5
commit
6aaf742dfe
@ -32,9 +32,12 @@ pub struct RpcConfirmedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTransactionStatus {
|
pub struct RpcTransactionStatus {
|
||||||
pub status: Result<()>,
|
pub status: Result<()>,
|
||||||
pub fee: u64,
|
pub fee: u64,
|
||||||
|
pub pre_balances: Vec<u64>,
|
||||||
|
pub post_balances: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
@ -22,7 +22,7 @@ use solana_metrics::{inc_new_counter_debug, inc_new_counter_info, inc_new_counte
|
|||||||
use solana_perf::{cuda_runtime::PinnedVec, perf_libs};
|
use solana_perf::{cuda_runtime::PinnedVec, perf_libs};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
accounts_db::ErrorCounters,
|
accounts_db::ErrorCounters,
|
||||||
bank::{Bank, TransactionProcessResult},
|
bank::{Bank, TransactionBalancesSet, TransactionProcessResult},
|
||||||
transaction_batch::TransactionBatch,
|
transaction_batch::TransactionBatch,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -511,6 +511,11 @@ impl BankingStage {
|
|||||||
// TODO: Banking stage threads should be prioritized to complete faster then this queue
|
// TODO: Banking stage threads should be prioritized to complete faster then this queue
|
||||||
// expires.
|
// expires.
|
||||||
let txs = batch.transactions();
|
let txs = batch.transactions();
|
||||||
|
let pre_balances = if transaction_status_sender.is_some() {
|
||||||
|
bank.collect_balances(txs)
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
let (mut loaded_accounts, results, mut retryable_txs, tx_count, signature_count) =
|
let (mut loaded_accounts, results, mut retryable_txs, tx_count, signature_count) =
|
||||||
bank.load_and_execute_transactions(batch, MAX_PROCESSING_AGE);
|
bank.load_and_execute_transactions(batch, MAX_PROCESSING_AGE);
|
||||||
load_execute_time.stop();
|
load_execute_time.stop();
|
||||||
@ -541,11 +546,14 @@ impl BankingStage {
|
|||||||
signature_count,
|
signature_count,
|
||||||
)
|
)
|
||||||
.processing_results;
|
.processing_results;
|
||||||
|
|
||||||
if let Some(sender) = transaction_status_sender {
|
if let Some(sender) = transaction_status_sender {
|
||||||
|
let post_balances = bank.collect_balances(txs);
|
||||||
send_transaction_status_batch(
|
send_transaction_status_batch(
|
||||||
bank.clone(),
|
bank.clone(),
|
||||||
batch.transactions(),
|
batch.transactions(),
|
||||||
transaction_statuses,
|
transaction_statuses,
|
||||||
|
TransactionBalancesSet::new(pre_balances, post_balances),
|
||||||
sender,
|
sender,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,16 @@ impl TransactionStatusService {
|
|||||||
bank,
|
bank,
|
||||||
transactions,
|
transactions,
|
||||||
statuses,
|
statuses,
|
||||||
|
balances,
|
||||||
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
|
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
|
||||||
|
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
for (transaction, (status, hash_age_kind)) in transactions.iter().zip(statuses) {
|
for (((transaction, (status, hash_age_kind)), pre_balances), post_balances) in transactions
|
||||||
|
.iter()
|
||||||
|
.zip(statuses)
|
||||||
|
.zip(balances.pre_balances)
|
||||||
|
.zip(balances.post_balances)
|
||||||
|
{
|
||||||
if Bank::can_commit(&status) && !transaction.signatures.is_empty() {
|
if Bank::can_commit(&status) && !transaction.signatures.is_empty() {
|
||||||
let fee_hash = if let Some(HashAgeKind::DurableNonce) = hash_age_kind {
|
let fee_hash = if let Some(HashAgeKind::DurableNonce) = hash_age_kind {
|
||||||
bank.last_blockhash()
|
bank.last_blockhash()
|
||||||
@ -70,7 +76,12 @@ impl TransactionStatusService {
|
|||||||
blocktree
|
blocktree
|
||||||
.write_transaction_status(
|
.write_transaction_status(
|
||||||
(slot, transaction.signatures[0]),
|
(slot, transaction.signatures[0]),
|
||||||
&RpcTransactionStatus { status, fee },
|
&RpcTransactionStatus {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.expect("Expect database write to succeed");
|
.expect("Expect database write to succeed");
|
||||||
}
|
}
|
||||||
|
@ -4550,6 +4550,12 @@ pub mod tests {
|
|||||||
.filter(|entry| !entry.is_tick())
|
.filter(|entry| !entry.is_tick())
|
||||||
.flat_map(|entry| entry.transactions)
|
.flat_map(|entry| entry.transactions)
|
||||||
.map(|transaction| {
|
.map(|transaction| {
|
||||||
|
let mut pre_balances: Vec<u64> = vec![];
|
||||||
|
let mut post_balances: Vec<u64> = vec![];
|
||||||
|
for (i, _account_key) in transaction.message.account_keys.iter().enumerate() {
|
||||||
|
pre_balances.push(i as u64 * 10);
|
||||||
|
post_balances.push(i as u64 * 11);
|
||||||
|
}
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
ledger
|
ledger
|
||||||
.transaction_status_cf
|
.transaction_status_cf
|
||||||
@ -4558,6 +4564,8 @@ pub mod tests {
|
|||||||
&RpcTransactionStatus {
|
&RpcTransactionStatus {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
|
pre_balances: pre_balances.clone(),
|
||||||
|
post_balances: post_balances.clone(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -4568,6 +4576,8 @@ pub mod tests {
|
|||||||
&RpcTransactionStatus {
|
&RpcTransactionStatus {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
|
pre_balances: pre_balances.clone(),
|
||||||
|
post_balances: post_balances.clone(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -4576,6 +4586,8 @@ pub mod tests {
|
|||||||
Some(RpcTransactionStatus {
|
Some(RpcTransactionStatus {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -4694,6 +4706,9 @@ pub mod tests {
|
|||||||
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
||||||
let transaction_status_cf = blocktree.db.column::<cf::TransactionStatus>();
|
let transaction_status_cf = blocktree.db.column::<cf::TransactionStatus>();
|
||||||
|
|
||||||
|
let pre_balances_vec = vec![1, 2, 3];
|
||||||
|
let post_balances_vec = vec![3, 2, 1];
|
||||||
|
|
||||||
// result not found
|
// result not found
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
.get((0, Signature::default()))
|
.get((0, Signature::default()))
|
||||||
@ -4708,18 +4723,27 @@ pub mod tests {
|
|||||||
status: solana_sdk::transaction::Result::<()>::Err(
|
status: solana_sdk::transaction::Result::<()>::Err(
|
||||||
TransactionError::AccountNotFound
|
TransactionError::AccountNotFound
|
||||||
),
|
),
|
||||||
fee: 5u64
|
fee: 5u64,
|
||||||
|
pre_balances: pre_balances_vec.clone(),
|
||||||
|
post_balances: post_balances_vec.clone(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
let RpcTransactionStatus { status, fee } = transaction_status_cf
|
let RpcTransactionStatus {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
} = transaction_status_cf
|
||||||
.get((0, Signature::default()))
|
.get((0, Signature::default()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(status, Err(TransactionError::AccountNotFound));
|
assert_eq!(status, Err(TransactionError::AccountNotFound));
|
||||||
assert_eq!(fee, 5u64);
|
assert_eq!(fee, 5u64);
|
||||||
|
assert_eq!(pre_balances, pre_balances_vec);
|
||||||
|
assert_eq!(post_balances, post_balances_vec);
|
||||||
|
|
||||||
// insert value
|
// insert value
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
@ -4727,13 +4751,20 @@ pub mod tests {
|
|||||||
(9, Signature::default()),
|
(9, Signature::default()),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatus {
|
||||||
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
||||||
fee: 9u64
|
fee: 9u64,
|
||||||
|
pre_balances: pre_balances_vec.clone(),
|
||||||
|
post_balances: post_balances_vec.clone(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
let RpcTransactionStatus { status, fee } = transaction_status_cf
|
let RpcTransactionStatus {
|
||||||
|
status,
|
||||||
|
fee,
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
} = transaction_status_cf
|
||||||
.get((9, Signature::default()))
|
.get((9, Signature::default()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -4741,6 +4772,8 @@ pub mod tests {
|
|||||||
// deserialize
|
// deserialize
|
||||||
assert_eq!(status, Ok(()));
|
assert_eq!(status, Ok(()));
|
||||||
assert_eq!(fee, 9u64);
|
assert_eq!(fee, 9u64);
|
||||||
|
assert_eq!(pre_balances, pre_balances_vec);
|
||||||
|
assert_eq!(post_balances, post_balances_vec);
|
||||||
}
|
}
|
||||||
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
@ -4786,6 +4819,8 @@ pub mod tests {
|
|||||||
TransactionError::AccountNotFound,
|
TransactionError::AccountNotFound,
|
||||||
),
|
),
|
||||||
fee: x,
|
fee: x,
|
||||||
|
pre_balances: vec![],
|
||||||
|
post_balances: vec![],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -14,7 +14,7 @@ use rayon::{prelude::*, ThreadPool};
|
|||||||
use solana_metrics::{datapoint, datapoint_error, inc_new_counter_debug};
|
use solana_metrics::{datapoint, datapoint_error, inc_new_counter_debug};
|
||||||
use solana_rayon_threadlimit::get_thread_count;
|
use solana_rayon_threadlimit::get_thread_count;
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::{Bank, TransactionProcessResult, TransactionResults},
|
bank::{Bank, TransactionBalancesSet, TransactionProcessResult, TransactionResults},
|
||||||
transaction_batch::TransactionBatch,
|
transaction_batch::TransactionBatch,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -54,18 +54,24 @@ fn execute_batch(
|
|||||||
bank: &Arc<Bank>,
|
bank: &Arc<Bank>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let TransactionResults {
|
let (
|
||||||
|
TransactionResults {
|
||||||
fee_collection_results,
|
fee_collection_results,
|
||||||
processing_results,
|
processing_results,
|
||||||
} = batch
|
},
|
||||||
.bank()
|
balances,
|
||||||
.load_execute_and_commit_transactions(batch, MAX_RECENT_BLOCKHASHES);
|
) = batch.bank().load_execute_and_commit_transactions(
|
||||||
|
batch,
|
||||||
|
MAX_RECENT_BLOCKHASHES,
|
||||||
|
transaction_status_sender.is_some(),
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(sender) = transaction_status_sender {
|
if let Some(sender) = transaction_status_sender {
|
||||||
send_transaction_status_batch(
|
send_transaction_status_batch(
|
||||||
bank.clone(),
|
bank.clone(),
|
||||||
batch.transactions(),
|
batch.transactions(),
|
||||||
processing_results,
|
processing_results,
|
||||||
|
balances,
|
||||||
sender,
|
sender,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -560,6 +566,7 @@ pub struct TransactionStatusBatch {
|
|||||||
pub bank: Arc<Bank>,
|
pub bank: Arc<Bank>,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<Transaction>,
|
||||||
pub statuses: Vec<TransactionProcessResult>,
|
pub statuses: Vec<TransactionProcessResult>,
|
||||||
|
pub balances: TransactionBalancesSet,
|
||||||
}
|
}
|
||||||
pub type TransactionStatusSender = Sender<TransactionStatusBatch>;
|
pub type TransactionStatusSender = Sender<TransactionStatusBatch>;
|
||||||
|
|
||||||
@ -567,6 +574,7 @@ pub fn send_transaction_status_batch(
|
|||||||
bank: Arc<Bank>,
|
bank: Arc<Bank>,
|
||||||
transactions: &[Transaction],
|
transactions: &[Transaction],
|
||||||
statuses: Vec<TransactionProcessResult>,
|
statuses: Vec<TransactionProcessResult>,
|
||||||
|
balances: TransactionBalancesSet,
|
||||||
transaction_status_sender: TransactionStatusSender,
|
transaction_status_sender: TransactionStatusSender,
|
||||||
) {
|
) {
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
@ -574,6 +582,7 @@ pub fn send_transaction_status_batch(
|
|||||||
bank,
|
bank,
|
||||||
transactions: transactions.to_vec(),
|
transactions: transactions.to_vec(),
|
||||||
statuses,
|
statuses,
|
||||||
|
balances,
|
||||||
}) {
|
}) {
|
||||||
trace!(
|
trace!(
|
||||||
"Slot {} transaction_status send batch failed: {:?}",
|
"Slot {} transaction_status send batch failed: {:?}",
|
||||||
|
@ -161,6 +161,20 @@ pub struct TransactionResults {
|
|||||||
pub fee_collection_results: Vec<Result<()>>,
|
pub fee_collection_results: Vec<Result<()>>,
|
||||||
pub processing_results: Vec<TransactionProcessResult>,
|
pub processing_results: Vec<TransactionProcessResult>,
|
||||||
}
|
}
|
||||||
|
pub struct TransactionBalancesSet {
|
||||||
|
pub pre_balances: TransactionBalances,
|
||||||
|
pub post_balances: TransactionBalances,
|
||||||
|
}
|
||||||
|
impl TransactionBalancesSet {
|
||||||
|
pub fn new(pre_balances: TransactionBalances, post_balances: TransactionBalances) -> Self {
|
||||||
|
assert_eq!(pre_balances.len(), post_balances.len());
|
||||||
|
Self {
|
||||||
|
pre_balances,
|
||||||
|
post_balances,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub type TransactionBalances = Vec<Vec<u64>>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum HashAgeKind {
|
pub enum HashAgeKind {
|
||||||
@ -1030,6 +1044,18 @@ impl Bank {
|
|||||||
self.check_signatures(txs, iteration_order, age_results, &mut error_counters)
|
self.check_signatures(txs, iteration_order, age_results, &mut error_counters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn collect_balances(&self, batch: &[Transaction]) -> TransactionBalances {
|
||||||
|
let mut balances: TransactionBalances = vec![];
|
||||||
|
for transaction in batch.iter() {
|
||||||
|
let mut transaction_balances: Vec<u64> = vec![];
|
||||||
|
for account_key in transaction.message.account_keys.iter() {
|
||||||
|
transaction_balances.push(self.get_balance(account_key));
|
||||||
|
}
|
||||||
|
balances.push(transaction_balances);
|
||||||
|
}
|
||||||
|
balances
|
||||||
|
}
|
||||||
|
|
||||||
fn update_error_counters(error_counters: &ErrorCounters) {
|
fn update_error_counters(error_counters: &ErrorCounters) {
|
||||||
if 0 != error_counters.blockhash_not_found {
|
if 0 != error_counters.blockhash_not_found {
|
||||||
inc_new_counter_error!(
|
inc_new_counter_error!(
|
||||||
@ -1372,24 +1398,40 @@ impl Bank {
|
|||||||
&self,
|
&self,
|
||||||
batch: &TransactionBatch,
|
batch: &TransactionBatch,
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
) -> TransactionResults {
|
collect_balances: bool,
|
||||||
|
) -> (TransactionResults, TransactionBalancesSet) {
|
||||||
|
let pre_balances = if collect_balances {
|
||||||
|
self.collect_balances(batch.transactions())
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
let (mut loaded_accounts, executed, _, tx_count, signature_count) =
|
let (mut loaded_accounts, executed, _, tx_count, signature_count) =
|
||||||
self.load_and_execute_transactions(batch, max_age);
|
self.load_and_execute_transactions(batch, max_age);
|
||||||
|
|
||||||
self.commit_transactions(
|
let results = self.commit_transactions(
|
||||||
batch.transactions(),
|
batch.transactions(),
|
||||||
batch.iteration_order(),
|
batch.iteration_order(),
|
||||||
&mut loaded_accounts,
|
&mut loaded_accounts,
|
||||||
&executed,
|
&executed,
|
||||||
tx_count,
|
tx_count,
|
||||||
signature_count,
|
signature_count,
|
||||||
|
);
|
||||||
|
let post_balances = if collect_balances {
|
||||||
|
self.collect_balances(batch.transactions())
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
(
|
||||||
|
results,
|
||||||
|
TransactionBalancesSet::new(pre_balances, post_balances),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn process_transactions(&self, txs: &[Transaction]) -> Vec<Result<()>> {
|
pub fn process_transactions(&self, txs: &[Transaction]) -> Vec<Result<()>> {
|
||||||
let batch = self.prepare_batch(txs, None);
|
let batch = self.prepare_batch(txs, None);
|
||||||
self.load_execute_and_commit_transactions(&batch, MAX_RECENT_BLOCKHASHES)
|
self.load_execute_and_commit_transactions(&batch, MAX_RECENT_BLOCKHASHES, false)
|
||||||
|
.0
|
||||||
.fee_collection_results
|
.fee_collection_results
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1816,7 +1858,7 @@ mod tests {
|
|||||||
clock::DEFAULT_TICKS_PER_SLOT,
|
clock::DEFAULT_TICKS_PER_SLOT,
|
||||||
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
instruction::{Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
message::{Message, MessageHeader},
|
message::{Message, MessageHeader},
|
||||||
nonce_instruction, nonce_state,
|
nonce_instruction, nonce_state,
|
||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
@ -3221,7 +3263,8 @@ mod tests {
|
|||||||
|
|
||||||
let lock_result = bank.prepare_batch(&pay_alice, None);
|
let lock_result = bank.prepare_batch(&pay_alice, None);
|
||||||
let results_alice = bank
|
let results_alice = bank
|
||||||
.load_execute_and_commit_transactions(&lock_result, MAX_RECENT_BLOCKHASHES)
|
.load_execute_and_commit_transactions(&lock_result, MAX_RECENT_BLOCKHASHES, false)
|
||||||
|
.0
|
||||||
.fee_collection_results;
|
.fee_collection_results;
|
||||||
assert_eq!(results_alice[0], Ok(()));
|
assert_eq!(results_alice[0], Ok(()));
|
||||||
|
|
||||||
@ -4731,4 +4774,94 @@ mod tests {
|
|||||||
/* Check fee charged */
|
/* Check fee charged */
|
||||||
assert_eq!(bank.get_balance(&custodian_pubkey), 4_630_000);
|
assert_eq!(bank.get_balance(&custodian_pubkey), 4_630_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_balances() {
|
||||||
|
let (genesis_config, _mint_keypair) = create_genesis_config(500);
|
||||||
|
let parent = Arc::new(Bank::new(&genesis_config));
|
||||||
|
let bank0 = Arc::new(new_from_parent(&parent));
|
||||||
|
|
||||||
|
let keypair = Keypair::new();
|
||||||
|
let pubkey0 = Pubkey::new_rand();
|
||||||
|
let pubkey1 = Pubkey::new_rand();
|
||||||
|
let program_id = Pubkey::new(&[2; 32]);
|
||||||
|
let keypair_account = Account::new(8, 0, &program_id);
|
||||||
|
let account0 = Account::new(11, 0, &program_id);
|
||||||
|
let program_account = Account::new(1, 10, &Pubkey::default());
|
||||||
|
bank0.store_account(&keypair.pubkey(), &keypair_account);
|
||||||
|
bank0.store_account(&pubkey0, &account0);
|
||||||
|
bank0.store_account(&program_id, &program_account);
|
||||||
|
|
||||||
|
let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
|
||||||
|
let tx0 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair],
|
||||||
|
&[pubkey0],
|
||||||
|
Hash::default(),
|
||||||
|
vec![program_id],
|
||||||
|
instructions,
|
||||||
|
);
|
||||||
|
let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
|
||||||
|
let tx1 = Transaction::new_with_compiled_instructions(
|
||||||
|
&[&keypair],
|
||||||
|
&[pubkey1],
|
||||||
|
Hash::default(),
|
||||||
|
vec![program_id],
|
||||||
|
instructions,
|
||||||
|
);
|
||||||
|
let balances = bank0.collect_balances(&[tx0, tx1]);
|
||||||
|
assert_eq!(balances.len(), 2);
|
||||||
|
assert_eq!(balances[0], vec![8, 11, 1]);
|
||||||
|
assert_eq!(balances[1], vec![8, 0, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pre_post_transaction_balances() {
|
||||||
|
let (mut genesis_config, _mint_keypair) = create_genesis_config(500);
|
||||||
|
let fee_calculator = FeeCalculator::new(1, 0);
|
||||||
|
genesis_config.fee_calculator = fee_calculator;
|
||||||
|
let parent = Arc::new(Bank::new(&genesis_config));
|
||||||
|
let bank0 = Arc::new(new_from_parent(&parent));
|
||||||
|
|
||||||
|
let keypair0 = Keypair::new();
|
||||||
|
let keypair1 = Keypair::new();
|
||||||
|
let pubkey0 = Pubkey::new_rand();
|
||||||
|
let pubkey1 = Pubkey::new_rand();
|
||||||
|
let pubkey2 = Pubkey::new_rand();
|
||||||
|
let keypair0_account = Account::new(8, 0, &Pubkey::default());
|
||||||
|
let keypair1_account = Account::new(9, 0, &Pubkey::default());
|
||||||
|
let account0 = Account::new(11, 0, &&Pubkey::default());
|
||||||
|
bank0.store_account(&keypair0.pubkey(), &keypair0_account);
|
||||||
|
bank0.store_account(&keypair1.pubkey(), &keypair1_account);
|
||||||
|
bank0.store_account(&pubkey0, &account0);
|
||||||
|
|
||||||
|
let blockhash = bank0.last_blockhash();
|
||||||
|
|
||||||
|
let tx0 = system_transaction::transfer(&keypair0, &pubkey0, 2, blockhash.clone());
|
||||||
|
let tx1 = system_transaction::transfer(&Keypair::new(), &pubkey1, 2, blockhash.clone());
|
||||||
|
let tx2 = system_transaction::transfer(&keypair1, &pubkey2, 12, blockhash.clone());
|
||||||
|
let txs = vec![tx0, tx1, tx2];
|
||||||
|
|
||||||
|
let lock_result = bank0.prepare_batch(&txs, None);
|
||||||
|
let (transaction_results, transaction_balances_set) =
|
||||||
|
bank0.load_execute_and_commit_transactions(&lock_result, MAX_RECENT_BLOCKHASHES, true);
|
||||||
|
|
||||||
|
assert_eq!(transaction_balances_set.pre_balances.len(), 3);
|
||||||
|
assert_eq!(transaction_balances_set.post_balances.len(), 3);
|
||||||
|
|
||||||
|
assert!(transaction_results.processing_results[0].0.is_ok());
|
||||||
|
assert_eq!(transaction_balances_set.pre_balances[0], vec![8, 11, 1]);
|
||||||
|
assert_eq!(transaction_balances_set.post_balances[0], vec![5, 13, 1]);
|
||||||
|
|
||||||
|
// Failed transactions still produce balance sets
|
||||||
|
// This is a TransactionError - not possible to charge fees
|
||||||
|
assert!(transaction_results.processing_results[1].0.is_err());
|
||||||
|
assert_eq!(transaction_balances_set.pre_balances[1], vec![0, 0, 1]);
|
||||||
|
assert_eq!(transaction_balances_set.post_balances[1], vec![0, 0, 1]);
|
||||||
|
|
||||||
|
// Failed transactions still produce balance sets
|
||||||
|
// This is an InstructionError - fees charged
|
||||||
|
assert!(transaction_results.processing_results[2].0.is_err());
|
||||||
|
assert_eq!(transaction_balances_set.pre_balances[2], vec![9, 0, 1]);
|
||||||
|
assert_eq!(transaction_balances_set.post_balances[2], vec![8, 0, 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user