Skip to content

Commit

Permalink
Submit a timestamp for every vote
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines committed Jun 16, 2020
1 parent ae0d5ba commit a817fdc
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 60 deletions.
54 changes: 4 additions & 50 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ use chrono::prelude::*;
use solana_ledger::bank_forks::BankForks;
use solana_runtime::bank::Bank;
use solana_sdk::{
account::Account,
clock::{Slot, UnixTimestamp},
hash::Hash,
instruction::Instruction,
pubkey::Pubkey,
account::Account, clock::Slot, hash::Hash, instruction::Instruction, pubkey::Pubkey,
};
use solana_vote_program::{
vote_instruction,
vote_state::{
BlockTimestamp, Lockout, Vote, VoteState, MAX_LOCKOUT_HISTORY, TIMESTAMP_SLOT_INTERVAL,
},
vote_state::{Lockout, Vote, VoteState, MAX_LOCKOUT_HISTORY},
};
use std::{
collections::{BTreeMap, HashMap, HashSet},
Expand Down Expand Up @@ -93,7 +87,6 @@ pub struct Tower {
threshold_size: f64,
lockouts: VoteState,
last_vote: Vote,
last_timestamp: BlockTimestamp,
}

impl Default for Tower {
Expand All @@ -104,7 +97,6 @@ impl Default for Tower {
threshold_size: VOTE_THRESHOLD_SIZE,
lockouts: VoteState::default(),
last_vote: Vote::default(),
last_timestamp: BlockTimestamp::default(),
}
}
}
Expand Down Expand Up @@ -343,8 +335,7 @@ impl Tower {

pub fn last_vote_and_timestamp(&mut self) -> Vote {
let mut last_vote = self.last_vote();
let current_slot = last_vote.slots.iter().max().unwrap_or(&0);
last_vote.timestamp = self.maybe_timestamp(*current_slot);
last_vote.timestamp = Some(Utc::now().timestamp());
last_vote
}

Expand Down Expand Up @@ -637,21 +628,6 @@ impl Tower {
self.lockouts = vote_state;
}
}

fn maybe_timestamp(&mut self, current_slot: Slot) -> Option<UnixTimestamp> {
if self.last_timestamp.slot == 0
|| self.last_timestamp.slot < (current_slot - (current_slot % TIMESTAMP_SLOT_INTERVAL))
{
let timestamp = Utc::now().timestamp();
self.last_timestamp = BlockTimestamp {
slot: current_slot,
timestamp,
};
Some(timestamp)
} else {
None
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -683,12 +659,7 @@ pub mod test {
vote_state::{Vote, VoteStateVersions, MAX_LOCKOUT_HISTORY},
vote_transaction,
};
use std::{
collections::HashMap,
rc::Rc,
sync::RwLock,
{thread::sleep, time::Duration},
};
use std::{collections::HashMap, rc::Rc, sync::RwLock};
use trees::{tr, Tree, TreeWalk};

pub(crate) struct VoteSimulator {
Expand Down Expand Up @@ -1850,21 +1821,4 @@ pub mod test {
fn test_recent_votes_exact() {
vote_and_check_recent(5)
}

#[test]
fn test_maybe_timestamp() {
let mut tower = Tower::default();
assert!(tower.maybe_timestamp(TIMESTAMP_SLOT_INTERVAL).is_some());
let BlockTimestamp { slot, timestamp } = tower.last_timestamp;

assert_eq!(tower.maybe_timestamp(1), None);
assert_eq!(tower.maybe_timestamp(slot), None);
assert_eq!(tower.maybe_timestamp(slot + 1), None);

sleep(Duration::from_secs(1));
assert!(tower
.maybe_timestamp(slot + TIMESTAMP_SLOT_INTERVAL + 1)
.is_some());
assert!(tower.last_timestamp.timestamp > timestamp);
}
}
6 changes: 3 additions & 3 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ impl JsonRpcRequestProcessor {
self.check_slot_cleaned_up(&result, slot)?;
Ok(result.ok())
} else {
Ok(None)
Err(RpcCustomError::BlockNotAvailable { slot }.into())
}
}

Expand Down Expand Up @@ -549,7 +549,7 @@ impl JsonRpcRequestProcessor {
self.check_slot_cleaned_up(&result, slot)?;
Ok(result.ok().unwrap_or(None))
} else {
Ok(None)
Err(RpcCustomError::BlockNotAvailable { slot }.into())
}
}

Expand Down Expand Up @@ -3354,7 +3354,7 @@ pub mod tests {
slot
);
let res = io.handle_request_sync(&req, meta);
let expected = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32003,"message":"Block not available for slot 12345"},"id":1}"#;
let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
Expand Down
9 changes: 9 additions & 0 deletions core/src/rpc_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use solana_sdk::clock::Slot;
const JSON_RPC_SERVER_ERROR_0: i64 = -32000;
const JSON_RPC_SERVER_ERROR_1: i64 = -32001;
const JSON_RPC_SERVER_ERROR_2: i64 = -32002;
const JSON_RPC_SERVER_ERROR_3: i64 = -32003;

