Add a test to the coordinator for running a Tributary

Impls a LocalP2p for testing.

Moves rebroadcasting into Tendermint, since it's what knows if a message is
fully valid + original.

Removes TributarySpec::validators() HashMap, as its non-determinism caused
different instances to have different round robin schedules. It was already
prior moved to a Vec for this issue, so I'm unsure why this remnant existed.

Also renames the GH no-std workflow from the prior commit.
This commit is contained in:
Luke Parker
2023-04-22 10:49:52 -04:00
parent 1e448dec21
commit 8c74576cf0
13 changed files with 259 additions and 69 deletions

View File

@@ -2,7 +2,6 @@ use core::fmt::Debug;
use std::{
sync::{Arc, RwLock},
io,
collections::HashMap,
};
use async_trait::async_trait;
@@ -96,16 +95,16 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
genesis: [u8; 32],
start_time: u64,
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
validators: HashMap<<Ristretto as Ciphersuite>::G, u64>,
validators: Vec<(<Ristretto as Ciphersuite>::G, u64)>,
p2p: P,
) -> Option<Self> {
let validators_vec = validators.keys().cloned().collect::<Vec<_>>();
let validators_vec = validators.iter().map(|validator| validator.0).collect::<Vec<_>>();
let signer = Arc::new(Signer::new(genesis, key));
let validators = Arc::new(Validators::new(genesis, validators)?);
let mut blockchain = Blockchain::new(db, genesis, &validators_vec);
let block_number = blockchain.block_number();
let block_number = BlockNumber(blockchain.block_number().into());
let start_time = if let Some(commit) = blockchain.commit(&blockchain.tip()) {
Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time
@@ -117,8 +116,6 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
let network = TendermintNetwork { genesis, signer, validators, blockchain, p2p };
// The genesis block is 0, so we're working on block #1
let block_number = BlockNumber((block_number + 1).into());
let TendermintHandle { synced_block, messages, machine } =
TendermintMachine::new(network.clone(), block_number, start_time, proposal).await;
tokio::task::spawn(machine.run());
@@ -129,6 +126,9 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
pub fn genesis(&self) -> [u8; 32] {
self.network.blockchain.read().unwrap().genesis()
}
pub fn block_number(&self) -> u32 {
self.network.blockchain.read().unwrap().block_number()
}
pub fn tip(&self) -> [u8; 32] {
self.network.blockchain.read().unwrap().tip()
}
@@ -184,36 +184,31 @@ impl<D: Db, T: Transaction, P: P2p> Tributary<D, T, P> {
}
// Return true if the message should be rebroadcasted.
pub async fn handle_message(&mut self, msg: Vec<u8>) -> bool {
match msg[0] {
TRANSACTION_MESSAGE => {
pub async fn handle_message(&mut self, msg: &[u8]) -> bool {
match msg.first() {
Some(&TRANSACTION_MESSAGE) => {
let Ok(tx) = T::read::<&[u8]>(&mut &msg[1 ..]) else {
log::error!("received invalid transaction message");
return false;
};
// TODO: Sync mempools with fellow peers
// Can we just rebroadcast transactions not included for at least two blocks?
self.network.blockchain.write().unwrap().add_transaction(false, tx)
let res = self.network.blockchain.write().unwrap().add_transaction(false, tx);
log::debug!("received transaction message. valid new transaction: {res}");
res
}
TENDERMINT_MESSAGE => {
Some(&TENDERMINT_MESSAGE) => {
let Ok(msg) = SignedMessageFor::<TendermintNetwork<D, T, P>>::decode::<&[u8]>(
&mut &msg[1 ..]
) else {
log::error!("received invalid tendermint message");
return false;
};
// If this message isn't to form consensus on the next block, ignore it
if msg.block().0 != (self.network.blockchain.read().unwrap().block_number() + 1).into() {
return false;
}
if !msg.verify_signature(&self.network.validators) {
return false;
}
self.messages.send(msg).await.unwrap();
true
false
}
_ => false,