Update timestamp max allowable drift to 50% of PoH (#14531)
* Repurpose warp-timestamp feature for general bump * Change max_allowable_drift to 50% * Fill in PR# * Fix rpc test setup
This commit is contained in:
@ -2896,7 +2896,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
|
vote_state::{BlockTimestamp, Vote, VoteInit, VoteStateVersions, MAX_LOCKOUT_HISTORY},
|
||||||
};
|
};
|
||||||
use spl_token_v2_0::{
|
use spl_token_v2_0::{
|
||||||
solana_program::{program_option::COption, pubkey::Pubkey as SplTokenPubkey},
|
solana_program::{program_option::COption, pubkey::Pubkey as SplTokenPubkey},
|
||||||
@ -2931,6 +2931,18 @@ pub mod tests {
|
|||||||
) -> RpcHandler {
|
) -> RpcHandler {
|
||||||
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
|
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
|
||||||
let bank = bank_forks.read().unwrap().working_bank();
|
let bank = bank_forks.read().unwrap().working_bank();
|
||||||
|
|
||||||
|
let vote_pubkey = leader_vote_keypair.pubkey();
|
||||||
|
let mut vote_account = bank.get_account(&vote_pubkey).unwrap_or_default();
|
||||||
|
let mut vote_state = VoteState::from(&vote_account).unwrap_or_default();
|
||||||
|
vote_state.last_timestamp = BlockTimestamp {
|
||||||
|
slot: bank.slot(),
|
||||||
|
timestamp: bank.clock().unix_timestamp,
|
||||||
|
};
|
||||||
|
let versioned = VoteStateVersions::new_current(vote_state);
|
||||||
|
VoteState::to(&versioned, &mut vote_account).unwrap();
|
||||||
|
bank.store_account(&vote_pubkey, &vote_account);
|
||||||
|
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
||||||
let blockstore = Arc::new(blockstore);
|
let blockstore = Arc::new(blockstore);
|
||||||
@ -5127,7 +5139,7 @@ pub mod tests {
|
|||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected = format!(
|
let expected = format!(
|
||||||
r#"{{"jsonrpc":"2.0","result":{},"id":1}}"#,
|
r#"{{"jsonrpc":"2.0","result":{},"id":1}}"#,
|
||||||
base_timestamp + (5 * slot_duration).as_secs() as i64
|
base_timestamp + (7 * slot_duration).as_secs() as i64
|
||||||
);
|
);
|
||||||
let expected: Response =
|
let expected: Response =
|
||||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||||
|
@ -60,7 +60,9 @@ use solana_sdk::{
|
|||||||
slot_hashes::SlotHashes,
|
slot_hashes::SlotHashes,
|
||||||
slot_history::SlotHistory,
|
slot_history::SlotHistory,
|
||||||
stake_weighted_timestamp::{
|
stake_weighted_timestamp::{
|
||||||
calculate_stake_weighted_timestamp, EstimateType, DEPRECATED_TIMESTAMP_SLOT_RANGE,
|
calculate_stake_weighted_timestamp, EstimateType,
|
||||||
|
DEPRECATED_MAX_ALLOWABLE_DRIFT_PERCENTAGE, DEPRECATED_TIMESTAMP_SLOT_RANGE,
|
||||||
|
MAX_ALLOWABLE_DRIFT_PERCENTAGE,
|
||||||
},
|
},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
sysvar::{self},
|
sysvar::{self},
|
||||||
@ -1332,12 +1334,10 @@ impl Bank {
|
|||||||
// needed for timestamp bounding, but isn't yet corrected for the activation slot
|
// needed for timestamp bounding, but isn't yet corrected for the activation slot
|
||||||
let epoch_start_timestamp = if self.slot() > timestamp_bounding_activation_slot
|
let epoch_start_timestamp = if self.slot() > timestamp_bounding_activation_slot
|
||||||
{
|
{
|
||||||
let warp_testnet_timestamp = self
|
let warp_timestamp = self
|
||||||
.feature_set
|
.feature_set
|
||||||
.activated_slot(&feature_set::warp_testnet_timestamp::id());
|
.activated_slot(&feature_set::warp_timestamp::id());
|
||||||
if warp_testnet_timestamp == Some(self.slot())
|
if warp_timestamp == Some(self.slot()) {
|
||||||
&& self.cluster_type() == ClusterType::Testnet
|
|
||||||
{
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let epoch = if let Some(epoch) = parent_epoch {
|
let epoch = if let Some(epoch) = parent_epoch {
|
||||||
@ -1352,7 +1352,18 @@ impl Bank {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
(EstimateType::Bounded, epoch_start_timestamp)
|
let max_allowable_drift = if self
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::warp_timestamp::id())
|
||||||
|
{
|
||||||
|
MAX_ALLOWABLE_DRIFT_PERCENTAGE
|
||||||
|
} else {
|
||||||
|
DEPRECATED_MAX_ALLOWABLE_DRIFT_PERCENTAGE
|
||||||
|
};
|
||||||
|
(
|
||||||
|
EstimateType::Bounded(max_allowable_drift),
|
||||||
|
epoch_start_timestamp,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(EstimateType::Unbounded, None)
|
(EstimateType::Unbounded, None)
|
||||||
};
|
};
|
||||||
@ -11144,6 +11155,10 @@ pub(crate) mod tests {
|
|||||||
.accounts
|
.accounts
|
||||||
.remove(&feature_set::timestamp_bounding::id())
|
.remove(&feature_set::timestamp_bounding::id())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
genesis_config
|
||||||
|
.accounts
|
||||||
|
.remove(&feature_set::warp_timestamp::id())
|
||||||
|
.unwrap();
|
||||||
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
|
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
|
||||||
let bank = Bank::new(&genesis_config);
|
let bank = Bank::new(&genesis_config);
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ pub mod try_find_program_address_syscall_enabled {
|
|||||||
solana_sdk::declare_id!("EMsMNadQNhCYDyGpYH5Tx6dGHxiUqKHk782PU5XaWfmi");
|
solana_sdk::declare_id!("EMsMNadQNhCYDyGpYH5Tx6dGHxiUqKHk782PU5XaWfmi");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod warp_testnet_timestamp {
|
pub mod warp_timestamp {
|
||||||
solana_sdk::declare_id!("Bfqm7fGk5MBptqa2WHXWFLH7uJvq8hkJcAQPipy2bAMk");
|
solana_sdk::declare_id!("Bfqm7fGk5MBptqa2WHXWFLH7uJvq8hkJcAQPipy2bAMk");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ lazy_static! {
|
|||||||
(simple_capitalization::id(), "simple capitalization"),
|
(simple_capitalization::id(), "simple capitalization"),
|
||||||
(bpf_loader_upgradeable_program::id(), "upgradeable bpf loader"),
|
(bpf_loader_upgradeable_program::id(), "upgradeable bpf loader"),
|
||||||
(try_find_program_address_syscall_enabled::id(), "add try_find_program_address syscall"),
|
(try_find_program_address_syscall_enabled::id(), "add try_find_program_address syscall"),
|
||||||
(warp_testnet_timestamp::id(), "warp testnet timestamp to current #14210"),
|
(warp_timestamp::id(), "warp timestamp to current, adjust bounding to 50% #14210 & #14531"),
|
||||||
(stake_program_v3::id(), "solana_stake_program v3"),
|
(stake_program_v3::id(), "solana_stake_program v3"),
|
||||||
(max_cpi_instruction_size_ipv6_mtu::id(), "Max cross-program invocation size 1280"),
|
(max_cpi_instruction_size_ipv6_mtu::id(), "Max cross-program invocation size 1280"),
|
||||||
(limit_cpi_loader_invoke::id(), "Loader not authorized via CPI"),
|
(limit_cpi_loader_invoke::id(), "Loader not authorized via CPI"),
|
||||||
|
@ -12,11 +12,12 @@ use std::{
|
|||||||
|
|
||||||
pub const TIMESTAMP_SLOT_RANGE: usize = 32;
|
pub const TIMESTAMP_SLOT_RANGE: usize = 32;
|
||||||
pub const DEPRECATED_TIMESTAMP_SLOT_RANGE: usize = 16; // Deprecated. Remove in the Solana v1.6.0 timeframe
|
pub const DEPRECATED_TIMESTAMP_SLOT_RANGE: usize = 16; // Deprecated. Remove in the Solana v1.6.0 timeframe
|
||||||
const MAX_ALLOWABLE_DRIFT_PERCENTAGE: u32 = 25;
|
pub const DEPRECATED_MAX_ALLOWABLE_DRIFT_PERCENTAGE: u32 = 25;
|
||||||
|
pub const MAX_ALLOWABLE_DRIFT_PERCENTAGE: u32 = 50;
|
||||||
|
|
||||||
pub enum EstimateType {
|
pub enum EstimateType {
|
||||||
Bounded,
|
Bounded(u32), // Value represents max allowable drift percentage
|
||||||
Unbounded, // Deprecated. Remove in the Solana v1.6.0 timeframe
|
Unbounded, // Deprecated. Remove in the Solana v1.6.0 timeframe
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_stake_weighted_timestamp<I, K, V, T>(
|
pub fn calculate_stake_weighted_timestamp<I, K, V, T>(
|
||||||
@ -33,12 +34,13 @@ where
|
|||||||
V: Borrow<(Slot, UnixTimestamp)>,
|
V: Borrow<(Slot, UnixTimestamp)>,
|
||||||
{
|
{
|
||||||
match estimate_type {
|
match estimate_type {
|
||||||
EstimateType::Bounded => calculate_bounded_stake_weighted_timestamp(
|
EstimateType::Bounded(max_allowable_drift) => calculate_bounded_stake_weighted_timestamp(
|
||||||
unique_timestamps,
|
unique_timestamps,
|
||||||
stakes,
|
stakes,
|
||||||
slot,
|
slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
epoch_start_timestamp,
|
epoch_start_timestamp,
|
||||||
|
max_allowable_drift,
|
||||||
),
|
),
|
||||||
EstimateType::Unbounded => calculate_unbounded_stake_weighted_timestamp(
|
EstimateType::Unbounded => calculate_unbounded_stake_weighted_timestamp(
|
||||||
unique_timestamps,
|
unique_timestamps,
|
||||||
@ -88,6 +90,7 @@ fn calculate_bounded_stake_weighted_timestamp<I, K, V, T>(
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
slot_duration: Duration,
|
slot_duration: Duration,
|
||||||
epoch_start_timestamp: Option<(Slot, UnixTimestamp)>,
|
epoch_start_timestamp: Option<(Slot, UnixTimestamp)>,
|
||||||
|
max_allowable_drift_percentage: u32,
|
||||||
) -> Option<UnixTimestamp>
|
) -> Option<UnixTimestamp>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (K, V)>,
|
I: IntoIterator<Item = (K, V)>,
|
||||||
@ -128,7 +131,7 @@ where
|
|||||||
let poh_estimate_offset = slot.saturating_sub(epoch_start_slot) as u32 * slot_duration;
|
let poh_estimate_offset = slot.saturating_sub(epoch_start_slot) as u32 * slot_duration;
|
||||||
let estimate_offset =
|
let estimate_offset =
|
||||||
Duration::from_secs(estimate.saturating_sub(epoch_start_timestamp) as u64);
|
Duration::from_secs(estimate.saturating_sub(epoch_start_timestamp) as u64);
|
||||||
let max_allowable_drift = poh_estimate_offset * MAX_ALLOWABLE_DRIFT_PERCENTAGE / 100;
|
let max_allowable_drift = poh_estimate_offset * max_allowable_drift_percentage / 100;
|
||||||
if estimate_offset > poh_estimate_offset
|
if estimate_offset > poh_estimate_offset
|
||||||
&& estimate_offset - poh_estimate_offset > max_allowable_drift
|
&& estimate_offset - poh_estimate_offset > max_allowable_drift
|
||||||
{
|
{
|
||||||
@ -271,6 +274,7 @@ pub mod tests {
|
|||||||
let pubkey2 = solana_sdk::pubkey::new_rand();
|
let pubkey2 = solana_sdk::pubkey::new_rand();
|
||||||
let pubkey3 = solana_sdk::pubkey::new_rand();
|
let pubkey3 = solana_sdk::pubkey::new_rand();
|
||||||
let pubkey4 = solana_sdk::pubkey::new_rand();
|
let pubkey4 = solana_sdk::pubkey::new_rand();
|
||||||
|
let max_allowable_drift = 25;
|
||||||
|
|
||||||
// Test low-staked outlier(s)
|
// Test low-staked outlier(s)
|
||||||
let stakes: HashMap<Pubkey, (u64, Account)> = [
|
let stakes: HashMap<Pubkey, (u64, Account)> = [
|
||||||
@ -333,6 +337,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
None,
|
None,
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded - unbounded, 527); // timestamp w/ 0.00003% of the stake can shift the timestamp backward 8min
|
assert_eq!(bounded - unbounded, 527); // timestamp w/ 0.00003% of the stake can shift the timestamp backward 8min
|
||||||
@ -363,6 +368,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
None,
|
None,
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(unbounded - bounded, 3074455295455); // timestamp w/ 0.00003% of the stake can shift the timestamp forward 97k years!
|
assert_eq!(unbounded - bounded, 3074455295455); // timestamp w/ 0.00003% of the stake can shift the timestamp forward 97k years!
|
||||||
@ -385,6 +391,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
None,
|
None,
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, recent_timestamp); // multiple low-staked outliers cannot affect bounded timestamp if they don't shift the median
|
assert_eq!(bounded, recent_timestamp); // multiple low-staked outliers cannot affect bounded timestamp if they don't shift the median
|
||||||
@ -432,6 +439,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
None,
|
None,
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, recent_timestamp); // outlier(s) cannot affect bounded timestamp if they don't shift the median
|
assert_eq!(bounded, recent_timestamp); // outlier(s) cannot affect bounded timestamp if they don't shift the median
|
||||||
@ -468,6 +476,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
None,
|
None,
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(recent_timestamp - bounded, 1578909061); // outliers > 1/2 of available stake can affect timestamp
|
assert_eq!(recent_timestamp - bounded, 1578909061); // outliers > 1/2 of available stake can affect timestamp
|
||||||
@ -479,7 +488,8 @@ pub mod tests {
|
|||||||
let slot = 20;
|
let slot = 20;
|
||||||
let slot_duration = Duration::from_millis(400);
|
let slot_duration = Duration::from_millis(400);
|
||||||
let poh_offset = (slot * slot_duration).as_secs();
|
let poh_offset = (slot * slot_duration).as_secs();
|
||||||
let acceptable_delta = (MAX_ALLOWABLE_DRIFT_PERCENTAGE * poh_offset as u32 / 100) as i64;
|
let max_allowable_drift = 25;
|
||||||
|
let acceptable_delta = (max_allowable_drift * poh_offset as u32 / 100) as i64;
|
||||||
let poh_estimate = epoch_start_timestamp + poh_offset as i64;
|
let poh_estimate = epoch_start_timestamp + poh_offset as i64;
|
||||||
let pubkey0 = solana_sdk::pubkey::new_rand();
|
let pubkey0 = solana_sdk::pubkey::new_rand();
|
||||||
let pubkey1 = solana_sdk::pubkey::new_rand();
|
let pubkey1 = solana_sdk::pubkey::new_rand();
|
||||||
@ -528,6 +538,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
Some((0, epoch_start_timestamp)),
|
Some((0, epoch_start_timestamp)),
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, poh_estimate + acceptable_delta);
|
assert_eq!(bounded, poh_estimate + acceptable_delta);
|
||||||
@ -548,6 +559,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
Some((0, epoch_start_timestamp)),
|
Some((0, epoch_start_timestamp)),
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, poh_estimate - acceptable_delta);
|
assert_eq!(bounded, poh_estimate - acceptable_delta);
|
||||||
@ -568,6 +580,7 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
Some((0, epoch_start_timestamp)),
|
Some((0, epoch_start_timestamp)),
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, poh_estimate + acceptable_delta);
|
assert_eq!(bounded, poh_estimate + acceptable_delta);
|
||||||
@ -587,8 +600,135 @@ pub mod tests {
|
|||||||
slot as Slot,
|
slot as Slot,
|
||||||
slot_duration,
|
slot_duration,
|
||||||
Some((0, epoch_start_timestamp)),
|
Some((0, epoch_start_timestamp)),
|
||||||
|
max_allowable_drift,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bounded, poh_estimate - acceptable_delta);
|
assert_eq!(bounded, poh_estimate - acceptable_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_calculate_bounded_stake_weighted_timestamp_levels() {
|
||||||
|
let epoch_start_timestamp: UnixTimestamp = 1_578_909_061;
|
||||||
|
let slot = 20;
|
||||||
|
let slot_duration = Duration::from_millis(400);
|
||||||
|
let poh_offset = (slot * slot_duration).as_secs();
|
||||||
|
let allowable_drift_25 = 25;
|
||||||
|
let allowable_drift_50 = 50;
|
||||||
|
let acceptable_delta_25 = (allowable_drift_25 * poh_offset as u32 / 100) as i64;
|
||||||
|
let acceptable_delta_50 = (allowable_drift_50 * poh_offset as u32 / 100) as i64;
|
||||||
|
assert!(acceptable_delta_50 > acceptable_delta_25 + 1);
|
||||||
|
let poh_estimate = epoch_start_timestamp + poh_offset as i64;
|
||||||
|
let pubkey0 = solana_sdk::pubkey::new_rand();
|
||||||
|
let pubkey1 = solana_sdk::pubkey::new_rand();
|
||||||
|
let pubkey2 = solana_sdk::pubkey::new_rand();
|
||||||
|
|
||||||
|
let stakes: HashMap<Pubkey, (u64, Account)> = [
|
||||||
|
(
|
||||||
|
pubkey0,
|
||||||
|
(
|
||||||
|
sol_to_lamports(1_000_000.0),
|
||||||
|
Account::new(1, 0, &Pubkey::default()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey1,
|
||||||
|
(
|
||||||
|
sol_to_lamports(1_000_000.0),
|
||||||
|
Account::new(1, 0, &Pubkey::default()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey2,
|
||||||
|
(
|
||||||
|
sol_to_lamports(1_000_000.0),
|
||||||
|
Account::new(1, 0, &Pubkey::default()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Test when stake-weighted median is above 25% deviance but below 50% deviance
|
||||||
|
let unique_timestamps: HashMap<Pubkey, (Slot, UnixTimestamp)> = [
|
||||||
|
(
|
||||||
|
pubkey0,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_25 + 1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey1,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_25 + 1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey2,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_25 + 1),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let bounded = calculate_bounded_stake_weighted_timestamp(
|
||||||
|
&unique_timestamps,
|
||||||
|
&stakes,
|
||||||
|
slot as Slot,
|
||||||
|
slot_duration,
|
||||||
|
Some((0, epoch_start_timestamp)),
|
||||||
|
allowable_drift_25,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(bounded, poh_estimate + acceptable_delta_25);
|
||||||
|
|
||||||
|
let bounded = calculate_bounded_stake_weighted_timestamp(
|
||||||
|
&unique_timestamps,
|
||||||
|
&stakes,
|
||||||
|
slot as Slot,
|
||||||
|
slot_duration,
|
||||||
|
Some((0, epoch_start_timestamp)),
|
||||||
|
allowable_drift_50,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(bounded, poh_estimate + acceptable_delta_25 + 1);
|
||||||
|
|
||||||
|
// Test when stake-weighted median is above 50% deviance
|
||||||
|
let unique_timestamps: HashMap<Pubkey, (Slot, UnixTimestamp)> = [
|
||||||
|
(
|
||||||
|
pubkey0,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_50 + 1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey1,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_50 + 1),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pubkey2,
|
||||||
|
(slot as u64, poh_estimate + acceptable_delta_50 + 1),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let bounded = calculate_bounded_stake_weighted_timestamp(
|
||||||
|
&unique_timestamps,
|
||||||
|
&stakes,
|
||||||
|
slot as Slot,
|
||||||
|
slot_duration,
|
||||||
|
Some((0, epoch_start_timestamp)),
|
||||||
|
allowable_drift_25,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(bounded, poh_estimate + acceptable_delta_25);
|
||||||
|
|
||||||
|
let bounded = calculate_bounded_stake_weighted_timestamp(
|
||||||
|
&unique_timestamps,
|
||||||
|
&stakes,
|
||||||
|
slot as Slot,
|
||||||
|
slot_duration,
|
||||||
|
Some((0, epoch_start_timestamp)),
|
||||||
|
allowable_drift_50,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(bounded, poh_estimate + acceptable_delta_50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user