credit_only credits forwarding (#6509)
* credit_only_credits_forwarding * whack transfer_now() * fixup * bench should retry the airdrop TX * fixup * try to make bench-exchange a bit more robust, informative
This commit is contained in:
parent
d398898c38
commit
b4119c454a
|
@ -633,7 +633,7 @@ fn trader<T>(
|
|||
}
|
||||
}
|
||||
|
||||
fn verify_transfer<T>(sync_client: &T, tx: &Transaction) -> bool
|
||||
fn verify_transaction<T>(sync_client: &T, tx: &Transaction) -> bool
|
||||
where
|
||||
T: SyncClient + ?Sized,
|
||||
{
|
||||
|
@ -657,9 +657,11 @@ fn verify_funding_transfer<T: SyncClient + ?Sized>(
|
|||
tx: &Transaction,
|
||||
amount: u64,
|
||||
) -> bool {
|
||||
for a in &tx.message().account_keys[1..] {
|
||||
if client.get_balance(a).unwrap_or(0) >= amount {
|
||||
return true;
|
||||
if verify_transaction(client, tx) {
|
||||
for a in &tx.message().account_keys[1..] {
|
||||
if client.get_balance(a).unwrap_or(0) >= amount {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -830,11 +832,11 @@ pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], acco
|
|||
let mut waits = 0;
|
||||
while !to_create_txs.is_empty() {
|
||||
sleep(Duration::from_millis(200));
|
||||
to_create_txs.retain(|(_, tx)| !verify_transfer(client, &tx));
|
||||
to_create_txs.retain(|(_, tx)| !verify_transaction(client, &tx));
|
||||
if to_create_txs.is_empty() {
|
||||
break;
|
||||
}
|
||||
debug!(
|
||||
info!(
|
||||
" {} transactions outstanding, waits {:?}",
|
||||
to_create_txs.len(),
|
||||
waits
|
||||
|
@ -847,7 +849,7 @@ pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], acco
|
|||
|
||||
if !to_create_txs.is_empty() {
|
||||
retries += 1;
|
||||
debug!(" Retry {:?}", retries);
|
||||
info!(" Retry {:?} {} txes left", retries, to_create_txs.len());
|
||||
if retries >= 20 {
|
||||
error!(
|
||||
"create_token_accounts: Too many retries ({}), give up",
|
||||
|
|
|
@ -306,7 +306,7 @@ fn generate_system_txs(
|
|||
.par_iter()
|
||||
.map(|(from, to)| {
|
||||
(
|
||||
system_transaction::transfer_now(from, &to.pubkey(), 1, *blockhash),
|
||||
system_transaction::transfer(from, &to.pubkey(), 1, *blockhash),
|
||||
timestamp(),
|
||||
)
|
||||
})
|
||||
|
@ -634,15 +634,22 @@ pub fn airdrop_lamports<T: Client>(
|
|||
let (blockhash, _fee_calculator) = get_recent_blockhash(client);
|
||||
match request_airdrop_transaction(&drone_addr, &id.pubkey(), airdrop_amount, blockhash) {
|
||||
Ok(transaction) => {
|
||||
let signature = client.async_send_transaction(transaction).unwrap();
|
||||
client
|
||||
.poll_for_signature_confirmation(&signature, 1)
|
||||
.unwrap_or_else(|_| {
|
||||
let mut tries = 0;
|
||||
loop {
|
||||
tries += 1;
|
||||
let signature = client.async_send_transaction(transaction.clone()).unwrap();
|
||||
let result = client.poll_for_signature_confirmation(&signature, 1);
|
||||
|
||||
if result.is_ok() {
|
||||
break;
|
||||
}
|
||||
if tries >= 5 {
|
||||
panic!(
|
||||
"Error requesting airdrop: to addr: {:?} amount: {}",
|
||||
drone_addr, airdrop_amount
|
||||
"Error requesting airdrop: to addr: {:?} amount: {} {:?}",
|
||||
drone_addr, airdrop_amount, result
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
panic!(
|
||||
|
|
|
@ -871,7 +871,7 @@ mod tests {
|
|||
let key = Keypair::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
|
||||
let signature = rpc_client.send_transaction(&tx);
|
||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||
|
@ -920,7 +920,7 @@ mod tests {
|
|||
let key = Keypair::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let mut tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let mut tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||
result.unwrap();
|
||||
|
@ -943,8 +943,8 @@ mod tests {
|
|||
let blockhash: Hash = "HUu3LwEzGRsUkuJS121jzkPJW39Kq62pXCTmTa1F9jDL"
|
||||
.parse()
|
||||
.unwrap();
|
||||
let prev_tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let mut tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let prev_tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
let mut tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
|
||||
rpc_client.resign_transaction(&mut tx, &[&key]).unwrap();
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ fn bench_poh_verify_transaction_entries(bencher: &mut Bencher) {
|
|||
|
||||
let mut ticks: Vec<Entry> = Vec::with_capacity(NUM_ENTRIES);
|
||||
for _ in 0..NUM_ENTRIES {
|
||||
let tx = system_transaction::transfer_now(&keypair1, &pubkey1, 42, cur_hash);
|
||||
let tx = system_transaction::transfer(&keypair1, &pubkey1, 42, cur_hash);
|
||||
ticks.push(next_entry_mut(&mut cur_hash, NUM_HASHES, vec![tx]));
|
||||
}
|
||||
|
||||
|
|
|
@ -1096,21 +1096,21 @@ mod tests {
|
|||
// fund another account so we can send 2 good transactions in a single batch.
|
||||
let keypair = Keypair::new();
|
||||
let fund_tx =
|
||||
system_transaction::transfer_now(&mint_keypair, &keypair.pubkey(), 2, start_hash);
|
||||
system_transaction::transfer(&mint_keypair, &keypair.pubkey(), 2, start_hash);
|
||||
bank.process_transaction(&fund_tx).unwrap();
|
||||
|
||||
// good tx
|
||||
let to = Pubkey::new_rand();
|
||||
let tx = system_transaction::transfer_now(&mint_keypair, &to, 1, start_hash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &to, 1, start_hash);
|
||||
|
||||
// good tx, but no verify
|
||||
let to2 = Pubkey::new_rand();
|
||||
let tx_no_ver = system_transaction::transfer_now(&keypair, &to2, 2, start_hash);
|
||||
let tx_no_ver = system_transaction::transfer(&keypair, &to2, 2, start_hash);
|
||||
|
||||
// bad tx, AccountNotFound
|
||||
let keypair = Keypair::new();
|
||||
let to3 = Pubkey::new_rand();
|
||||
let tx_anf = system_transaction::transfer_now(&keypair, &to3, 1, start_hash);
|
||||
let tx_anf = system_transaction::transfer(&keypair, &to3, 1, start_hash);
|
||||
|
||||
// send 'em over
|
||||
let packets = to_packets(&[tx_no_ver, tx_anf, tx]);
|
||||
|
@ -1186,12 +1186,8 @@ mod tests {
|
|||
|
||||
// Process a batch that includes a transaction that receives two lamports.
|
||||
let alice = Keypair::new();
|
||||
let tx = system_transaction::transfer_now(
|
||||
&mint_keypair,
|
||||
&alice.pubkey(),
|
||||
2,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 2, genesis_block.hash());
|
||||
|
||||
let packets = to_packets(&[tx]);
|
||||
let packets = packets
|
||||
|
@ -1200,13 +1196,9 @@ mod tests {
|
|||
.collect();
|
||||
verified_sender.send(packets).unwrap();
|
||||
|
||||
// Process a second batch that spends one of those lamports.
|
||||
let tx = system_transaction::transfer_now(
|
||||
&alice,
|
||||
&mint_keypair.pubkey(),
|
||||
1,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
// Process a second batch that uses the same from account, so conflicts with above TX
|
||||
let tx =
|
||||
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, genesis_block.hash());
|
||||
let packets = to_packets(&[tx]);
|
||||
let packets = packets
|
||||
.into_iter()
|
||||
|
@ -1241,7 +1233,7 @@ mod tests {
|
|||
);
|
||||
|
||||
// wait for banking_stage to eat the packets
|
||||
while bank.get_balance(&alice.pubkey()) != 1 {
|
||||
while bank.get_balance(&alice.pubkey()) < 2 {
|
||||
sleep(Duration::from_millis(100));
|
||||
}
|
||||
exit.store(true, Ordering::Relaxed);
|
||||
|
@ -1265,10 +1257,10 @@ mod tests {
|
|||
.for_each(|x| assert_eq!(*x, Ok(())));
|
||||
}
|
||||
|
||||
// Assert the user holds one lamport, not two. If the stage only outputs one
|
||||
// Assert the user holds two lamports, not three. If the stage only outputs one
|
||||
// entry, then the second transaction will be rejected, because it drives
|
||||
// the account balance below zero before the credit is added.
|
||||
assert_eq!(bank.get_balance(&alice.pubkey()), 1);
|
||||
assert_eq!(bank.get_balance(&alice.pubkey()), 2);
|
||||
}
|
||||
Blocktree::destroy(&ledger_path).unwrap();
|
||||
}
|
||||
|
@ -1607,7 +1599,7 @@ mod tests {
|
|||
let bank = Arc::new(Bank::new(&genesis_block));
|
||||
let pubkey = Pubkey::new_rand();
|
||||
|
||||
let transactions = vec![system_transaction::transfer_now(
|
||||
let transactions = vec![system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&pubkey,
|
||||
1,
|
||||
|
|
|
@ -138,7 +138,7 @@ mod test {
|
|||
|
||||
let keypair = Keypair::new();
|
||||
let mut blockhash = entries[3].hash;
|
||||
let tx = system_transaction::transfer_now(&keypair, &keypair.pubkey(), 1, Hash::default());
|
||||
let tx = system_transaction::transfer(&keypair, &keypair.pubkey(), 1, Hash::default());
|
||||
let entry = Entry::new(&mut blockhash, 1, vec![tx]);
|
||||
blockhash = entry.hash;
|
||||
entries.push(entry);
|
||||
|
|
|
@ -87,7 +87,7 @@ mod tests {
|
|||
..
|
||||
} = create_genesis_block(2);
|
||||
let bank0 = Arc::new(Bank::new(&genesis_block));
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&Pubkey::new_rand(),
|
||||
1,
|
||||
|
|
|
@ -101,7 +101,7 @@ mod tests {
|
|||
Entry::new_mut(
|
||||
&mut id,
|
||||
&mut num_hashes,
|
||||
vec![system_transaction::transfer_now(
|
||||
vec![system_transaction::transfer(
|
||||
&keypair,
|
||||
&keypair.pubkey(),
|
||||
1,
|
||||
|
|
|
@ -602,7 +602,7 @@ mod tests {
|
|||
fn test_to_packets() {
|
||||
let keypair = Keypair::new();
|
||||
let hash = Hash::new(&[1; 32]);
|
||||
let tx = system_transaction::transfer_now(&keypair, &keypair.pubkey(), 1, hash);
|
||||
let tx = system_transaction::transfer(&keypair, &keypair.pubkey(), 1, hash);
|
||||
let rv = to_packets(&vec![tx.clone(); 1]);
|
||||
assert_eq!(rv.len(), 1);
|
||||
assert_eq!(rv[0].packets.len(), 1);
|
||||
|
|
|
@ -956,7 +956,7 @@ mod test {
|
|||
blockhash,
|
||||
1,
|
||||
vec![
|
||||
system_transaction::transfer_now(&keypair1, &keypair2.pubkey(), 2, *blockhash), // should be fine,
|
||||
system_transaction::transfer(&keypair1, &keypair2.pubkey(), 2, *blockhash), // should be fine,
|
||||
system_transaction::transfer(
|
||||
&missing_keypair,
|
||||
&missing_keypair2.pubkey(),
|
||||
|
@ -983,7 +983,7 @@ mod test {
|
|||
// Use wrong blockhash so that the entry causes an entry verification failure
|
||||
&bad_hash,
|
||||
1,
|
||||
vec![system_transaction::transfer_now(
|
||||
vec![system_transaction::transfer(
|
||||
&genesis_keypair,
|
||||
&keypair2.pubkey(),
|
||||
2,
|
||||
|
|
|
@ -391,7 +391,7 @@ mod tests {
|
|||
None,
|
||||
);
|
||||
|
||||
let tx = system_transaction::transfer_now(&alice, &contract_funds.pubkey(), 51, blockhash);
|
||||
let tx = system_transaction::transfer(&alice, &contract_funds.pubkey(), 51, blockhash);
|
||||
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions).unwrap();
|
||||
|
||||
let ixs = budget_instruction::when_signed(
|
||||
|
@ -435,7 +435,7 @@ mod tests {
|
|||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
}
|
||||
|
||||
let tx = system_transaction::transfer_now(&alice, &witness.pubkey(), 1, blockhash);
|
||||
let tx = system_transaction::transfer(&alice, &witness.pubkey(), 1, blockhash);
|
||||
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions).unwrap();
|
||||
sleep(Duration::from_millis(200));
|
||||
let ix = budget_instruction::apply_signature(
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn test_tx() -> Transaction {
|
|||
let keypair1 = Keypair::new();
|
||||
let pubkey1 = keypair1.pubkey();
|
||||
let zero = Hash::default();
|
||||
system_transaction::transfer_now(&keypair1, &pubkey1, 42, zero)
|
||||
system_transaction::transfer(&keypair1, &pubkey1, 42, zero)
|
||||
}
|
||||
|
||||
pub fn test_multisig_tx() -> Transaction {
|
||||
|
|
|
@ -156,12 +156,8 @@ mod tests {
|
|||
4,
|
||||
|bank, mint_keypair| {
|
||||
let key1 = Keypair::new().pubkey();
|
||||
let tx = system_transaction::transfer_now(
|
||||
&mint_keypair,
|
||||
&key1,
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&mint_keypair, &key1, 1, bank.last_blockhash());
|
||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||
bank.freeze();
|
||||
},
|
||||
|
@ -224,8 +220,7 @@ mod tests {
|
|||
);
|
||||
let slot = bank.slot();
|
||||
let key1 = Keypair::new().pubkey();
|
||||
let tx =
|
||||
system_transaction::transfer_now(&mint_keypair, &key1, 1, genesis_block.hash());
|
||||
let tx = system_transaction::transfer(&mint_keypair, &key1, 1, genesis_block.hash());
|
||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||
bank.freeze();
|
||||
bank_forks.insert(bank);
|
||||
|
|
|
@ -121,11 +121,8 @@ impl Drone {
|
|||
);
|
||||
info!("Requesting airdrop of {} to {:?}", lamports, to);
|
||||
|
||||
let create_instruction = system_instruction::transfer_now(
|
||||
&self.mint_keypair.pubkey(),
|
||||
&to,
|
||||
lamports,
|
||||
);
|
||||
let create_instruction =
|
||||
system_instruction::transfer(&self.mint_keypair.pubkey(), &to, lamports);
|
||||
let message = Message::new(vec![create_instruction]);
|
||||
Ok(Transaction::new(&[&self.mint_keypair], message, blockhash))
|
||||
} else {
|
||||
|
@ -411,8 +408,7 @@ mod tests {
|
|||
bytes.put(&req[..]);
|
||||
|
||||
let keypair = Keypair::new();
|
||||
let expected_instruction =
|
||||
system_instruction::transfer_now(&keypair.pubkey(), &to, lamports);
|
||||
let expected_instruction = system_instruction::transfer(&keypair.pubkey(), &to, lamports);
|
||||
let message = Message::new(vec![expected_instruction]);
|
||||
let expected_tx = Transaction::new(&[&keypair], message, blockhash);
|
||||
let expected_bytes = serialize(&expected_tx).unwrap();
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn request_airdrop_transaction(
|
|||
let key = Keypair::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let tx = system_transaction::transfer_now(&key, &to, lamports, blockhash);
|
||||
let tx = system_transaction::transfer(&key, &to, lamports, blockhash);
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ fn test_local_drone() {
|
|||
let to = Pubkey::new_rand();
|
||||
let lamports = 50;
|
||||
let blockhash = Hash::new(&to.as_ref());
|
||||
let create_instruction = system_instruction::transfer_now(&keypair.pubkey(), &to, lamports);
|
||||
let create_instruction = system_instruction::transfer(&keypair.pubkey(), &to, lamports);
|
||||
let message = Message::new(vec![create_instruction]);
|
||||
let expected_tx = Transaction::new(&[&keypair], message, blockhash);
|
||||
|
||||
|
|
|
@ -842,7 +842,7 @@ pub mod tests {
|
|||
let bank = Arc::new(Bank::new(&genesis_block));
|
||||
let keypair = Keypair::new();
|
||||
let slot_entries = create_ticks(genesis_block.ticks_per_slot, genesis_block.hash());
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair.pubkey(),
|
||||
1,
|
||||
|
@ -879,8 +879,7 @@ pub mod tests {
|
|||
for _ in 0..deducted_from_mint {
|
||||
// Transfer one token from the mint to a random account
|
||||
let keypair = Keypair::new();
|
||||
let tx =
|
||||
system_transaction::transfer_now(&mint_keypair, &keypair.pubkey(), 1, blockhash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &keypair.pubkey(), 1, blockhash);
|
||||
let entry = Entry::new(&last_entry_hash, 1, vec![tx]);
|
||||
last_entry_hash = entry.hash;
|
||||
entries.push(entry);
|
||||
|
@ -888,7 +887,8 @@ pub mod tests {
|
|||
// Add a second Transaction that will produce a
|
||||
// InstructionError<0, ResultWithNegativeLamports> error when processed
|
||||
let keypair2 = Keypair::new();
|
||||
let tx = system_transaction::transfer_now(&keypair, &keypair2.pubkey(), 42, blockhash);
|
||||
let tx =
|
||||
system_transaction::transfer(&mint_keypair, &keypair2.pubkey(), 101, blockhash);
|
||||
let entry = Entry::new(&last_entry_hash, 1, vec![tx]);
|
||||
last_entry_hash = entry.hash;
|
||||
entries.push(entry);
|
||||
|
@ -997,12 +997,10 @@ pub mod tests {
|
|||
let blockhash = genesis_block.hash();
|
||||
let keypairs = [Keypair::new(), Keypair::new(), Keypair::new()];
|
||||
|
||||
let tx =
|
||||
system_transaction::transfer_now(&mint_keypair, &keypairs[0].pubkey(), 1, blockhash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &keypairs[0].pubkey(), 1, blockhash);
|
||||
let entry_1 = next_entry(&last_entry_hash, 1, vec![tx]);
|
||||
|
||||
let tx =
|
||||
system_transaction::transfer_now(&mint_keypair, &keypairs[1].pubkey(), 1, blockhash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &keypairs[1].pubkey(), 1, blockhash);
|
||||
let entry_2 = next_entry(&entry_1.hash, 1, vec![tx]);
|
||||
|
||||
let mut entries = vec![entry_1, entry_2];
|
||||
|
@ -1067,14 +1065,14 @@ pub mod tests {
|
|||
let blockhash = bank.last_blockhash();
|
||||
|
||||
// ensure bank can process 2 entries that have a common account and no tick is registered
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair1.pubkey(),
|
||||
2,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let entry_1 = next_entry(&blockhash, 1, vec![tx]);
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair2.pubkey(),
|
||||
2,
|
||||
|
@ -1107,7 +1105,7 @@ pub mod tests {
|
|||
let entry_1_to_mint = next_entry(
|
||||
&bank.last_blockhash(),
|
||||
1,
|
||||
vec![system_transaction::transfer_now(
|
||||
vec![system_transaction::transfer(
|
||||
&keypair1,
|
||||
&mint_keypair.pubkey(),
|
||||
1,
|
||||
|
@ -1119,13 +1117,13 @@ pub mod tests {
|
|||
&entry_1_to_mint.hash,
|
||||
1,
|
||||
vec![
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair2,
|
||||
&keypair3.pubkey(),
|
||||
2,
|
||||
bank.last_blockhash(),
|
||||
), // should be fine
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair1,
|
||||
&mint_keypair.pubkey(),
|
||||
2,
|
||||
|
@ -1167,7 +1165,7 @@ pub mod tests {
|
|||
&bank.last_blockhash(),
|
||||
1,
|
||||
vec![
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair1,
|
||||
&mint_keypair.pubkey(),
|
||||
1,
|
||||
|
@ -1186,13 +1184,13 @@ pub mod tests {
|
|||
&entry_1_to_mint.hash,
|
||||
1,
|
||||
vec![
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair2,
|
||||
&keypair3.pubkey(),
|
||||
2,
|
||||
bank.last_blockhash(),
|
||||
), // should be fine
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair1,
|
||||
&mint_keypair.pubkey(),
|
||||
2,
|
||||
|
@ -1265,7 +1263,7 @@ pub mod tests {
|
|||
&entry_1_to_mint.hash,
|
||||
1,
|
||||
vec![
|
||||
system_transaction::transfer_now(
|
||||
system_transaction::transfer(
|
||||
&keypair2,
|
||||
&keypair3.pubkey(),
|
||||
2,
|
||||
|
@ -1338,14 +1336,14 @@ pub mod tests {
|
|||
let keypair4 = Keypair::new();
|
||||
|
||||
//load accounts
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair1.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair2.pubkey(),
|
||||
1,
|
||||
|
@ -1355,19 +1353,11 @@ pub mod tests {
|
|||
|
||||
// ensure bank can process 2 entries that do not have a common account and no tick is registered
|
||||
let blockhash = bank.last_blockhash();
|
||||
let tx = system_transaction::transfer_now(
|
||||
&keypair1,
|
||||
&keypair3.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&keypair1, &keypair3.pubkey(), 1, bank.last_blockhash());
|
||||
let entry_1 = next_entry(&blockhash, 1, vec![tx]);
|
||||
let tx = system_transaction::transfer_now(
|
||||
&keypair2,
|
||||
&keypair4.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&keypair2, &keypair4.pubkey(), 1, bank.last_blockhash());
|
||||
let entry_2 = next_entry(&entry_1.hash, 1, vec![tx]);
|
||||
assert_eq!(process_entries(&bank, &[entry_1, entry_2], true), Ok(()));
|
||||
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
||||
|
@ -1448,7 +1438,7 @@ pub mod tests {
|
|||
|
||||
for _ in 0..num_accounts {
|
||||
let keypair = Keypair::new();
|
||||
let create_account_tx = system_transaction::transfer_now(
|
||||
let create_account_tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair.pubkey(),
|
||||
0,
|
||||
|
@ -1516,14 +1506,14 @@ pub mod tests {
|
|||
let keypair4 = Keypair::new();
|
||||
|
||||
//load accounts
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair1.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||
let tx = system_transaction::transfer_now(
|
||||
let tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair2.pubkey(),
|
||||
1,
|
||||
|
@ -1537,15 +1527,11 @@ pub mod tests {
|
|||
}
|
||||
|
||||
// ensure bank can process 2 entries that do not have a common account and tick is registered
|
||||
let tx = system_transaction::transfer_now(&keypair2, &keypair3.pubkey(), 1, blockhash);
|
||||
let tx = system_transaction::transfer(&keypair2, &keypair3.pubkey(), 1, blockhash);
|
||||
let entry_1 = next_entry(&blockhash, 1, vec![tx]);
|
||||
let tick = next_entry(&entry_1.hash, 1, vec![]);
|
||||
let tx = system_transaction::transfer_now(
|
||||
&keypair1,
|
||||
&keypair4.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&keypair1, &keypair4.pubkey(), 1, bank.last_blockhash());
|
||||
let entry_2 = next_entry(&tick.hash, 1, vec![tx]);
|
||||
assert_eq!(
|
||||
process_entries(
|
||||
|
@ -1559,12 +1545,8 @@ pub mod tests {
|
|||
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
||||
|
||||
// ensure that an error is returned for an empty account (keypair2)
|
||||
let tx = system_transaction::transfer_now(
|
||||
&keypair2,
|
||||
&keypair3.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&keypair2, &keypair3.pubkey(), 1, bank.last_blockhash());
|
||||
let entry_3 = next_entry(&entry_2.hash, 1, vec![tx]);
|
||||
assert_eq!(
|
||||
process_entries(&bank, &[entry_3], true),
|
||||
|
@ -1598,7 +1580,7 @@ pub mod tests {
|
|||
);
|
||||
|
||||
// Make sure other errors don't update the signature cache
|
||||
let tx = system_transaction::transfer_now(&mint_keypair, &pubkey, 1000, Hash::default());
|
||||
let tx = system_transaction::transfer(&mint_keypair, &pubkey, 1000, Hash::default());
|
||||
let signature = tx.signatures[0];
|
||||
|
||||
// Should fail with blockhash not found
|
||||
|
@ -1624,13 +1606,13 @@ pub mod tests {
|
|||
let bank = Arc::new(Bank::new(&genesis_block));
|
||||
let keypair1 = Keypair::new();
|
||||
let keypair2 = Keypair::new();
|
||||
let success_tx = system_transaction::transfer_now(
|
||||
let success_tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair1.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let fail_tx = system_transaction::transfer_now(
|
||||
let fail_tx = system_transaction::transfer(
|
||||
&mint_keypair,
|
||||
&keypair2.pubkey(),
|
||||
2,
|
||||
|
|
|
@ -412,8 +412,8 @@ mod tests {
|
|||
|
||||
// First, verify entries
|
||||
let keypair = Keypair::new();
|
||||
let tx0 = system_transaction::transfer_now(&keypair, &keypair.pubkey(), 0, zero);
|
||||
let tx1 = system_transaction::transfer_now(&keypair, &keypair.pubkey(), 1, zero);
|
||||
let tx0 = system_transaction::transfer(&keypair, &keypair.pubkey(), 0, zero);
|
||||
let tx1 = system_transaction::transfer(&keypair, &keypair.pubkey(), 1, zero);
|
||||
let mut e0 = Entry::new(&zero, 0, vec![tx0.clone(), tx1.clone()]);
|
||||
assert!(e0.verify(&zero));
|
||||
|
||||
|
@ -463,7 +463,7 @@ mod tests {
|
|||
fn test_next_entry_panic() {
|
||||
let zero = Hash::default();
|
||||
let keypair = Keypair::new();
|
||||
let tx = system_transaction::transfer_now(&keypair, &keypair.pubkey(), 0, zero);
|
||||
let tx = system_transaction::transfer(&keypair, &keypair.pubkey(), 0, zero);
|
||||
next_entry(&zero, 0, vec![tx]);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ pub fn package_snapshot<P: AsRef<Path>, Q: AsRef<Path>>(
|
|||
.rc
|
||||
.get_storage_entries()
|
||||
.into_iter()
|
||||
.filter(|x| x.fork_id() <= bank.slot())
|
||||
.filter(|x| x.slot_id() <= bank.slot())
|
||||
.collect();
|
||||
|
||||
// Create a snapshot package
|
||||
|
|
|
@ -426,7 +426,7 @@ impl LocalCluster {
|
|||
trace!("getting leader blockhash");
|
||||
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
|
||||
let mut tx =
|
||||
system_transaction::transfer_now(&source_keypair, dest_pubkey, lamports, blockhash);
|
||||
system_transaction::transfer(&source_keypair, dest_pubkey, lamports, blockhash);
|
||||
info!(
|
||||
"executing transfer of {} from {} to {}",
|
||||
lamports,
|
||||
|
|
|
@ -117,10 +117,8 @@ mod bpf {
|
|||
} = create_genesis_block(50);
|
||||
let bank = Arc::new(Bank::new(&genesis_block));
|
||||
// Create bank with specific slot, used by solana_bpf_rust_sysvar test
|
||||
dbg!(bank.epoch());
|
||||
let bank =
|
||||
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
|
||||
dbg!(bank.epoch());
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
// Call user program
|
||||
|
|
|
@ -469,7 +469,7 @@ fn init_storage_accounts(
|
|||
archiver_accounts_to_create: &[&Pubkey],
|
||||
lamports: u64,
|
||||
) {
|
||||
let mut ixs: Vec<_> = vec![system_instruction::transfer_now(&mint.pubkey(), owner, 1)];
|
||||
let mut ixs: Vec<_> = vec![system_instruction::transfer(&mint.pubkey(), owner, 1)];
|
||||
ixs.append(
|
||||
&mut validator_accounts_to_create
|
||||
.into_iter()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::accounts_db::{AccountInfo, AccountStorage, AccountsDB, AppendVecId, ErrorCounters};
|
||||
use crate::accounts_index::{AccountsIndex, Fork};
|
||||
use crate::accounts_index::AccountsIndex;
|
||||
use crate::append_vec::StoredAccount;
|
||||
use crate::blockhash_queue::BlockhashQueue;
|
||||
use crate::message_processor::has_duplicates;
|
||||
|
@ -9,6 +9,7 @@ use rayon::slice::ParallelSliceMut;
|
|||
use solana_metrics::inc_new_counter_error;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::bank_hash::BankHash;
|
||||
use solana_sdk::clock::Slot;
|
||||
use solana_sdk::message::Message;
|
||||
use solana_sdk::native_loader;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
@ -19,7 +20,7 @@ use std::collections::{HashMap, HashSet};
|
|||
use std::io::{BufReader, Error as IOError, Read};
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use crate::transaction_utils::OrderedIterator;
|
||||
|
||||
|
@ -32,6 +33,9 @@ struct CreditOnlyLock {
|
|||
/// This structure handles synchronization for db
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Accounts {
|
||||
/// my slot
|
||||
pub slot: Slot,
|
||||
|
||||
/// Single global AccountsDB
|
||||
pub accounts_db: Arc<AccountsDB>,
|
||||
|
||||
|
@ -41,7 +45,7 @@ pub struct Accounts {
|
|||
/// Set of credit-only accounts which are currently in the pipeline, caching account balance
|
||||
/// and number of locks. On commit_credits(), we do a take() on the option so that the hashmap
|
||||
/// is no longer available to be written to.
|
||||
credit_only_account_locks: Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||
credit_only_locks: Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||
}
|
||||
|
||||
// for the load instructions
|
||||
|
@ -62,18 +66,20 @@ impl Accounts {
|
|||
let accounts_db = Arc::new(AccountsDB::new(paths));
|
||||
|
||||
Accounts {
|
||||
slot: 0,
|
||||
accounts_db,
|
||||
account_locks: Mutex::new(HashSet::new()),
|
||||
credit_only_account_locks: Arc::new(RwLock::new(Some(HashMap::new()))),
|
||||
credit_only_locks: Arc::new(RwLock::new(Some(HashMap::new()))),
|
||||
}
|
||||
}
|
||||
pub fn new_from_parent(parent: &Accounts, slot: Fork, parent_slot: Fork) -> Self {
|
||||
pub fn new_from_parent(parent: &Accounts, slot: Slot, parent_slot: Slot) -> Self {
|
||||
let accounts_db = parent.accounts_db.clone();
|
||||
accounts_db.set_hash(slot, parent_slot);
|
||||
Accounts {
|
||||
slot,
|
||||
accounts_db,
|
||||
account_locks: Mutex::new(HashSet::new()),
|
||||
credit_only_account_locks: Arc::new(RwLock::new(Some(HashMap::new()))),
|
||||
credit_only_locks: Arc::new(RwLock::new(Some(HashMap::new()))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,14 +94,15 @@ impl Accounts {
|
|||
}
|
||||
|
||||
fn load_tx_accounts(
|
||||
&self,
|
||||
storage: &AccountStorage,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
accounts_index: &AccountsIndex<AccountInfo>,
|
||||
tx: &Transaction,
|
||||
fee: u64,
|
||||
error_counters: &mut ErrorCounters,
|
||||
rent_collector: &RentCollector,
|
||||
) -> Result<(TransactionAccounts, TransactionCredits, TransactionRents)> {
|
||||
) -> Result<(TransactionAccounts, TransactionRents)> {
|
||||
// Copy all the accounts
|
||||
let message = tx.message();
|
||||
if tx.signatures.is_empty() && fee != 0 {
|
||||
|
@ -110,19 +117,17 @@ impl Accounts {
|
|||
// There is no way to predict what program will execute without an error
|
||||
// If a fee can pay for execution then the program will be scheduled
|
||||
let mut accounts: TransactionAccounts = vec![];
|
||||
let mut credits: TransactionCredits = vec![];
|
||||
let mut rents: TransactionRents = vec![];
|
||||
for key in message
|
||||
.account_keys
|
||||
.iter()
|
||||
.filter(|key| !message.program_ids().contains(&key))
|
||||
.filter(|key| !message.program_ids().contains(key))
|
||||
{
|
||||
let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key)
|
||||
.and_then(|(account, _)| rent_collector.update(account))
|
||||
.unwrap_or_default();
|
||||
|
||||
accounts.push(account);
|
||||
credits.push(0);
|
||||
rents.push(rent);
|
||||
}
|
||||
|
||||
|
@ -137,14 +142,14 @@ impl Accounts {
|
|||
Err(TransactionError::InsufficientFundsForFee)
|
||||
} else {
|
||||
accounts[0].lamports -= fee;
|
||||
Ok((accounts, credits, rents))
|
||||
Ok((accounts, rents))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_executable_accounts(
|
||||
storage: &AccountStorage,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
accounts_index: &AccountsIndex<AccountInfo>,
|
||||
program_id: &Pubkey,
|
||||
error_counters: &mut ErrorCounters,
|
||||
|
@ -189,7 +194,7 @@ impl Accounts {
|
|||
/// For each program_id in the transaction, load its loaders.
|
||||
fn load_loaders(
|
||||
storage: &AccountStorage,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
accounts_index: &AccountsIndex<AccountInfo>,
|
||||
tx: &Transaction,
|
||||
error_counters: &mut ErrorCounters,
|
||||
|
@ -217,7 +222,7 @@ impl Accounts {
|
|||
|
||||
pub fn load_accounts(
|
||||
&self,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
txs: &[Transaction],
|
||||
txs_iteration_order: Option<&[usize]>,
|
||||
lock_results: Vec<Result<()>>,
|
||||
|
@ -238,7 +243,7 @@ impl Accounts {
|
|||
.ok_or(TransactionError::BlockhashNotFound)?;
|
||||
|
||||
let fee = fee_calculator.calculate_fee(tx.message());
|
||||
let (accounts, credits, rents) = Self::load_tx_accounts(
|
||||
let (accounts, rents) = self.load_tx_accounts(
|
||||
&storage,
|
||||
ancestors,
|
||||
&accounts_index,
|
||||
|
@ -254,6 +259,7 @@ impl Accounts {
|
|||
tx,
|
||||
error_counters,
|
||||
)?;
|
||||
let credits = vec![0; accounts.len()];
|
||||
Ok((accounts, loaders, credits, rents))
|
||||
}
|
||||
(_, Err(e)) => Err(e),
|
||||
|
@ -264,24 +270,33 @@ impl Accounts {
|
|||
/// Slow because lock is held for 1 operation instead of many
|
||||
pub fn load_slow(
|
||||
&self,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
pubkey: &Pubkey,
|
||||
) -> Option<(Account, Fork)> {
|
||||
self.accounts_db
|
||||
) -> Option<(Account, Slot)> {
|
||||
let (mut account, slot) = self
|
||||
.accounts_db
|
||||
.load_slow(ancestors, pubkey)
|
||||
.filter(|(acc, _)| acc.lamports != 0)
|
||||
.unwrap_or((Account::default(), self.slot));
|
||||
|
||||
account.lamports += self.credit_only_pending_credits(pubkey);
|
||||
|
||||
if account.lamports > 0 {
|
||||
Some((account, slot))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// scans underlying accounts_db for this delta (fork) with a map function
|
||||
/// scans underlying accounts_db for this delta (slot) with a map function
|
||||
/// from StoredAccount to B
|
||||
/// returns only the latest/current version of B for this fork
|
||||
fn scan_fork<F, B>(&self, fork: Fork, func: F) -> Vec<B>
|
||||
/// returns only the latest/current version of B for this slot
|
||||
fn scan_slot<F, B>(&self, slot: Slot, func: F) -> Vec<B>
|
||||
where
|
||||
F: Fn(&StoredAccount) -> Option<B> + Send + Sync,
|
||||
B: Send + Default,
|
||||
{
|
||||
let accumulator: Vec<Vec<(Pubkey, u64, B)>> = self.accounts_db.scan_account_storage(
|
||||
fork,
|
||||
slot,
|
||||
|stored_account: &StoredAccount,
|
||||
_id: AppendVecId,
|
||||
accum: &mut Vec<(Pubkey, u64, B)>| {
|
||||
|
@ -306,8 +321,8 @@ impl Accounts {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn load_by_program_fork(&self, fork: Fork, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
|
||||
self.scan_fork(fork, |stored_account| {
|
||||
pub fn load_by_program_slot(&self, slot: Slot, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
|
||||
self.scan_slot(slot, |stored_account| {
|
||||
if stored_account.account_meta.owner == *program_id {
|
||||
Some((stored_account.meta.pubkey, stored_account.clone_account()))
|
||||
} else {
|
||||
|
@ -316,13 +331,13 @@ impl Accounts {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn verify_hash_internal_state(&self, fork: Fork, ancestors: &HashMap<Fork, usize>) -> bool {
|
||||
self.accounts_db.verify_hash_internal_state(fork, ancestors)
|
||||
pub fn verify_hash_internal_state(&self, slot: Slot, ancestors: &HashMap<Slot, usize>) -> bool {
|
||||
self.accounts_db.verify_hash_internal_state(slot, ancestors)
|
||||
}
|
||||
|
||||
pub fn load_by_program(
|
||||
&self,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
program_id: &Pubkey,
|
||||
) -> Vec<(Pubkey, Account)> {
|
||||
self.accounts_db.scan_accounts(
|
||||
|
@ -330,7 +345,7 @@ impl Accounts {
|
|||
|collector: &mut Vec<(Pubkey, Account)>, option| {
|
||||
if let Some(data) = option
|
||||
.filter(|(_, account, _)| account.owner == *program_id && account.lamports != 0)
|
||||
.map(|(pubkey, account, _fork)| (*pubkey, account))
|
||||
.map(|(pubkey, account, _slot)| (*pubkey, account))
|
||||
{
|
||||
collector.push(data)
|
||||
}
|
||||
|
@ -339,51 +354,88 @@ impl Accounts {
|
|||
}
|
||||
|
||||
/// Slow because lock is held for 1 operation instead of many
|
||||
pub fn store_slow(&self, fork: Fork, pubkey: &Pubkey, account: &Account) {
|
||||
self.accounts_db.store(fork, &[(pubkey, account)]);
|
||||
pub fn store_slow(&self, slot: Slot, pubkey: &Pubkey, account: &Account) {
|
||||
self.accounts_db.store(slot, &[(pubkey, account)]);
|
||||
}
|
||||
|
||||
fn get_read_access_credit_only<'a>(
|
||||
credit_only_locks: &'a RwLockReadGuard<Option<HashMap<Pubkey, CreditOnlyLock>>>,
|
||||
) -> Result<&'a HashMap<Pubkey, CreditOnlyLock>> {
|
||||
credit_only_locks
|
||||
.as_ref()
|
||||
.ok_or(TransactionError::AccountInUse)
|
||||
}
|
||||
|
||||
fn get_write_access_credit_only<'a>(
|
||||
credit_only_locks: &'a mut RwLockWriteGuard<Option<HashMap<Pubkey, CreditOnlyLock>>>,
|
||||
) -> Result<&'a mut HashMap<Pubkey, CreditOnlyLock>> {
|
||||
credit_only_locks
|
||||
.as_mut()
|
||||
.ok_or(TransactionError::AccountInUse)
|
||||
}
|
||||
|
||||
fn take_credit_only(
|
||||
credit_only_locks: &Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||
) -> Result<HashMap<Pubkey, CreditOnlyLock>> {
|
||||
let mut w_credit_only_locks = credit_only_locks.write().unwrap();
|
||||
fn take_credit_only(&self) -> Result<HashMap<Pubkey, CreditOnlyLock>> {
|
||||
let mut w_credit_only_locks = self.credit_only_locks.write().unwrap();
|
||||
w_credit_only_locks
|
||||
.take()
|
||||
.ok_or(TransactionError::AccountInUse)
|
||||
}
|
||||
|
||||
fn is_locked_credit_only(&self, key: &Pubkey) -> bool {
|
||||
self.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map_or(false, |locks| {
|
||||
locks
|
||||
.get(key)
|
||||
.map_or(false, |lock| *lock.lock_count.lock().unwrap() > 0)
|
||||
})
|
||||
}
|
||||
|
||||
fn credit_only_pending_credits(&self, key: &Pubkey) -> u64 {
|
||||
self.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map_or(0, |locks| {
|
||||
locks
|
||||
.get(key)
|
||||
.map_or(0, |lock| lock.credits.load(Ordering::Relaxed))
|
||||
})
|
||||
}
|
||||
|
||||
fn unlock_credit_only(&self, key: &Pubkey) {
|
||||
self.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|locks| {
|
||||
locks
|
||||
.get(key)
|
||||
.map(|lock| *lock.lock_count.lock().unwrap() -= 1)
|
||||
});
|
||||
}
|
||||
|
||||
fn lock_credit_only(&self, key: &Pubkey) -> bool {
|
||||
self.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map_or(false, |locks| {
|
||||
locks.get(key).map_or(false, |lock| {
|
||||
*lock.lock_count.lock().unwrap() += 1;
|
||||
true
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_credit_only(&self, key: &Pubkey, lock: CreditOnlyLock) -> bool {
|
||||
self.credit_only_locks
|
||||
.write()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.map_or(false, |locks| {
|
||||
assert!(locks.get(key).is_none());
|
||||
locks.insert(*key, lock);
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
fn lock_account(
|
||||
&self,
|
||||
locks: &mut HashSet<Pubkey>,
|
||||
credit_only_locks: &Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||
message: &Message,
|
||||
error_counters: &mut ErrorCounters,
|
||||
) -> Result<()> {
|
||||
let (credit_debit_keys, credit_only_keys) = message.get_account_keys_by_lock_type();
|
||||
|
||||
for k in credit_debit_keys.iter() {
|
||||
let r_credit_only_locks = credit_only_locks.read().unwrap();
|
||||
let r_credit_only_locks = Self::get_read_access_credit_only(&r_credit_only_locks)?;
|
||||
if locks.contains(k)
|
||||
|| r_credit_only_locks
|
||||
.get(&k)
|
||||
.map_or(false, |lock| *lock.lock_count.lock().unwrap() > 0)
|
||||
{
|
||||
if locks.contains(k) || self.is_locked_credit_only(k) {
|
||||
error_counters.account_in_use += 1;
|
||||
debug!("CD Account in use: {:?}", k);
|
||||
return Err(TransactionError::AccountInUse);
|
||||
|
@ -400,23 +452,15 @@ impl Accounts {
|
|||
for k in credit_debit_keys {
|
||||
locks.insert(*k);
|
||||
}
|
||||
let mut credit_only_writes: Vec<&Pubkey> = vec![];
|
||||
for k in credit_only_keys {
|
||||
let r_credit_only_locks = credit_only_locks.read().unwrap();
|
||||
let r_credit_only_locks = Self::get_read_access_credit_only(&r_credit_only_locks)?;
|
||||
if let Some(credit_only_lock) = r_credit_only_locks.get(&k) {
|
||||
*credit_only_lock.lock_count.lock().unwrap() += 1;
|
||||
} else {
|
||||
credit_only_writes.push(k);
|
||||
}
|
||||
}
|
||||
|
||||
let credit_only_writes: Vec<&&Pubkey> = credit_only_keys
|
||||
.iter()
|
||||
.filter(|k| !self.lock_credit_only(k))
|
||||
.collect();
|
||||
|
||||
for k in credit_only_writes.iter() {
|
||||
let mut w_credit_only_locks = credit_only_locks.write().unwrap();
|
||||
let w_credit_only_locks = Self::get_write_access_credit_only(&mut w_credit_only_locks)?;
|
||||
assert!(w_credit_only_locks.get(&k).is_none());
|
||||
w_credit_only_locks.insert(
|
||||
**k,
|
||||
self.insert_credit_only(
|
||||
*k,
|
||||
CreditOnlyLock {
|
||||
credits: AtomicU64::new(0),
|
||||
lock_count: Mutex::new(1),
|
||||
|
@ -427,12 +471,7 @@ impl Accounts {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn unlock_account(
|
||||
tx: &Transaction,
|
||||
result: &Result<()>,
|
||||
locks: &mut HashSet<Pubkey>,
|
||||
credit_only_locks: &Arc<RwLock<Option<HashMap<Pubkey, CreditOnlyLock>>>>,
|
||||
) {
|
||||
fn unlock_account(&self, tx: &Transaction, result: &Result<()>, locks: &mut HashSet<Pubkey>) {
|
||||
let (credit_debit_keys, credit_only_keys) = &tx.message().get_account_keys_by_lock_type();
|
||||
match result {
|
||||
Err(TransactionError::AccountInUse) => (),
|
||||
|
@ -441,23 +480,17 @@ impl Accounts {
|
|||
locks.remove(k);
|
||||
}
|
||||
for k in credit_only_keys {
|
||||
let r_credit_only_locks = credit_only_locks.read().unwrap();
|
||||
let locks = Self::get_read_access_credit_only(&r_credit_only_locks);
|
||||
if let Ok(locks) = locks {
|
||||
if let Some(lock) = locks.get(&k) {
|
||||
*lock.lock_count.lock().unwrap() -= 1;
|
||||
}
|
||||
}
|
||||
self.unlock_credit_only(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash_internal_state(&self, fork_id: Fork) -> Option<BankHash> {
|
||||
let fork_hashes = self.accounts_db.fork_hashes.read().unwrap();
|
||||
let fork_hash = fork_hashes.get(&fork_id)?;
|
||||
if fork_hash.0 {
|
||||
Some(fork_hash.1)
|
||||
pub fn hash_internal_state(&self, slot_id: Slot) -> Option<BankHash> {
|
||||
let slot_hashes = self.accounts_db.slot_hashes.read().unwrap();
|
||||
let slot_hash = slot_hashes.get(&slot_id)?;
|
||||
if slot_hash.0 {
|
||||
Some(slot_hash.1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -475,9 +508,8 @@ impl Accounts {
|
|||
let rv = OrderedIterator::new(txs, txs_iteration_order)
|
||||
.map(|tx| {
|
||||
let message = &tx.message();
|
||||
Self::lock_account(
|
||||
self.lock_account(
|
||||
&mut self.account_locks.lock().unwrap(),
|
||||
&self.credit_only_account_locks,
|
||||
&message,
|
||||
&mut error_counters,
|
||||
)
|
||||
|
@ -502,24 +534,21 @@ impl Accounts {
|
|||
results: &[Result<()>],
|
||||
) {
|
||||
let mut account_locks = self.account_locks.lock().unwrap();
|
||||
let credit_only_locks = self.credit_only_account_locks.clone();
|
||||
debug!("bank unlock accounts");
|
||||
|
||||
OrderedIterator::new(txs, txs_iteration_order)
|
||||
.zip(results.iter())
|
||||
.for_each(|(tx, result)| {
|
||||
Self::unlock_account(tx, result, &mut account_locks, &credit_only_locks)
|
||||
});
|
||||
.for_each(|(tx, result)| self.unlock_account(tx, result, &mut account_locks));
|
||||
}
|
||||
|
||||
pub fn has_accounts(&self, fork: Fork) -> bool {
|
||||
self.accounts_db.has_accounts(fork)
|
||||
pub fn has_accounts(&self, slot: Slot) -> bool {
|
||||
self.accounts_db.has_accounts(slot)
|
||||
}
|
||||
|
||||
/// Store the accounts into the DB
|
||||
pub fn store_accounts(
|
||||
&self,
|
||||
fork: Fork,
|
||||
slot: Slot,
|
||||
txs: &[Transaction],
|
||||
txs_iteration_order: Option<&[usize]>,
|
||||
res: &[Result<()>],
|
||||
|
@ -527,22 +556,22 @@ impl Accounts {
|
|||
) {
|
||||
let accounts_to_store =
|
||||
self.collect_accounts_to_store(txs, txs_iteration_order, res, loaded);
|
||||
self.accounts_db.store(fork, &accounts_to_store);
|
||||
self.accounts_db.store(slot, &accounts_to_store);
|
||||
}
|
||||
|
||||
/// Purge a fork if it is not a root
|
||||
/// Root forks cannot be purged
|
||||
pub fn purge_fork(&self, fork: Fork) {
|
||||
self.accounts_db.purge_fork(fork);
|
||||
/// Purge a slot if it is not a root
|
||||
/// Root slots cannot be purged
|
||||
pub fn purge_slot(&self, slot: Slot) {
|
||||
self.accounts_db.purge_slot(slot);
|
||||
}
|
||||
/// Add a fork to root. Root forks cannot be purged
|
||||
pub fn add_root(&self, fork: Fork) {
|
||||
self.accounts_db.add_root(fork)
|
||||
/// Add a slot to root. Root slots cannot be purged
|
||||
pub fn add_root(&self, slot: Slot) {
|
||||
self.accounts_db.add_root(slot)
|
||||
}
|
||||
|
||||
/// Commit remaining credit-only changes, regardless of reference count
|
||||
///
|
||||
/// We do a take() on `self.credit_only_account_locks` so that the hashmap is no longer
|
||||
/// We do a take() on `self.credit_only_locks` so that the hashmap is no longer
|
||||
/// available to be written to. This prevents any transactions from reinserting into the hashmap.
|
||||
/// Then there are then only 2 cases for interleaving with commit_credits and lock_accounts.
|
||||
/// Either:
|
||||
|
@ -550,32 +579,34 @@ impl Accounts {
|
|||
// so will fail the lock
|
||||
// 2) Any transaction that grabs a lock and then commit_credits clears the HashMap will find
|
||||
// the HashMap is None on unlock_accounts, and will perform a no-op.
|
||||
pub fn commit_credits(&self, ancestors: &HashMap<Fork, usize>, fork: Fork) {
|
||||
pub fn commit_credits(&self, ancestors: &HashMap<Slot, usize>, slot: Slot) {
|
||||
// Clear the credit only hashmap so that no further transactions can modify it
|
||||
let credit_only_account_locks = Self::take_credit_only(&self.credit_only_account_locks)
|
||||
let credit_only_locks = self
|
||||
.take_credit_only()
|
||||
.expect("Credit only locks didn't exist in commit_credits");
|
||||
self.store_credit_only_credits(credit_only_account_locks, ancestors, fork);
|
||||
self.store_credit_only_credits(credit_only_locks, ancestors, slot);
|
||||
}
|
||||
|
||||
/// Used only for tests to store credit-only accounts after every transaction
|
||||
pub fn commit_credits_unsafe(&self, ancestors: &HashMap<Fork, usize>, fork: Fork) {
|
||||
pub fn commit_credits_unsafe(&self, ancestors: &HashMap<Slot, usize>, slot: Slot) {
|
||||
// Clear the credit only hashmap so that no further transactions can modify it
|
||||
let mut w_credit_only_account_locks = self.credit_only_account_locks.write().unwrap();
|
||||
let w_credit_only_account_locks =
|
||||
Self::get_write_access_credit_only(&mut w_credit_only_account_locks)
|
||||
.expect("Credit only locks didn't exist in commit_credits");
|
||||
self.store_credit_only_credits(w_credit_only_account_locks.drain(), ancestors, fork);
|
||||
let mut credit_only_locks = self.credit_only_locks.write().unwrap();
|
||||
let credit_only_locks = credit_only_locks
|
||||
.as_mut()
|
||||
.expect("Credit only locks didn't exist in commit_credits");
|
||||
|
||||
self.store_credit_only_credits(credit_only_locks.drain(), ancestors, slot);
|
||||
}
|
||||
|
||||
fn store_credit_only_credits<I>(
|
||||
&self,
|
||||
credit_only_account_locks: I,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
fork: Fork,
|
||||
credit_only_locks: I,
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
slot: Slot,
|
||||
) where
|
||||
I: IntoIterator<Item = (Pubkey, CreditOnlyLock)>,
|
||||
{
|
||||
for (pubkey, lock) in credit_only_account_locks {
|
||||
for (pubkey, lock) in credit_only_locks {
|
||||
let lock_count = *lock.lock_count.lock().unwrap();
|
||||
if lock_count != 0 {
|
||||
warn!(
|
||||
|
@ -585,12 +616,12 @@ impl Accounts {
|
|||
}
|
||||
let credit = lock.credits.load(Ordering::Relaxed);
|
||||
if credit > 0 {
|
||||
let mut account = self
|
||||
let (mut account, _slot) = self
|
||||
.accounts_db
|
||||
.load_slow(ancestors, &pubkey)
|
||||
.map(|(account, _)| account)
|
||||
.unwrap_or_default();
|
||||
account.lamports += credit;
|
||||
self.store_slow(fork, &pubkey, &account);
|
||||
self.store_slow(slot, &pubkey, &account);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +657,7 @@ impl Accounts {
|
|||
}
|
||||
if *credit > 0 {
|
||||
// Increment credit-only account balance Atomic
|
||||
self.credit_only_account_locks
|
||||
self.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
|
@ -642,11 +673,11 @@ impl Accounts {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_test_accounts(accounts: &Accounts, pubkeys: &mut Vec<Pubkey>, num: usize, fork: u64) {
|
||||
pub fn create_test_accounts(accounts: &Accounts, pubkeys: &mut Vec<Pubkey>, num: usize, slot: u64) {
|
||||
for t in 0..num {
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let account = Account::new((t + 1) as u64, 0, &Account::default().owner);
|
||||
accounts.store_slow(fork, &pubkey, &account);
|
||||
accounts.store_slow(slot, &pubkey, &account);
|
||||
pubkeys.push(pubkey);
|
||||
}
|
||||
}
|
||||
|
@ -1124,7 +1155,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_by_program_fork() {
|
||||
fn test_load_by_program_slot() {
|
||||
let accounts = Accounts::new(None);
|
||||
|
||||
// Load accounts owned by various programs into AccountsDB
|
||||
|
@ -1138,11 +1169,11 @@ mod tests {
|
|||
let account2 = Account::new(1, 0, &Pubkey::new(&[3; 32]));
|
||||
accounts.store_slow(0, &pubkey2, &account2);
|
||||
|
||||
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[2; 32]));
|
||||
let loaded = accounts.load_by_program_slot(0, &Pubkey::new(&[2; 32]));
|
||||
assert_eq!(loaded.len(), 2);
|
||||
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[3; 32]));
|
||||
let loaded = accounts.load_by_program_slot(0, &Pubkey::new(&[3; 32]));
|
||||
assert_eq!(loaded, vec![(pubkey2, account2)]);
|
||||
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[4; 32]));
|
||||
let loaded = accounts.load_by_program_slot(0, &Pubkey::new(&[4; 32]));
|
||||
assert_eq!(loaded, vec![]);
|
||||
}
|
||||
|
||||
|
@ -1258,7 +1289,7 @@ mod tests {
|
|||
assert!(results0[0].is_ok());
|
||||
assert_eq!(
|
||||
*accounts
|
||||
.credit_only_account_locks
|
||||
.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
|
@ -1298,7 +1329,7 @@ mod tests {
|
|||
assert!(results1[1].is_err()); // Credit-only account (keypair1) cannot also be locked as credit-debit
|
||||
assert_eq!(
|
||||
*accounts
|
||||
.credit_only_account_locks
|
||||
.credit_only_locks
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
|
@ -1329,9 +1360,9 @@ mod tests {
|
|||
assert!(results2[0].is_ok()); // Now keypair1 account can be locked as credit-debit
|
||||
|
||||
// Check that credit-only credits are still cached in accounts struct
|
||||
let credit_only_account_locks = accounts.credit_only_account_locks.read().unwrap();
|
||||
let credit_only_account_locks = credit_only_account_locks.as_ref().unwrap();
|
||||
let keypair1_lock = credit_only_account_locks.get(&keypair1.pubkey());
|
||||
let credit_only_locks = accounts.credit_only_locks.read().unwrap();
|
||||
let credit_only_locks = credit_only_locks.as_ref().unwrap();
|
||||
let keypair1_lock = credit_only_locks.get(&keypair1.pubkey());
|
||||
assert!(keypair1_lock.is_some());
|
||||
assert_eq!(*keypair1_lock.unwrap().lock_count.lock().unwrap(), 0);
|
||||
}
|
||||
|
@ -1427,23 +1458,23 @@ mod tests {
|
|||
accounts.store_slow(0, &pubkey1, &account1);
|
||||
|
||||
{
|
||||
let mut credit_only_account_locks = accounts.credit_only_account_locks.write().unwrap();
|
||||
let credit_only_account_locks = credit_only_account_locks.as_mut().unwrap();
|
||||
credit_only_account_locks.insert(
|
||||
let mut credit_only_locks = accounts.credit_only_locks.write().unwrap();
|
||||
let credit_only_locks = credit_only_locks.as_mut().unwrap();
|
||||
credit_only_locks.insert(
|
||||
pubkey0,
|
||||
CreditOnlyLock {
|
||||
credits: AtomicU64::new(0),
|
||||
lock_count: Mutex::new(1),
|
||||
},
|
||||
);
|
||||
credit_only_account_locks.insert(
|
||||
credit_only_locks.insert(
|
||||
pubkey1,
|
||||
CreditOnlyLock {
|
||||
credits: AtomicU64::new(5),
|
||||
lock_count: Mutex::new(1),
|
||||
},
|
||||
);
|
||||
credit_only_account_locks.insert(
|
||||
credit_only_locks.insert(
|
||||
pubkey2,
|
||||
CreditOnlyLock {
|
||||
credits: AtomicU64::new(10),
|
||||
|
@ -1453,7 +1484,7 @@ mod tests {
|
|||
}
|
||||
|
||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||
accounts.commit_credits_unsafe(&ancestors, 0);
|
||||
accounts.commit_credits(&ancestors, 0);
|
||||
|
||||
// No change when CreditOnlyLock credits are 0
|
||||
assert_eq!(
|
||||
|
@ -1471,15 +1502,49 @@ mod tests {
|
|||
10
|
||||
);
|
||||
// Account locks should be cleared
|
||||
assert!(accounts.credit_only_locks.read().unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_credit_only_pending_credits() {
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let account = Account::new(1, 0, &Pubkey::default());
|
||||
|
||||
let accounts = Accounts::new(None);
|
||||
accounts.store_slow(0, &pubkey, &account);
|
||||
|
||||
accounts.insert_credit_only(
|
||||
&pubkey,
|
||||
CreditOnlyLock {
|
||||
credits: AtomicU64::new(10),
|
||||
lock_count: Mutex::new(1),
|
||||
},
|
||||
);
|
||||
|
||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||
assert_eq!(
|
||||
accounts.load_slow(&ancestors, &pubkey).unwrap().0.lamports,
|
||||
11
|
||||
);
|
||||
assert_eq!(
|
||||
accounts
|
||||
.credit_only_account_locks
|
||||
.read()
|
||||
.accounts_db
|
||||
.load_slow(&ancestors, &pubkey)
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.0
|
||||
.lamports,
|
||||
1
|
||||
);
|
||||
|
||||
accounts.commit_credits(&ancestors, 0);
|
||||
assert_eq!(
|
||||
accounts
|
||||
.accounts_db
|
||||
.load_slow(&ancestors, &pubkey)
|
||||
.unwrap()
|
||||
.len(),
|
||||
0
|
||||
.0
|
||||
.lamports,
|
||||
11
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1544,7 +1609,7 @@ mod tests {
|
|||
|
||||
let accounts = Accounts::new(None);
|
||||
{
|
||||
let mut credit_only_locks = accounts.credit_only_account_locks.write().unwrap();
|
||||
let mut credit_only_locks = accounts.credit_only_locks.write().unwrap();
|
||||
let credit_only_locks = credit_only_locks.as_mut().unwrap();
|
||||
credit_only_locks.insert(
|
||||
pubkey,
|
||||
|
@ -1567,7 +1632,7 @@ mod tests {
|
|||
.is_some());
|
||||
|
||||
// Ensure credit_only_lock reflects credits from both accounts: 2 + 3 = 5
|
||||
let credit_only_locks = accounts.credit_only_account_locks.read().unwrap();
|
||||
let credit_only_locks = accounts.credit_only_locks.read().unwrap();
|
||||
let credit_only_locks = credit_only_locks.as_ref().unwrap();
|
||||
assert_eq!(
|
||||
credit_only_locks
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,53 +2,53 @@ use solana_sdk::pubkey::Pubkey;
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
pub type Fork = u64;
|
||||
type ForkList<T> = Vec<(Fork, T)>;
|
||||
pub type Slot = u64;
|
||||
type SlotList<T> = Vec<(Slot, T)>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AccountsIndex<T> {
|
||||
pub account_maps: HashMap<Pubkey, RwLock<ForkList<T>>>,
|
||||
pub account_maps: HashMap<Pubkey, RwLock<SlotList<T>>>,
|
||||
|
||||
pub roots: HashSet<Fork>,
|
||||
pub roots: HashSet<Slot>,
|
||||
|
||||
//This value that needs to be stored to recover the index from AppendVec
|
||||
pub last_root: Fork,
|
||||
pub last_root: Slot,
|
||||
}
|
||||
|
||||
impl<T: Clone> AccountsIndex<T> {
|
||||
/// call func with every pubkey and index visible from a given set of ancestors
|
||||
pub fn scan_accounts<F>(&self, ancestors: &HashMap<Fork, usize>, mut func: F)
|
||||
pub fn scan_accounts<F>(&self, ancestors: &HashMap<Slot, usize>, mut func: F)
|
||||
where
|
||||
F: FnMut(&Pubkey, (&T, Fork)) -> (),
|
||||
F: FnMut(&Pubkey, (&T, Slot)) -> (),
|
||||
{
|
||||
for (pubkey, list) in self.account_maps.iter() {
|
||||
let list_r = list.read().unwrap();
|
||||
if let Some(index) = self.latest_fork(ancestors, &list_r) {
|
||||
if let Some(index) = self.latest_slot(ancestors, &list_r) {
|
||||
func(pubkey, (&list_r[index].1, list_r[index].0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn purge(&mut self, pubkey: &Pubkey) -> Vec<(Fork, T)> {
|
||||
pub fn purge(&mut self, pubkey: &Pubkey) -> Vec<(Slot, T)> {
|
||||
let mut list = self.account_maps.get(&pubkey).unwrap().write().unwrap();
|
||||
let reclaims = list
|
||||
.iter()
|
||||
.filter(|(fork, _)| self.is_root(*fork))
|
||||
.filter(|(slot, _)| self.is_root(*slot))
|
||||
.cloned()
|
||||
.collect();
|
||||
list.retain(|(fork, _)| !self.is_root(*fork));
|
||||
list.retain(|(slot, _)| !self.is_root(*slot));
|
||||
reclaims
|
||||
}
|
||||
|
||||
// find the latest fork and T in a list for a given ancestor
|
||||
// find the latest slot and T in a list for a given ancestor
|
||||
// returns index into 'list' if found, None if not.
|
||||
fn latest_fork(&self, ancestors: &HashMap<Fork, usize>, list: &[(Fork, T)]) -> Option<usize> {
|
||||
fn latest_slot(&self, ancestors: &HashMap<Slot, usize>, list: &[(Slot, T)]) -> Option<usize> {
|
||||
let mut max = 0;
|
||||
let mut rv = None;
|
||||
for (i, (fork, _t)) in list.iter().rev().enumerate() {
|
||||
if *fork >= max && (ancestors.get(fork).is_some() || self.is_root(*fork)) {
|
||||
for (i, (slot, _t)) in list.iter().rev().enumerate() {
|
||||
if *slot >= max && (ancestors.get(slot).is_some() || self.is_root(*slot)) {
|
||||
rv = Some((list.len() - 1) - i);
|
||||
max = *fork;
|
||||
max = *slot;
|
||||
}
|
||||
}
|
||||
rv
|
||||
|
@ -59,11 +59,11 @@ impl<T: Clone> AccountsIndex<T> {
|
|||
pub fn get(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
ancestors: &HashMap<Fork, usize>,
|
||||
) -> Option<(RwLockReadGuard<ForkList<T>>, usize)> {
|
||||
ancestors: &HashMap<Slot, usize>,
|
||||
) -> Option<(RwLockReadGuard<SlotList<T>>, usize)> {
|
||||
self.account_maps.get(pubkey).and_then(|list| {
|
||||
let lock = list.read().unwrap();
|
||||
if let Some(found_index) = self.latest_fork(ancestors, &lock) {
|
||||
if let Some(found_index) = self.latest_slot(ancestors, &lock) {
|
||||
Some((lock, found_index))
|
||||
} else {
|
||||
None
|
||||
|
@ -71,9 +71,9 @@ impl<T: Clone> AccountsIndex<T> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_max_root(roots: &HashSet<Fork>, fork_vec: &[(Fork, T)]) -> Fork {
|
||||
pub fn get_max_root(roots: &HashSet<Slot>, slot_vec: &[(Slot, T)]) -> Slot {
|
||||
let mut max_root = 0;
|
||||
for (f, _) in fork_vec.iter() {
|
||||
for (f, _) in slot_vec.iter() {
|
||||
if *f > max_root && roots.contains(f) {
|
||||
max_root = *f;
|
||||
}
|
||||
|
@ -83,16 +83,16 @@ impl<T: Clone> AccountsIndex<T> {
|
|||
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
fork: Fork,
|
||||
slot: Slot,
|
||||
pubkey: &Pubkey,
|
||||
account_info: T,
|
||||
reclaims: &mut Vec<(Fork, T)>,
|
||||
reclaims: &mut Vec<(Slot, T)>,
|
||||
) {
|
||||
let _fork_vec = self
|
||||
let _slot_vec = self
|
||||
.account_maps
|
||||
.entry(*pubkey)
|
||||
.or_insert_with(|| RwLock::new(Vec::with_capacity(32)));
|
||||
self.update(fork, pubkey, account_info, reclaims);
|
||||
self.update(slot, pubkey, account_info, reclaims);
|
||||
}
|
||||
|
||||
// Try to update an item in account_maps. If the account is not
|
||||
|
@ -101,30 +101,30 @@ impl<T: Clone> AccountsIndex<T> {
|
|||
// It returns None if the item is already present and thus successfully updated.
|
||||
pub fn update(
|
||||
&self,
|
||||
fork: Fork,
|
||||
slot: Slot,
|
||||
pubkey: &Pubkey,
|
||||
account_info: T,
|
||||
reclaims: &mut Vec<(Fork, T)>,
|
||||
reclaims: &mut Vec<(Slot, T)>,
|
||||
) -> Option<T> {
|
||||
let roots = &self.roots;
|
||||
if let Some(lock) = self.account_maps.get(pubkey) {
|
||||
let mut fork_vec = lock.write().unwrap();
|
||||
let mut slot_vec = lock.write().unwrap();
|
||||
// filter out old entries
|
||||
reclaims.extend(fork_vec.iter().filter(|(f, _)| *f == fork).cloned());
|
||||
fork_vec.retain(|(f, _)| *f != fork);
|
||||
reclaims.extend(slot_vec.iter().filter(|(f, _)| *f == slot).cloned());
|
||||
slot_vec.retain(|(f, _)| *f != slot);
|
||||
|
||||
// add the new entry
|
||||
fork_vec.push((fork, account_info));
|
||||
slot_vec.push((slot, account_info));
|
||||
|
||||
let max_root = Self::get_max_root(roots, &fork_vec);
|
||||
let max_root = Self::get_max_root(roots, &slot_vec);
|
||||
|
||||
reclaims.extend(
|
||||
fork_vec
|
||||
slot_vec
|
||||
.iter()
|
||||
.filter(|(fork, _)| Self::can_purge(max_root, *fork))
|
||||
.filter(|(slot, _)| Self::can_purge(max_root, *slot))
|
||||
.cloned(),
|
||||
);
|
||||
fork_vec.retain(|(fork, _)| !Self::can_purge(max_root, *fork));
|
||||
slot_vec.retain(|(slot, _)| !Self::can_purge(max_root, *slot));
|
||||
|
||||
None
|
||||
} else {
|
||||
|
@ -132,38 +132,38 @@ impl<T: Clone> AccountsIndex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_index(&mut self, fork: Fork, pubkey: &Pubkey, account_info: T) {
|
||||
pub fn add_index(&mut self, slot: Slot, pubkey: &Pubkey, account_info: T) {
|
||||
let entry = self
|
||||
.account_maps
|
||||
.entry(*pubkey)
|
||||
.or_insert_with(|| RwLock::new(vec![]));
|
||||
entry.write().unwrap().push((fork, account_info));
|
||||
entry.write().unwrap().push((slot, account_info));
|
||||
}
|
||||
|
||||
pub fn is_purged(&self, fork: Fork) -> bool {
|
||||
fork < self.last_root
|
||||
pub fn is_purged(&self, slot: Slot) -> bool {
|
||||
slot < self.last_root
|
||||
}
|
||||
|
||||
pub fn can_purge(max_root: Fork, fork: Fork) -> bool {
|
||||
fork < max_root
|
||||
pub fn can_purge(max_root: Slot, slot: Slot) -> bool {
|
||||
slot < max_root
|
||||
}
|
||||
|
||||
pub fn is_root(&self, fork: Fork) -> bool {
|
||||
self.roots.contains(&fork)
|
||||
pub fn is_root(&self, slot: Slot) -> bool {
|
||||
self.roots.contains(&slot)
|
||||
}
|
||||
|
||||
pub fn add_root(&mut self, fork: Fork) {
|
||||
pub fn add_root(&mut self, slot: Slot) {
|
||||
assert!(
|
||||
(self.last_root == 0 && fork == 0) || (fork >= self.last_root),
|
||||
(self.last_root == 0 && slot == 0) || (slot >= self.last_root),
|
||||
"new roots must be increasing"
|
||||
);
|
||||
self.last_root = fork;
|
||||
self.roots.insert(fork);
|
||||
self.last_root = slot;
|
||||
self.roots.insert(slot);
|
||||
}
|
||||
/// Remove the fork when the storage for the fork is freed
|
||||
/// Accounts no longer reference this fork.
|
||||
pub fn cleanup_dead_fork(&mut self, fork: Fork) {
|
||||
self.roots.remove(&fork);
|
||||
/// Remove the slot when the storage for the slot is freed
|
||||
/// Accounts no longer reference this slot.
|
||||
pub fn cleanup_dead_slot(&mut self, slot: Slot) {
|
||||
self.roots.remove(&slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,18 +290,18 @@ mod tests {
|
|||
let mut index = AccountsIndex::<bool>::default();
|
||||
index.add_root(0);
|
||||
index.add_root(1);
|
||||
index.cleanup_dead_fork(0);
|
||||
index.cleanup_dead_slot(0);
|
||||
assert!(index.is_root(1));
|
||||
assert!(!index.is_root(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cleanup_last() {
|
||||
//this behavior might be undefined, clean up should only occur on older forks
|
||||
//this behavior might be undefined, clean up should only occur on older slots
|
||||
let mut index = AccountsIndex::<bool>::default();
|
||||
index.add_root(0);
|
||||
index.add_root(1);
|
||||
index.cleanup_dead_fork(1);
|
||||
index.cleanup_dead_slot(1);
|
||||
assert!(!index.is_root(1));
|
||||
assert!(index.is_root(0));
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_new_fork() {
|
||||
fn test_update_new_slot() {
|
||||
solana_logger::setup();
|
||||
let key = Keypair::new();
|
||||
let mut index = AccountsIndex::<bool>::default();
|
||||
|
@ -344,7 +344,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_gc_purged_fork() {
|
||||
fn test_update_gc_purged_slot() {
|
||||
let key = Keypair::new();
|
||||
let mut index = AccountsIndex::<bool>::default();
|
||||
let mut gc = Vec::new();
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
use crate::{
|
||||
accounts::{Accounts, TransactionLoadResult},
|
||||
accounts_db::{AccountStorageEntry, AccountsDBSerialize, AppendVecId, ErrorCounters},
|
||||
accounts_index::Fork,
|
||||
blockhash_queue::BlockhashQueue,
|
||||
message_processor::{MessageProcessor, ProcessInstruction},
|
||||
rent_collector::RentCollector,
|
||||
|
@ -1318,7 +1317,7 @@ impl Bank {
|
|||
self.rc
|
||||
.accounts
|
||||
.load_slow(&self.ancestors, pubkey)
|
||||
.map(|(account, _)| account)
|
||||
.map(|(acc, _slot)| acc)
|
||||
}
|
||||
|
||||
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
|
||||
|
@ -1333,10 +1332,10 @@ impl Bank {
|
|||
) -> Vec<(Pubkey, Account)> {
|
||||
self.rc
|
||||
.accounts
|
||||
.load_by_program_fork(self.slot(), program_id)
|
||||
.load_by_program_slot(self.slot(), program_id)
|
||||
}
|
||||
|
||||
pub fn get_account_modified_since_parent(&self, pubkey: &Pubkey) -> Option<(Account, Fork)> {
|
||||
pub fn get_account_modified_since_parent(&self, pubkey: &Pubkey) -> Option<(Account, Slot)> {
|
||||
let just_self: HashMap<u64, usize> = vec![(self.slot(), 0)].into_iter().collect();
|
||||
self.rc.accounts.load_slow(&just_self, pubkey)
|
||||
}
|
||||
|
@ -1617,8 +1616,8 @@ impl Bank {
|
|||
|
||||
impl Drop for Bank {
|
||||
fn drop(&mut self) {
|
||||
// For root forks this is a noop
|
||||
self.rc.accounts.purge_fork(self.slot());
|
||||
// For root slots this is a noop
|
||||
self.rc.accounts.purge_slot(self.slot());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1796,7 +1795,7 @@ mod tests {
|
|||
for _ in 0..10 {
|
||||
let blockhash = bank.last_blockhash();
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let tx = system_transaction::transfer_now(&mint_keypair, &pubkey, 0, blockhash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &pubkey, 0, blockhash);
|
||||
bank.process_transaction(&tx).unwrap();
|
||||
bank.squash();
|
||||
bank = Arc::new(new_from_parent(&bank));
|
||||
|
@ -1809,13 +1808,13 @@ mod tests {
|
|||
let bank0 = Arc::new(new_from_parent(&bank));
|
||||
let blockhash = bank.last_blockhash();
|
||||
let keypair = Keypair::new();
|
||||
let tx = system_transaction::transfer_now(&mint_keypair, &keypair.pubkey(), 10, blockhash);
|
||||
let tx = system_transaction::transfer(&mint_keypair, &keypair.pubkey(), 10, blockhash);
|
||||
bank0.process_transaction(&tx).unwrap();
|
||||
|
||||
let bank1 = Arc::new(new_from_parent(&bank0));
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let blockhash = bank.last_blockhash();
|
||||
let tx = system_transaction::transfer_now(&keypair, &pubkey, 10, blockhash);
|
||||
let tx = system_transaction::transfer(&keypair, &pubkey, 10, blockhash);
|
||||
bank1.process_transaction(&tx).unwrap();
|
||||
|
||||
assert_eq!(bank0.get_account(&keypair.pubkey()).unwrap().lamports, 10);
|
||||
|
@ -1941,12 +1940,8 @@ mod tests {
|
|||
let dest = Keypair::new();
|
||||
|
||||
// source with 0 program context
|
||||
let tx = system_transaction::transfer_now(
|
||||
&mint_keypair,
|
||||
&dest.pubkey(),
|
||||
2,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
let tx =
|
||||
system_transaction::transfer(&mint_keypair, &dest.pubkey(), 2, genesis_block.hash());
|
||||
let signature = tx.signatures[0];
|
||||
assert!(!bank.has_signature(&signature));
|
||||
|
||||
|
@ -2230,18 +2225,10 @@ mod tests {
|
|||
let (genesis_block, mint_keypair) = create_genesis_block(2);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let keypair = Keypair::new();
|
||||
let tx0 = system_transaction::transfer_now(
|
||||
&mint_keypair,
|
||||
&keypair.pubkey(),
|
||||
2,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
let tx1 = system_transaction::transfer_now(
|
||||
&keypair,
|
||||
&mint_keypair.pubkey(),
|
||||
1,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
let tx0 =
|
||||
system_transaction::transfer(&mint_keypair, &keypair.pubkey(), 2, genesis_block.hash());
|
||||
let tx1 =
|
||||
system_transaction::transfer(&keypair, &mint_keypair.pubkey(), 1, genesis_block.hash());
|
||||
let txs = vec![tx0, tx1];
|
||||
let results = bank.process_transactions(&txs);
|
||||
assert!(results[1].is_err());
|
||||
|
@ -2272,9 +2259,6 @@ mod tests {
|
|||
system_transaction::transfer(&payer1, &recipient.pubkey(), 1, genesis_block.hash());
|
||||
let txs = vec![tx0, tx1, tx2];
|
||||
let results = bank.process_transactions(&txs);
|
||||
bank.rc
|
||||
.accounts
|
||||
.commit_credits_unsafe(&bank.ancestors, bank.slot());
|
||||
|
||||
// If multiple transactions attempt to deposit into the same account, they should succeed,
|
||||
// since System Transfer `To` accounts are given credit-only handling
|
||||
|
@ -2293,9 +2277,6 @@ mod tests {
|
|||
system_transaction::transfer(&recipient, &payer0.pubkey(), 1, genesis_block.hash());
|
||||
let txs = vec![tx0, tx1];
|
||||
let results = bank.process_transactions(&txs);
|
||||
bank.rc
|
||||
.accounts
|
||||
.commit_credits_unsafe(&bank.ancestors, bank.slot());
|
||||
// However, an account may not be locked as credit-only and credit-debit at the same time.
|
||||
assert_eq!(results[0], Ok(()));
|
||||
assert_eq!(results[1], Err(TransactionError::AccountInUse));
|
||||
|
@ -2308,12 +2289,8 @@ mod tests {
|
|||
let alice = Keypair::new();
|
||||
let bob = Keypair::new();
|
||||
|
||||
let tx1 = system_transaction::transfer_now(
|
||||
&mint_keypair,
|
||||
&alice.pubkey(),
|
||||
1,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
let tx1 =
|
||||
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, genesis_block.hash());
|
||||
let pay_alice = vec![tx1];
|
||||
|
||||
let lock_result = bank.prepare_batch(&pay_alice, None);
|
||||
|
@ -3112,12 +3089,8 @@ mod tests {
|
|||
|
||||
let keypair1 = Keypair::new();
|
||||
let keypair2 = Keypair::new();
|
||||
let fail_tx = system_transaction::transfer_now(
|
||||
&keypair1,
|
||||
&keypair2.pubkey(),
|
||||
1,
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let fail_tx =
|
||||
system_transaction::transfer(&keypair1, &keypair2.pubkey(), 1, bank.last_blockhash());
|
||||
|
||||
// Should fail with TransactionError::AccountNotFound, which means
|
||||
// the account which this tx operated on will not be committed. Thus
|
||||
|
|
|
@ -501,7 +501,7 @@ mod tests {
|
|||
let key = KeypairNative::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
let serialized = serialize(&tx).unwrap();
|
||||
let tx = Box::new(Transaction::from_native(tx));
|
||||
let tx = Box::into_raw(tx);
|
||||
|
@ -520,7 +520,7 @@ mod tests {
|
|||
let key = KeypairNative::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let tx = system_transaction::transfer_now(&key, &to, 50, blockhash);
|
||||
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
let serialized = serialize(&tx).unwrap();
|
||||
let deserialized;
|
||||
unsafe {
|
||||
|
@ -559,7 +559,7 @@ mod tests {
|
|||
let key_native = KeypairNative::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let mut tx_native = system_transaction::transfer_now(&key_native, &to, 50, blockhash);
|
||||
let mut tx_native = system_transaction::transfer(&key_native, &to, 50, blockhash);
|
||||
let tx = Box::into_raw(Box::new(Transaction::from_native(tx_native.clone())));
|
||||
let key = Keypair::from_native(&key_native);
|
||||
let tx2;
|
||||
|
|
|
@ -24,10 +24,10 @@ pub struct EpochSchedule {
|
|||
/// whether epochs start short and grow
|
||||
pub warmup: bool,
|
||||
|
||||
/// basically: log2(slots_per_epoch) - log2(MINIMUM_SLOT_LEN)
|
||||
/// basically: log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
|
||||
pub first_normal_epoch: Epoch,
|
||||
|
||||
/// basically: 2.pow(first_normal_epoch) - MINIMUM_SLOT_LEN
|
||||
/// basically: MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)
|
||||
pub first_normal_slot: Slot,
|
||||
}
|
||||
|
||||
|
|
|
@ -69,19 +69,6 @@ pub fn create_account(
|
|||
)
|
||||
}
|
||||
|
||||
/// transfer with to as credit-debit
|
||||
pub fn transfer_now(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*from_pubkey, true),
|
||||
AccountMeta::new(*to_pubkey, false),
|
||||
];
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::Transfer { lamports },
|
||||
account_metas,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn assign(from_pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
||||
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
||||
Instruction::new(
|
||||
|
|
|
@ -24,19 +24,6 @@ pub fn create_account(
|
|||
Transaction::new_signed_instructions(&[from_keypair], instructions, recent_blockhash)
|
||||
}
|
||||
|
||||
/// Create and sign new system_instruction::Transfer transaction, but don't use a CO "to"
|
||||
pub fn transfer_now(
|
||||
from_keypair: &Keypair,
|
||||
to: &Pubkey,
|
||||
lamports: u64,
|
||||
recent_blockhash: Hash,
|
||||
) -> Transaction {
|
||||
let from_pubkey = from_keypair.pubkey();
|
||||
let transfer_instruction = system_instruction::transfer_now(&from_pubkey, to, lamports);
|
||||
let instructions = vec![transfer_instruction];
|
||||
Transaction::new_signed_instructions(&[from_keypair], instructions, recent_blockhash)
|
||||
}
|
||||
|
||||
/// Create and sign new system_instruction::Assign transaction
|
||||
pub fn assign(from_keypair: &Keypair, recent_blockhash: Hash, program_id: &Pubkey) -> Transaction {
|
||||
let from_pubkey = from_keypair.pubkey();
|
||||
|
|
Loading…
Reference in New Issue