Break coordinator main into multiple functions

Also moves from std::sync::RwLock to tokio::sync::RwLock to prevent wasting
cycles on spinning.
This commit is contained in:
Luke Parker
2023-04-23 23:15:15 -04:00
parent be8c25aef0
commit c476f9b640
10 changed files with 263 additions and 245 deletions

View File

@@ -34,8 +34,5 @@ tendermint = { package = "tendermint-machine", path = "./tendermint" }
tokio = { version = "1", features = ["macros", "sync", "time", "rt"] }
[dev-dependencies]
zeroize = "^1.5"
[features]
tests = []

View File

@@ -1,8 +1,5 @@
use core::fmt::Debug;
use std::{
sync::{Arc, RwLock},
io,
};
use std::{sync::Arc, io};
use async_trait::async_trait;
@@ -20,7 +17,7 @@ use ::tendermint::{
use serai_db::Db;
use tokio::sync::RwLock as AsyncRwLock;
use tokio::sync::RwLock;
mod merkle;
pub(crate) use merkle::*;
@@ -90,7 +87,7 @@ pub struct Tributary<D: Db, T: Transaction, P: P2p> {
network: TendermintNetwork<D, T, P>,
synced_block: SyncedBlockSender<TendermintNetwork<D, T, P>>,
messages: Arc<AsyncRwLock<MessageSender<TendermintNetwork<D, T, P>>>>,
messages: Arc<RwLock<MessageSender<TendermintNetwork<D, T, P>>>>,
}
impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
@@ -124,7 +121,7 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
TendermintMachine::new(network.clone(), block_number, start_time, proposal).await;
tokio::task::spawn(machine.run());
Some(Self { genesis, network, synced_block, messages: Arc::new(AsyncRwLock::new(messages)) })
Some(Self { genesis, network, synced_block, messages: Arc::new(RwLock::new(messages)) })
}
pub fn block_time() -> u32 {
@@ -134,34 +131,37 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
pub fn genesis(&self) -> [u8; 32] {
self.genesis
}
pub fn block_number(&self) -> u32 {
self.network.blockchain.read().unwrap().block_number()
// TODO: block, time_of_block, and commit shouldn't require acquiring the read lock
// These values can be safely read directly from the database since they're static
pub async fn block_number(&self) -> u32 {
self.network.blockchain.read().await.block_number()
}
pub fn tip(&self) -> [u8; 32] {
self.network.blockchain.read().unwrap().tip()
pub async fn tip(&self) -> [u8; 32] {
self.network.blockchain.read().await.tip()
}
pub fn block(&self, hash: &[u8; 32]) -> Option<Block<T>> {
self.network.blockchain.read().unwrap().block(hash)
pub async fn block(&self, hash: &[u8; 32]) -> Option<Block<T>> {
self.network.blockchain.read().await.block(hash)
}
pub fn time_of_block(&self, hash: &[u8; 32]) -> Option<u64> {
pub async fn time_of_block(&self, hash: &[u8; 32]) -> Option<u64> {
self
.network
.blockchain
.read()
.unwrap()
.await
.commit(hash)
.map(|commit| Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time)
}
pub fn commit(&self, hash: &[u8; 32]) -> Option<Vec<u8>> {
self.network.blockchain.read().unwrap().commit(hash)
pub async fn commit(&self, hash: &[u8; 32]) -> Option<Vec<u8>> {
self.network.blockchain.read().await.commit(hash)
}
pub fn provide_transaction(&self, tx: T) -> Result<(), ProvidedError> {
self.network.blockchain.write().unwrap().provide_transaction(tx)
pub async fn provide_transaction(&self, tx: T) -> Result<(), ProvidedError> {
self.network.blockchain.write().await.provide_transaction(tx)
}
pub fn next_nonce(&self, signer: <Ristretto as Ciphersuite>::G) -> Option<u32> {
self.network.blockchain.read().unwrap().next_nonce(signer)
pub async fn next_nonce(&self, signer: <Ristretto as Ciphersuite>::G) -> Option<u32> {
self.network.blockchain.read().await.next_nonce(signer)
}
// Returns if the transaction was valid.
@@ -170,7 +170,7 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
pub async fn add_transaction(&self, tx: T) -> bool {
let mut to_broadcast = vec![TRANSACTION_MESSAGE];
tx.write(&mut to_broadcast).unwrap();
let res = self.network.blockchain.write().unwrap().add_transaction(true, tx);
let res = self.network.blockchain.write().await.add_transaction(true, tx);
if res {
self.network.p2p.broadcast(self.genesis, to_broadcast).await;
}
@@ -181,7 +181,7 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
// TODO: Since we have a static validator set, we should only need the tail commit?
pub async fn sync_block(&mut self, block: Block<T>, commit: Vec<u8>) -> bool {
let (tip, block_number) = {
let blockchain = self.network.blockchain.read().unwrap();
let blockchain = self.network.blockchain.read().await;
(blockchain.tip(), blockchain.block_number())
};
@@ -215,7 +215,7 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
// TODO: Sync mempools with fellow peers
// Can we just rebroadcast transactions not included for at least two blocks?
let res = self.network.blockchain.write().unwrap().add_transaction(false, tx);
let res = self.network.blockchain.write().await.add_transaction(false, tx);
log::debug!("received transaction message. valid new transaction: {res}");
res
}

View File

@@ -1,8 +1,5 @@
use core::ops::Deref;
use std::{
sync::{Arc, RwLock},
collections::HashMap,
};
use std::{sync::Arc, collections::HashMap};
use async_trait::async_trait;
@@ -34,7 +31,10 @@ use tendermint::{
},
};
use tokio::time::{Duration, sleep};
use tokio::{
sync::RwLock,
time::{Duration, sleep},
};
use crate::{
TENDERMINT_MESSAGE, ReadWrite, Transaction, BlockHeader, Block, BlockError, Blockchain, P2p,
@@ -273,7 +273,7 @@ impl<D: Db, T: Transaction, P: P2p> Network for TendermintNetwork<D, T, P> {
async fn validate(&mut self, block: &Self::Block) -> Result<(), TendermintBlockError> {
let block =
Block::read::<&[u8]>(&mut block.0.as_ref()).map_err(|_| TendermintBlockError::Fatal)?;
self.blockchain.read().unwrap().verify_block(&block).map_err(|e| match e {
self.blockchain.read().await.verify_block(&block).map_err(|e| match e {
BlockError::NonLocalProvided(_) => TendermintBlockError::Temporal,
_ => TendermintBlockError::Fatal,
})
@@ -301,7 +301,7 @@ impl<D: Db, T: Transaction, P: P2p> Network for TendermintNetwork<D, T, P> {
};
loop {
let block_res = self.blockchain.write().unwrap().add_block(&block, commit.encode());
let block_res = self.blockchain.write().await.add_block(&block, commit.encode());
match block_res {
Ok(()) => break,
Err(BlockError::NonLocalProvided(hash)) => {
@@ -316,6 +316,6 @@ impl<D: Db, T: Transaction, P: P2p> Network for TendermintNetwork<D, T, P> {
}
}
Some(TendermintBlock(self.blockchain.write().unwrap().build_block().serialize()))
Some(TendermintBlock(self.blockchain.write().await.build_block().serialize()))
}
}