Register a new last_id once per slot
This commit is contained in:
parent
61beb42797
commit
d5de5bec4f
|
@ -23,11 +23,12 @@ use solana_sdk::signature::{Keypair, Signature};
|
||||||
use solana_sdk::storage_program;
|
use solana_sdk::storage_program;
|
||||||
use solana_sdk::system_program;
|
use solana_sdk::system_program;
|
||||||
use solana_sdk::system_transaction::SystemTransaction;
|
use solana_sdk::system_transaction::SystemTransaction;
|
||||||
use solana_sdk::timing::{duration_as_us, MAX_RECENT_TICK_HASHES, NUM_TICKS_PER_SECOND};
|
use solana_sdk::timing::{duration_as_us, MAX_RECENT_BLOCK_HASHES, NUM_TICKS_PER_SECOND};
|
||||||
use solana_sdk::token_program;
|
use solana_sdk::token_program;
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
use solana_sdk::vote_program::{self, VoteState};
|
use solana_sdk::vote_program::{self, VoteState};
|
||||||
use std::result;
|
use std::result;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ pub struct Bank {
|
||||||
status_cache: RwLock<BankStatusCache>,
|
status_cache: RwLock<BankStatusCache>,
|
||||||
|
|
||||||
/// FIFO queue of `last_id` items
|
/// FIFO queue of `last_id` items
|
||||||
tick_hash_queue: RwLock<HashQueue>,
|
block_hash_queue: RwLock<HashQueue>,
|
||||||
|
|
||||||
/// Previous checkpoint of this bank
|
/// Previous checkpoint of this bank
|
||||||
parent: RwLock<Option<Arc<Bank>>>,
|
parent: RwLock<Option<Arc<Bank>>>,
|
||||||
|
@ -121,7 +122,7 @@ pub struct Bank {
|
||||||
|
|
||||||
impl Default for HashQueue {
|
impl Default for HashQueue {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(MAX_RECENT_TICK_HASHES)
|
Self::new(MAX_RECENT_BLOCK_HASHES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ impl Bank {
|
||||||
parent.freeze();
|
parent.freeze();
|
||||||
|
|
||||||
let mut bank = Self::default();
|
let mut bank = Self::default();
|
||||||
bank.tick_hash_queue = RwLock::new(parent.tick_hash_queue.read().unwrap().clone());
|
bank.block_hash_queue = RwLock::new(parent.block_hash_queue.read().unwrap().clone());
|
||||||
bank.tick_height
|
bank.tick_height
|
||||||
.store(parent.tick_height.load(Ordering::SeqCst), Ordering::SeqCst);
|
.store(parent.tick_height.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
bank.ticks_per_slot = parent.ticks_per_slot;
|
bank.ticks_per_slot = parent.ticks_per_slot;
|
||||||
|
@ -263,7 +264,7 @@ impl Bank {
|
||||||
&bootstrap_leader_vote_account,
|
&bootstrap_leader_vote_account,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.tick_hash_queue
|
self.block_hash_queue
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.genesis_hash(&genesis_block.hash());
|
.genesis_hash(&genesis_block.hash());
|
||||||
|
@ -289,7 +290,7 @@ impl Bank {
|
||||||
|
|
||||||
/// Return the last entry ID registered.
|
/// Return the last entry ID registered.
|
||||||
pub fn last_id(&self) -> Hash {
|
pub fn last_id(&self) -> Hash {
|
||||||
self.tick_hash_queue.read().unwrap().last_hash()
|
self.block_hash_queue.read().unwrap().last_hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forget all signatures. Useful for benchmarking.
|
/// Forget all signatures. Useful for benchmarking.
|
||||||
|
@ -324,8 +325,7 @@ impl Bank {
|
||||||
slots_and_stakes.sort_by(|a, b| a.0.cmp(&b.0));
|
slots_and_stakes.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
let max_slot = self.slot_height();
|
let max_slot = self.slot_height();
|
||||||
let min_slot =
|
let min_slot = max_slot.saturating_sub(MAX_RECENT_BLOCK_HASHES as u64);
|
||||||
max_slot.saturating_sub(MAX_RECENT_TICK_HASHES as u64 / self.ticks_per_slot());
|
|
||||||
|
|
||||||
let mut total_stake = 0;
|
let mut total_stake = 0;
|
||||||
for (slot, stake) in slots_and_stakes.iter() {
|
for (slot, stake) in slots_and_stakes.iter() {
|
||||||
|
@ -333,10 +333,10 @@ impl Bank {
|
||||||
total_stake += stake;
|
total_stake += stake;
|
||||||
if total_stake > supermajority_stake {
|
if total_stake > supermajority_stake {
|
||||||
return self
|
return self
|
||||||
.tick_hash_queue
|
.block_hash_queue
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.hash_height_to_timestamp(slot * self.ticks_per_slot());
|
.hash_height_to_timestamp(*slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,12 +360,12 @@ impl Bank {
|
||||||
self.tick_height.fetch_add(1, Ordering::SeqCst);
|
self.tick_height.fetch_add(1, Ordering::SeqCst);
|
||||||
self.tick_height.load(Ordering::SeqCst) as u64
|
self.tick_height.load(Ordering::SeqCst) as u64
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
|
||||||
let mut tick_hash_queue = self.tick_hash_queue.write().unwrap();
|
|
||||||
inc_new_counter_info!("bank-register_tick-registered", 1);
|
inc_new_counter_info!("bank-register_tick-registered", 1);
|
||||||
tick_hash_queue.register_hash(hash);
|
|
||||||
assert_eq!(current_tick_height, tick_hash_queue.hash_height())
|
// Register a new block hash if at the last tick in the slot
|
||||||
|
if current_tick_height % self.ticks_per_slot == self.ticks_per_slot - 1 {
|
||||||
|
let mut block_hash_queue = self.block_hash_queue.write().unwrap();
|
||||||
|
block_hash_queue.register_hash(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_tick_height % NUM_TICKS_PER_SECOND == 0 {
|
if current_tick_height % NUM_TICKS_PER_SECOND == 0 {
|
||||||
|
@ -411,7 +411,7 @@ impl Bank {
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> Vec<Result<()>> {
|
) -> Vec<Result<()>> {
|
||||||
let hash_queue = self.tick_hash_queue.read().unwrap();
|
let hash_queue = self.block_hash_queue.read().unwrap();
|
||||||
txs.iter()
|
txs.iter()
|
||||||
.zip(lock_results.into_iter())
|
.zip(lock_results.into_iter())
|
||||||
.map(|(tx, lock_res)| {
|
.map(|(tx, lock_res)| {
|
||||||
|
@ -617,7 +617,7 @@ impl Bank {
|
||||||
pub fn process_transactions(&self, txs: &[Transaction]) -> Vec<Result<()>> {
|
pub fn process_transactions(&self, txs: &[Transaction]) -> Vec<Result<()>> {
|
||||||
let lock_results = self.lock_accounts(txs);
|
let lock_results = self.lock_accounts(txs);
|
||||||
let results =
|
let results =
|
||||||
self.load_execute_and_commit_transactions(txs, lock_results, MAX_RECENT_TICK_HASHES);
|
self.load_execute_and_commit_transactions(txs, lock_results, MAX_RECENT_BLOCK_HASHES);
|
||||||
self.unlock_accounts(txs, &results);
|
self.unlock_accounts(txs, &results);
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
@ -747,7 +747,7 @@ impl Bank {
|
||||||
pub fn tick_height(&self) -> u64 {
|
pub fn tick_height(&self) -> u64 {
|
||||||
// tick_height is using an AtomicUSize because AtomicU64 is not yet a stable API.
|
// tick_height is using an AtomicUSize because AtomicU64 is not yet a stable API.
|
||||||
// Until we can switch to AtomicU64, fail if usize is not the same as u64
|
// Until we can switch to AtomicU64, fail if usize is not the same as u64
|
||||||
assert_eq!(std::usize::MAX, 0xFFFFFFFFFFFFFFFF);
|
assert_eq!(std::usize::MAX, 0xFFFF_FFFF_FFFF_FFFF);
|
||||||
|
|
||||||
self.tick_height.load(Ordering::SeqCst) as u64
|
self.tick_height.load(Ordering::SeqCst) as u64
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1229,7 @@ mod tests {
|
||||||
let results_alice = bank.load_execute_and_commit_transactions(
|
let results_alice = bank.load_execute_and_commit_transactions(
|
||||||
&pay_alice,
|
&pay_alice,
|
||||||
lock_result,
|
lock_result,
|
||||||
MAX_RECENT_TICK_HASHES,
|
MAX_RECENT_BLOCK_HASHES,
|
||||||
);
|
);
|
||||||
assert_eq!(results_alice[0], Ok(()));
|
assert_eq!(results_alice[0], Ok(()));
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ impl HashQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn hash_height(&self) -> u64 {
|
pub fn hash_height(&self) -> u64 {
|
||||||
self.hash_height
|
self.hash_height
|
||||||
}
|
}
|
||||||
|
@ -78,7 +79,6 @@ impl HashQueue {
|
||||||
self.entries
|
self.entries
|
||||||
.retain(|_, entry| hash_height - entry.hash_height <= max_entries as u64);
|
.retain(|_, entry| hash_height - entry.hash_height <= max_entries as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.entries.insert(
|
self.entries.insert(
|
||||||
*hash,
|
*hash,
|
||||||
HashQueueEntry {
|
HashQueueEntry {
|
||||||
|
|
|
@ -18,6 +18,8 @@ pub const DEFAULT_SLOTS_PER_EPOCH: u64 = 64;
|
||||||
pub const MAX_HASH_AGE_IN_SECONDS: usize = 120;
|
pub const MAX_HASH_AGE_IN_SECONDS: usize = 120;
|
||||||
|
|
||||||
pub const MAX_RECENT_TICK_HASHES: usize = NUM_TICKS_PER_SECOND as usize * MAX_HASH_AGE_IN_SECONDS;
|
pub const MAX_RECENT_TICK_HASHES: usize = NUM_TICKS_PER_SECOND as usize * MAX_HASH_AGE_IN_SECONDS;
|
||||||
|
pub const MAX_RECENT_BLOCK_HASHES: usize =
|
||||||
|
MAX_RECENT_TICK_HASHES / (DEFAULT_TICKS_PER_SLOT as usize);
|
||||||
|
|
||||||
pub fn duration_as_us(d: &Duration) -> u64 {
|
pub fn duration_as_us(d: &Duration) -> u64 {
|
||||||
(d.as_secs() * 1000 * 1000) + (u64::from(d.subsec_nanos()) / 1_000)
|
(d.as_secs() * 1000 * 1000) + (u64::from(d.subsec_nanos()) / 1_000)
|
||||||
|
|
|
@ -391,7 +391,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_banking_stage_tick() {
|
fn test_banking_stage_tick() {
|
||||||
let (genesis_block, _mint_keypair) = GenesisBlock::new(2);
|
let (mut genesis_block, _mint_keypair) = GenesisBlock::new(2);
|
||||||
|
genesis_block.ticks_per_slot = 4;
|
||||||
let bank = Arc::new(Bank::new(&genesis_block));
|
let bank = Arc::new(Bank::new(&genesis_block));
|
||||||
let start_hash = bank.last_id();
|
let start_hash = bank.last_id();
|
||||||
let (verified_sender, verified_receiver) = channel();
|
let (verified_sender, verified_receiver) = channel();
|
||||||
|
@ -400,17 +401,17 @@ mod tests {
|
||||||
&bank,
|
&bank,
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
verified_receiver,
|
verified_receiver,
|
||||||
DEFAULT_TICKS_PER_SLOT,
|
genesis_block.ticks_per_slot - 1,
|
||||||
genesis_block.bootstrap_leader_id,
|
genesis_block.bootstrap_leader_id,
|
||||||
);
|
);
|
||||||
sleep(Duration::from_millis(500));
|
sleep(Duration::from_millis(600));
|
||||||
drop(verified_sender);
|
drop(verified_sender);
|
||||||
|
|
||||||
let entries: Vec<_> = entry_receiver
|
let entries: Vec<_> = entry_receiver
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|x| x.into_iter().map(|e| e.0))
|
.flat_map(|x| x.into_iter().map(|e| e.0))
|
||||||
.collect();
|
.collect();
|
||||||
assert!(entries.len() != 0);
|
assert_eq!(entries.len(), genesis_block.ticks_per_slot as usize - 1);
|
||||||
assert!(entries.verify(&start_hash));
|
assert!(entries.verify(&start_hash));
|
||||||
assert_eq!(entries[entries.len() - 1].hash, bank.last_id());
|
assert_eq!(entries[entries.len() - 1].hash, bank.last_id());
|
||||||
banking_stage.join().unwrap();
|
banking_stage.join().unwrap();
|
||||||
|
|
|
@ -426,11 +426,19 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_process_empty_entry_is_registered() {
|
fn test_process_empty_entry_is_registered() {
|
||||||
|
solana_logger::setup();
|
||||||
|
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
|
let (genesis_block, mint_keypair) = GenesisBlock::new(2);
|
||||||
let bank = Bank::new(&genesis_block);
|
let bank = Bank::new(&genesis_block);
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let entry = next_entry(&genesis_block.hash(), 1, vec![]);
|
let slot_entries = create_ticks(genesis_block.ticks_per_slot - 1, genesis_block.hash());
|
||||||
let tx = SystemTransaction::new_account(&mint_keypair, keypair.pubkey(), 1, entry.hash, 0);
|
let tx = SystemTransaction::new_account(
|
||||||
|
&mint_keypair,
|
||||||
|
keypair.pubkey(),
|
||||||
|
1,
|
||||||
|
slot_entries.last().unwrap().hash,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
// First, ensure the TX is rejected because of the unregistered last ID
|
// First, ensure the TX is rejected because of the unregistered last ID
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -439,19 +447,20 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Now ensure the TX is accepted despite pointing to the ID of an empty entry.
|
// Now ensure the TX is accepted despite pointing to the ID of an empty entry.
|
||||||
par_process_entries(&bank, &[entry]).unwrap();
|
par_process_entries(&bank, &slot_entries).unwrap();
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_process_ledger_simple() {
|
fn test_process_ledger_simple() {
|
||||||
|
solana_logger::setup();
|
||||||
let leader_pubkey = Keypair::new().pubkey();
|
let leader_pubkey = Keypair::new().pubkey();
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader_pubkey, 50);
|
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader_pubkey, 50);
|
||||||
let (ledger_path, last_id) = create_new_tmp_ledger!(&genesis_block);
|
let (ledger_path, mut last_entry_hash) = create_new_tmp_ledger!(&genesis_block);
|
||||||
debug!("ledger_path: {:?}", ledger_path);
|
debug!("ledger_path: {:?}", ledger_path);
|
||||||
|
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
let mut last_entry_hash = last_id;
|
let last_id = genesis_block.hash();
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
// Transfer one token from the mint to a random account
|
// Transfer one token from the mint to a random account
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
|
@ -522,9 +531,10 @@ mod tests {
|
||||||
let bank = Bank::new(&genesis_block);
|
let bank = Bank::new(&genesis_block);
|
||||||
|
|
||||||
// ensure bank can process a tick
|
// ensure bank can process a tick
|
||||||
|
assert_eq!(bank.tick_height(), 0);
|
||||||
let tick = next_entry(&genesis_block.hash(), 1, vec![]);
|
let tick = next_entry(&genesis_block.hash(), 1, vec![]);
|
||||||
assert_eq!(par_process_entries(&bank, &[tick.clone()]), Ok(()));
|
assert_eq!(par_process_entries(&bank, &[tick.clone()]), Ok(()));
|
||||||
assert_eq!(bank.last_id(), tick.hash);
|
assert_eq!(bank.tick_height(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -652,12 +662,15 @@ mod tests {
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||||
|
|
||||||
let last_id = bank.last_id();
|
let last_id = bank.last_id();
|
||||||
|
while last_id == bank.last_id() {
|
||||||
|
bank.register_tick(&Hash::default());
|
||||||
|
}
|
||||||
|
|
||||||
// ensure bank can process 2 entries that do not have a common account and tick is registered
|
// ensure bank can process 2 entries that do not have a common account and tick is registered
|
||||||
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, bank.last_id(), 0);
|
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, last_id, 0);
|
||||||
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
let entry_1 = next_entry(&last_id, 1, vec![tx]);
|
||||||
let tick = next_entry(&entry_1.hash, 1, vec![]);
|
let tick = next_entry(&entry_1.hash, 1, vec![]);
|
||||||
let tx = SystemTransaction::new_account(&keypair1, keypair4.pubkey(), 1, tick.hash, 0);
|
let tx = SystemTransaction::new_account(&keypair1, keypair4.pubkey(), 1, bank.last_id(), 0);
|
||||||
let entry_2 = next_entry(&tick.hash, 1, vec![tx]);
|
let entry_2 = next_entry(&tick.hash, 1, vec![tx]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
par_process_entries(&bank, &[entry_1.clone(), tick.clone(), entry_2.clone()]),
|
par_process_entries(&bank, &[entry_1.clone(), tick.clone(), entry_2.clone()]),
|
||||||
|
@ -665,9 +678,9 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair3.pubkey()), 1);
|
||||||
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
assert_eq!(bank.get_balance(&keypair4.pubkey()), 1);
|
||||||
assert_eq!(bank.last_id(), tick.hash);
|
|
||||||
// ensure that an error is returned for an empty account (keypair2)
|
// ensure that an error is returned for an empty account (keypair2)
|
||||||
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, tick.hash, 0);
|
let tx = SystemTransaction::new_account(&keypair2, keypair3.pubkey(), 1, bank.last_id(), 0);
|
||||||
let entry_3 = next_entry(&entry_2.hash, 1, vec![tx]);
|
let entry_3 = next_entry(&entry_2.hash, 1, vec![tx]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
par_process_entries(&bank, &[entry_3]),
|
par_process_entries(&bank, &[entry_3]),
|
||||||
|
|
|
@ -147,14 +147,14 @@ mod tests {
|
||||||
|
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(1234);
|
let (genesis_block, mint_keypair) = GenesisBlock::new(1234);
|
||||||
let bank = Arc::new(Bank::new(&genesis_block));
|
let bank = Arc::new(Bank::new(&genesis_block));
|
||||||
// generate 10 validators, but only vote for the first 6 validators
|
|
||||||
let ids: Vec<_> = (0..10 * bank.ticks_per_slot())
|
// Move the bank up 10 slots
|
||||||
.map(|i| {
|
let mut tick_hash = genesis_block.hash();
|
||||||
let last_id = hash(&serialize(&i).unwrap()); // Unique hash
|
while bank.slot_height() < 10 {
|
||||||
bank.register_tick(&last_id);
|
tick_hash = hash(&serialize(&tick_hash).unwrap());
|
||||||
last_id
|
bank.register_tick(&tick_hash);
|
||||||
})
|
}
|
||||||
.collect();
|
let last_id = bank.last_id();
|
||||||
|
|
||||||
// Create a total of 10 vote accounts, each will have a balance of 1 (after giving 1 to
|
// Create a total of 10 vote accounts, each will have a balance of 1 (after giving 1 to
|
||||||
// their vote account), for a total staking pool of 10 tokens.
|
// their vote account), for a total staking pool of 10 tokens.
|
||||||
|
@ -162,7 +162,6 @@ mod tests {
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
// Create new validator to vote
|
// Create new validator to vote
|
||||||
let validator_keypair = Arc::new(Keypair::new());
|
let validator_keypair = Arc::new(Keypair::new());
|
||||||
let last_id = ids[i];
|
|
||||||
let voting_keypair = VotingKeypair::new_local(&validator_keypair);
|
let voting_keypair = VotingKeypair::new_local(&validator_keypair);
|
||||||
let voting_pubkey = voting_keypair.pubkey();
|
let voting_pubkey = voting_keypair.pubkey();
|
||||||
|
|
||||||
|
@ -185,10 +184,11 @@ mod tests {
|
||||||
genesis_block.bootstrap_leader_id,
|
genesis_block.bootstrap_leader_id,
|
||||||
&mut last_confirmation_time,
|
&mut last_confirmation_time,
|
||||||
);
|
);
|
||||||
|
assert_eq!(last_confirmation_time, 0);
|
||||||
|
|
||||||
// Get another validator to vote, so we now have 2/3 consensus
|
// Get another validator to vote, so we now have 2/3 consensus
|
||||||
let voting_keypair = &vote_accounts[7].0;
|
let voting_keypair = &vote_accounts[7].0;
|
||||||
let vote_tx = VoteTransaction::new_vote(voting_keypair, 7, ids[6], 0);
|
let vote_tx = VoteTransaction::new_vote(voting_keypair, 7, last_id, 0);
|
||||||
bank.process_transaction(&vote_tx).unwrap();
|
bank.process_transaction(&vote_tx).unwrap();
|
||||||
|
|
||||||
LeaderConfirmationService::compute_confirmation(
|
LeaderConfirmationService::compute_confirmation(
|
||||||
|
|
Loading…
Reference in New Issue