Skip to content

Commit

Permalink
fix: status indicator works now + fixed async/sync context
Browse files Browse the repository at this point in the history
  • Loading branch information
anoushk1234 committed Apr 23, 2023
1 parent 3230bb6 commit 8c71154
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 189 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
**.log
tmp/
.vscode
db/
db/
archives
192 changes: 95 additions & 97 deletions tinydancer/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::tinydancer::{endpoint, ClientService, ClientStatus, Cluster};
use crate::sampler::{ArchiveConfig, SlotSubscribeResponse};
use crate::tinydancer::{endpoint, ClientService, ClientStatus, Cluster};
use crate::{convert_to_websocket, send_rpc_call, try_coerce_shred};
use anyhow::anyhow;
use async_trait::async_trait;
Expand All @@ -12,42 +12,42 @@ use rayon::prelude::*;
use reqwest::Request;
use rocksdb::{ColumnFamily, Options as RocksOptions, DB};
use serde::de::DeserializeOwned;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use solana_ledger::shred::{ShredId, ShredType};
use solana_ledger::{
ancestor_iterator::{AncestorIterator, AncestorIteratorWithHash},
blockstore::Blockstore,
// blockstore_db::columns::ShredCode,
shred::{Nonce, Shred, ShredCode, ShredData, ShredFetchStats, SIZE_OF_NONCE},
ancestor_iterator::{AncestorIterator, AncestorIteratorWithHash},
blockstore::Blockstore,
// blockstore_db::columns::ShredCode,
shred::{Nonce, Shred, ShredCode, ShredData, ShredFetchStats, SIZE_OF_NONCE},
};
use solana_sdk::hash::hashv;
use solana_sdk::{
clock::Slot,
genesis_config::ClusterType,
hash::{Hash, HASH_BYTES},
packet::PACKET_DATA_SIZE,
pubkey::{Pubkey, PUBKEY_BYTES},
signature::{Signable, Signature, Signer, SIGNATURE_BYTES},
signer::keypair::Keypair,
timing::{duration_as_ms, timestamp},
clock::Slot,
genesis_config::ClusterType,
hash::{Hash, HASH_BYTES},
packet::PACKET_DATA_SIZE,
pubkey::{Pubkey, PUBKEY_BYTES},
signature::{Signable, Signature, Signer, SIGNATURE_BYTES},
signer::keypair::Keypair,
timing::{duration_as_ms, timestamp},
};
use std::str::FromStr;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::Arc;
use std::{error::Error, ops::Add};
use std::{
net::{SocketAddr, UdpSocket},
thread::Builder,
net::{SocketAddr, UdpSocket},
thread::Builder,
};
use tiny_logger::logs::{debug, error, info};
use tokio::{
sync::mpsc::UnboundedSender,
task::{JoinError, JoinHandle},
sync::Mutex as TokioMutex,
sync::mpsc::UnboundedSender,
sync::{Mutex, MutexGuard},
task::{JoinError, JoinHandle},
};
use tungstenite::{connect, Message};
use url::Url;
use serde_derive::Deserialize;
use serde_derive::Serialize;

