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

Commit

Permalink
Move stakes up into rpc to make testing easier; expand tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyera Eulberg committed Dec 13, 2019
1 parent d578483 commit 2d876ec
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 29 deletions.
79 changes: 58 additions & 21 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use solana_sdk::{
};
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
use std::{
collections::HashMap,
net::{SocketAddr, UdpSocket},
sync::{Arc, RwLock},
thread::sleep,
Expand Down Expand Up @@ -311,21 +312,19 @@ impl JsonRpcRequestProcessor {
Ok(self.blocktree.get_confirmed_block(slot).ok())
}

// The `get_block_time` method is not fully implemented. It currently returns `slot` *
// DEFAULT_MS_PER_SLOT offset from 0 for all requests, and null for any values that would
// overflow.
pub fn get_block_time(&self, slot: Slot) -> Result<Option<UnixTimestamp>> {
// This calculation currently assumes that bank.ticks_per_slot and bank.slots_per_year will
// remain unchanged after genesis. If these values will be variable in the future, those
// timing parameters will need to be stored persistently, and this calculation will likely
// need to be moved upstream into blocktree. Also, an explicit commitment level will need
// to be set.
// This calculation currently assumes that bank.slots_per_year will remain unchanged after
// genesis (ie. that this bank's slot_per_year will be applicable to any rooted slot being
// queried). If these values will be variable in the future, those timing parameters will
// need to be stored persistently, and the slot_duration calculation will likely need to be
// moved upstream into blocktree. Also, an explicit commitment level will need to be set.
let bank = self.bank(None);
let slot_duration = slot_duration_from_slots_per_year(bank.slots_per_year());
let epoch = bank.epoch_schedule().get_epoch(slot);
let stakes = HashMap::new();
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);

Ok(self
.blocktree
.get_block_time(slot, slot_duration, &bank.clone()))
Ok(self.blocktree.get_block_time(slot, slot_duration, stakes))
}
}

Expand Down Expand Up @@ -1008,7 +1007,9 @@ pub mod tests {
replay_stage::tests::create_test_transactions_and_populate_blocktree,
};
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
use solana_ledger::get_tmp_ledger_path;
use solana_ledger::{
blocktree::entries_to_test_shreds, entry::next_entry_mut, get_tmp_ledger_path,
};
use solana_sdk::{
fee_calculator::DEFAULT_BURN_PERCENT,
hash::{hash, Hash},
Expand Down Expand Up @@ -1044,6 +1045,14 @@ pub mod tests {
}

fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
start_rpc_handler_with_tx_and_blocktree(pubkey, vec![], 0)
}

fn start_rpc_handler_with_tx_and_blocktree(
pubkey: &Pubkey,
blocktree_roots: Vec<Slot>,
default_timestamp: i64,
) -> RpcHandler {
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
let bank = bank_forks.read().unwrap().working_bank();

Expand Down Expand Up @@ -1073,6 +1082,32 @@ pub mod tests {
blocktree.clone(),
);

// Add timestamp vote to blocktree
let vote = Vote {
slots: vec![1],
hash: Hash::default(),
timestamp: Some(default_timestamp),
};
let vote_ix = vote_instruction::vote(
&leader_vote_keypair.pubkey(),
&leader_vote_keypair.pubkey(),
vote,
);
let vote_tx = Transaction::new_signed_instructions(
&[&leader_vote_keypair],
vec![vote_ix],
Hash::default(),
);
let shreds = entries_to_test_shreds(
vec![next_entry_mut(&mut Hash::default(), 0, vec![vote_tx])],
1,
0,
true,
0,
);
blocktree.insert_shreds(shreds, None, false).unwrap();
blocktree.set_roots(&blocktree_roots).unwrap();

let leader_pubkey = *bank.collector_id();
let exit = Arc::new(AtomicBool::new(false));
let validator_exit = create_validator_exit(&exit);
Expand Down Expand Up @@ -1864,43 +1899,45 @@ pub mod tests {
#[test]
fn test_get_block_time() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&bob_pubkey);
let base_timestamp = 1576183541;
let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx_and_blocktree(
&bob_pubkey,
vec![1, 2, 3, 4, 5, 6, 7],
base_timestamp,
);

let slot_duration = slot_duration_from_slots_per_year(bank.slots_per_year());

let slot = 100;
let slot = 2;
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"#,
slot
);
let res = io.handle_request_sync(&req, meta.clone());
let expected = format!(
r#"{{"jsonrpc":"2.0","result":{},"id":1}}"#,
(slot * slot_duration).as_secs()
);
let expected = format!(r#"{{"jsonrpc":"2.0","result":{},"id":1}}"#, base_timestamp);
let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);

let slot = 12345;
let slot = 7;
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"#,
slot
);
let res = io.handle_request_sync(&req, meta.clone());
let expected = format!(
r#"{{"jsonrpc":"2.0","result":{},"id":1}}"#,
(slot * slot_duration).as_secs()
base_timestamp + (5 * slot_duration).as_secs() as i64
);
let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);

let slot = 123450000000000000u64;
let slot = 12345;
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"#,
slot
Expand Down
39 changes: 31 additions & 8 deletions ledger/src/blocktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use solana_client::rpc_request::{RpcConfirmedBlock, RpcTransactionStatus};
use solana_measure::measure::Measure;
use solana_metrics::{datapoint_debug, datapoint_error};
use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::bank::Bank;
use solana_sdk::{
account::Account,
clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, MS_PER_TICK},
genesis_config::GenesisConfig,
hash::Hash,
Expand Down Expand Up @@ -1186,18 +1186,12 @@ impl Blocktree {
}
}

// The `get_block_time` method is not fully implemented (depends on validator timestamp
// transactions). It currently returns Some(`slot` * DEFAULT_MS_PER_SLOT) offset from 0 for all
// transactions, and None for any values that would overflow any step.
pub fn get_block_time(
&self,
slot: Slot,
slot_duration: Duration,
bank: &Bank,
stakes: &HashMap<Pubkey, (u64, Account)>,
) -> Option<UnixTimestamp> {
let epoch = bank.epoch_schedule().get_epoch(slot);
let stakes = HashMap::new();
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);
let mut total_stake = 0;
let stake_weighted_timestamps_sum: u64 = self
.get_timestamp_slots(slot, TIMESTAMP_SLOT_INTERVAL)
Expand Down Expand Up @@ -4564,6 +4558,35 @@ pub mod tests {
expected_timestamps
);
assert_eq!(blocktree.get_block_timestamps(2).unwrap(), vec![]);

// Build epoch vote_accounts HashMap to test stake-weighted block time
blocktree.set_roots(&[3, 8]).unwrap();
let mut stakes = HashMap::new();
for (i, keypair) in vote_keypairs.iter().enumerate() {
stakes.insert(keypair.pubkey(), (1 + i as u64, Account::default()));
}
let slot_duration = Duration::from_millis(400);
let block_time_slot_3 = blocktree.get_block_time(3, slot_duration.clone(), &stakes);

let mut total_stake = 0;
let mut expected_time: u64 = (0..6)
.map(|x| {
if x % 2 == 0 {
total_stake += 1 + x;
(base_timestamp as u64 + x) * (1 + x)
} else {
0
}
})
.sum();
expected_time /= total_stake;
assert_eq!(block_time_slot_3.unwrap() as u64, expected_time);
assert_eq!(
blocktree
.get_block_time(8, slot_duration.clone(), &stakes)
.unwrap() as u64,
expected_time + 2 // At 400ms block duration, 5 slots == 2sec
);
}

#[test]
Expand Down

0 comments on commit 2d876ec

Please sign in to comment.