pub enum RpcCustomError {
NonexistentClusterRoot {
Expand All @@ -17,6 +18,9 @@ pub enum RpcCustomError {
SendTransactionPreflightFailure {
message: String,
},
BlockNotAvailable {
slot: Slot,
},
}

impl From<RpcCustomError> for Error {
Expand Down Expand Up @@ -49,6 +53,11 @@ impl From<RpcCustomError> for Error {
message,
data: None,
},
RpcCustomError::BlockNotAvailable { slot } => Self {
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_3),
message: format!("Block not available for slot {}", slot,),
data: None,
},
}
}
}
4 changes: 2 additions & 2 deletions docs/src/apps/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m

### getBlockTime

Returns the estimated production time of a block.
Returns the estimated production time of a confirmed block.

Each validator reports their UTC time to the ledger on a regular interval by
intermittently adding a timestamp to a Vote for a particular block. A requested
Expand All @@ -231,8 +231,8 @@ query a node that is built from genesis and retains the entire ledger.

#### Results:

* `<null>` - block has not yet been produced
* `<i64>` - estimated production time, as Unix timestamp (seconds since the Unix epoch)
* `<null>` - timestamp is not available for this block

#### Example:

Expand Down
3 changes: 2 additions & 1 deletion ledger/src/blockstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use solana_transaction_status::{
ConfirmedBlock, ConfirmedTransaction, EncodedTransaction, Rewards, RpcTransactionStatusMeta,
TransactionEncoding, TransactionStatusMeta, TransactionWithStatusMeta,
};
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
use solana_vote_program::vote_instruction::VoteInstruction;
use std::{
cell::RefCell,
cmp,
Expand Down Expand Up @@ -75,6 +75,7 @@ thread_local!(static PAR_THREAD_POOL_ALL_CPUS: RefCell<ThreadPool> = RefCell::ne
pub const MAX_COMPLETED_SLOTS_IN_CHANNEL: usize = 100_000;
pub const MAX_TURBINE_PROPAGATION_IN_MS: u64 = 100;
pub const MAX_TURBINE_DELAY_IN_TICKS: u64 = MAX_TURBINE_PROPAGATION_IN_MS / MS_PER_TICK;
const TIMESTAMP_SLOT_INTERVAL: u64 = 4500;
const TIMESTAMP_SLOT_RANGE: usize = 16;

// An upper bound on maximum number of data shreds we can handle in a slot
Expand Down
4 changes: 0 additions & 4 deletions programs/vote/src/vote_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ pub const INITIAL_LOCKOUT: usize = 2;
// smaller numbers makes
pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;

// Frequency of timestamp Votes. In v0.22.0, this is approximately 30min with cluster clock
// defaults, intended to limit block time drift to < 1hr
pub const TIMESTAMP_SLOT_INTERVAL: u64 = 4500;

#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Vote {
/// A stack of votes starting with the oldest vote
Expand Down

0 comments on commit a817fdc

Please sign in to comment.