pub struct ConsensusService {
consensus_indices: Vec<u64>,
Expand All @@ -58,20 +58,20 @@ pub struct ConsensusServiceConfig {
pub cluster: Cluster,
pub archive_config: ArchiveConfig,
pub instance: Arc<rocksdb::DB>,
pub status_consensus: Arc<TokioMutex<ClientStatus>>,
pub client_status: Arc<Mutex<ClientStatus>>,
pub sample_qty: usize,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcBlockCommitment<T> {
pub struct RpcBlockCommitment<T> {
pub commitment: Option<T>,
pub total_stake: u64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetCommittmentResponse {
pub struct GetCommittmentResponse {
pub jsonrpc: String,
pub result: RpcBlockCommitment<BlockCommitmentArray>,
pub id: i64,
Expand All @@ -84,96 +84,95 @@ pub const VOTE_THRESHOLD_SIZE: f64 = 2f64 / 3f64;

#[async_trait]
impl ClientService<ConsensusServiceConfig> for ConsensusService {
type ServiceError = tokio::task::JoinError;
type ServiceError = tokio::task::JoinError;

fn new(config: ConsensusServiceConfig) -> Self {
let consensus_handler = tokio::spawn(async move {
let rpc_url = endpoint(config.cluster);
let pub_sub = convert_to_websocket!(rpc_url);
fn new(config: ConsensusServiceConfig) -> Self {
let consensus_handler = tokio::spawn(async move {
let rpc_url = endpoint(config.cluster);
let pub_sub = convert_to_websocket!(rpc_url);

let mut threads = Vec::default();
let mut threads = Vec::default();

let (slot_update_tx, slot_update_rx) = crossbeam::channel::unbounded::<u64>();
let (slot_update_tx, slot_update_rx) = crossbeam::channel::unbounded::<u64>();

let status_arc = config.status_consensus.clone();
let status_arc = config.client_status.clone();

// waits on new slots => triggers slot_verify_loop
threads.push(tokio::spawn(slot_update_loop(
slot_update_tx,
pub_sub,
config.status_consensus,
)));
// waits on new slots => triggers slot_verify_loop
threads.push(tokio::spawn(slot_update_loop(
slot_update_tx,
pub_sub,
config.client_status,
)));

// verify slot votes
threads.push(tokio::spawn(slot_verify_loop(
slot_update_rx,
rpc_url,
status_arc,
)));
// verify slot votes
threads.push(tokio::spawn(slot_verify_loop(
slot_update_rx,
rpc_url,
status_arc,
)));

for thread in threads {
thread.await;
}
});

for thread in threads {
thread.await;
Self {
consensus_handler,
consensus_indices: Vec::default(),
}
});

Self {
consensus_handler,
consensus_indices: Vec::default(),
}
}

async fn join(self) -> std::result::Result<(), Self::ServiceError> {
self.consensus_handler.await
}
async fn join(self) -> std::result::Result<(), Self::ServiceError> {
self.consensus_handler.await
}
}

pub async fn slot_update_loop(
slot_update_tx: Sender<u64>,
pub_sub: String,
status_sampler: Arc<TokioMutex<ClientStatus>>,
client_status: Arc<Mutex<ClientStatus>>,
) -> anyhow::Result<()> {
let result = match connect(Url::parse(pub_sub.as_str()).unwrap()) {
Ok((socket, _response)) => Some((socket, _response)),
Err(_) => {
let mut status = status_sampler.lock().await;
*status = ClientStatus::Crashed(String::from("Client can't connect to socket"));
None
}
};

if result.is_none() {
return Err(anyhow!(""));
}

let (mut socket, _response) = result.unwrap();

socket.write_message(Message::Text(
r#"{ "jsonrpc": "2.0", "id": 1, "method": "slotSubscribe" }"#.into(),
))?;
let result = match connect(Url::parse(pub_sub.as_str()).unwrap()) {
Ok((socket, _response)) => Some((socket, _response)),
Err(_) => {
let mut status = client_status.lock().await;
*status = ClientStatus::Crashed(String::from("Client can't connect to socket"));
None
}
};

loop {
match socket.read_message() {
Ok(msg) => {
let res = serde_json::from_str::<SlotSubscribeResponse>(msg.to_string().as_str());
if result.is_none() {
return Err(anyhow!(""));
}

// info!("res: {:?}", msg.to_string().as_str());
if let Ok(res) = res {
match slot_update_tx.send(res.params.result.root as u64) {
Ok(_) => {
info!("slot updated: {:?}", res.params.result.root);
}
Err(e) => {
info!("error here: {:?} {:?}", e, res.params.result.root as u64);
continue; // @TODO: we should add retries here incase send fails for some reason
let (mut socket, _response) = result.unwrap();

socket.write_message(Message::Text(
r#"{ "jsonrpc": "2.0", "id": 1, "method": "slotSubscribe" }"#.into(),
))?;

loop {
match socket.read_message() {
Ok(msg) => {
let res = serde_json::from_str::<SlotSubscribeResponse>(msg.to_string().as_str());

// info!("res: {:?}", msg.to_string().as_str());
if let Ok(res) = res {
match slot_update_tx.send(res.params.result.root as u64) {
Ok(_) => {
info!("slot updated: {:?}", res.params.result.root);
}
Err(e) => {
info!("error here: {:?} {:?}", e, res.params.result.root as u64);
continue; // @TODO: we should add retries here incase send fails for some reason
}
}
}
}
Err(e) => info!("err: {:?}", e),
}
Err(e) => info!("err: {:?}", e),
}
}
}

// verifies the total vote on the slot > 2/3
fn verify_slot(slot_commitment: RpcBlockCommitment<BlockCommitmentArray>) -> bool {
Expand All @@ -191,20 +190,20 @@ fn verify_slot(slot_commitment: RpcBlockCommitment<BlockCommitmentArray>) -> boo
pub async fn slot_verify_loop(
slot_update_rx: Receiver<u64>,
endpoint: String,
status_sampler: Arc<tokio::sync::Mutex<ClientStatus>>,
client_status: Arc<Mutex<ClientStatus>>,
) -> anyhow::Result<()> {
loop {
let mut status = status_sampler.lock().await;
loop {
let mut status = client_status.lock().await;
if let ClientStatus::Crashed(_) = &*status {
return Err(anyhow!("Client crashed"));
} else {
*status = ClientStatus::Active(String::from(
"Monitoring Tinydancer: Verifying consensus",
));
*status =
ClientStatus::Active(String::from("Monitoring Tinydancer: Verifying consensus"));
}
drop(status);
if let Ok(slot) = slot_update_rx.recv() {
let slot_commitment_result = request_slot_voting(slot, &endpoint).await;

if let Err(e) = slot_commitment_result {
println!("Error {}", e);
info!("{}", e);
Expand All @@ -229,7 +228,6 @@ pub async fn request_slot_voting(
slot: u64,
endpoint: &String,
) -> Result<GetCommittmentResponse, serde_json::Error> {

let request = serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
Expand Down
11 changes: 11 additions & 0 deletions tinydancer/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ macro_rules! block_on {
rt.handle().block_on($func).expect($error);
};
}
#[macro_export]
macro_rules! block_on_async {
($func:expr) => {{
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on($func)
}};
}

#[macro_export]
macro_rules! try_coerce_shred {
($response:expr) => {{
Expand Down
6 changes: 2 additions & 4 deletions tinydancer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ use std::{
use tinydancer::{endpoint, Cluster, TinyDancer, TinyDancerConfig};
mod macros;
use colored::Colorize;
mod consensus;
mod rpc_wrapper;
mod sampler;
mod consensus;
mod ui;

use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -149,7 +149,7 @@ async fn main() -> Result<()> {
archive_path,
shred_archive_duration,
tui_monitor,
consensus_mode
consensus_mode,
} => {
let config_file =
get_config_file().map_err(|_| anyhow!("tinydancer config not set"))?;
Expand Down Expand Up @@ -234,8 +234,6 @@ async fn main() -> Result<()> {
}
}
ConfigSubcommands::Set { log_path, cluster } => {
// println!("{:?}", fs::create_dir_all("~/.config/tinydancer"));

let home_path = std::env::var("HOME").unwrap();
let tinydancer_dir = home_path + "/.config/tinydancer";

Expand Down
Loading

0 comments on commit 8c71154

Please sign in to comment.